|
namespace RSI.Transactions
{
using System;
using System.Threading;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Messaging;
using System.Data.SqlClient;
using System.Data;
/// <summary>
/// Summary description for Class1.
/// </summary>
public class ContextUtil
{
static public void SetAbort()
{
TransactionAttribute Property = Transaction.ContextProperty;
if(Property == null)
return;
Property.SetAbort();
}
static public void SetComplete()
{
TransactionAttribute Property = Transaction.ContextProperty;
if(Property == null)
return;
Property.SetComplete();
}
static public IDbTransaction DbTransaction
{
get
{
TransactionAttribute Property = Transaction.ContextProperty;
if(Property == null)
return null;
return Property.DbTransaction;
}
}
}
public class DbConnectionUtil
{
static public IDbConnection Connection
{
get { return DbConnectionAttribute.Connection; }
}
}
[AttributeUsage(AttributeTargets.Method)]
public class NoDbConnectionAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Class)]
public class DbConnectionAttribute : ContextAttribute, IContributeObjectSink
{
private SqlConnection m_SqlConnection;
public DbConnectionAttribute()
: base(PropertyName)
{
m_SqlConnection = null;
}
private static String PropertyName
{
get { return "WorkSight.DataAccess.Connection"; }
}
internal static DbConnectionAttribute CurrentConnection
{
get { return Thread.CurrentContext.GetProperty(PropertyName) as DbConnectionAttribute; }
}
internal void OpenConnection()
{
if(m_SqlConnection == null)
{
#if DEBUGGING_TRXS
Console.WriteLine("[" + Thread.CurrentContext.ContextID + "]" + " Opening Database Connection...");
#endif
//
// TODO: Put your Datasource Connection Here!
//
m_SqlConnection = new SqlConnection(System.Configuration.ConfigurationSettings.AppSettings["dsn"]);
m_SqlConnection.Open();
}
}
internal void CloseConnection()
{
if(m_SqlConnection != null)
{
#if DEBUGGING_TRXS
Console.WriteLine("[" + Thread.CurrentContext.ContextID + "]" + " Closing Database Connection...");
#endif
m_SqlConnection.Close();
m_SqlConnection.Dispose();
m_SqlConnection = null;
}
}
static internal IDbConnection Connection
{
get
{
DbConnectionAttribute currentConnection = CurrentConnection;
if(currentConnection != null)
return currentConnection.m_SqlConnection;
return null;
}
}
public override bool IsContextOK(Context ctx, IConstructionCallMessage ctor)
{
return true;
}
public override void GetPropertiesForNewContext(IConstructionCallMessage ctor)
{
ctor.ContextProperties.Add(this);
}
public IMessageSink GetObjectSink(MarshalByRefObject o, IMessageSink m_Next)
{
TransactionAttribute transactionProperty = Transaction.ContextProperty;
if(transactionProperty != null)
{
return new DbConnectionMessageSink(this, new TransactionMessageSink(transactionProperty, m_Next));
}
return new DbConnectionMessageSink(this, m_Next);
}
}
public class DbConnectionMessageSink : IMessageSink
{
private IMessageSink m_Next;
private DbConnectionAttribute m_DbConnectionAttribute;
internal DbConnectionMessageSink(DbConnectionAttribute connectionAttribute, IMessageSink ims)
{
m_Next = ims;
m_DbConnectionAttribute = connectionAttribute;
}
public IMessageSink NextSink
{
get { return m_Next; }
}
public IMessage SyncProcessMessage(IMessage imCall)
{
if (!(imCall is IMethodMessage))
return m_Next.SyncProcessMessage(imCall);
IMethodMessage imm = imCall as IMethodMessage;
bool bNoConnection = (Attribute.GetCustomAttribute(imm.MethodBase, typeof(NoDbConnectionAttribute)) != null);
if(bNoConnection)
return m_Next.SyncProcessMessage(imCall);
m_DbConnectionAttribute.OpenConnection();
IMessage imReturn = m_Next.SyncProcessMessage(imCall);
m_DbConnectionAttribute.CloseConnection();
return imReturn;
}
public IMessageCtrl AsyncProcessMessage(IMessage im, IMessageSink ims)
{
// TODO: Find some way to also allow AsyncMessages to work (and ideally, be tracked)
return m_Next.AsyncProcessMessage(im, ims);
}
}
public enum TransactionOption
{
Disabled = 0,
NotSupported,
Required,
RequiresNew,
Supported
}
public class Transaction
{
internal static String PropertyName
{
get { return "WorkSight.DataAccess.Transaction"; }
}
internal static TransactionAttribute ContextProperty
{
get { return Thread.CurrentContext.GetProperty(Transaction.PropertyName) as TransactionAttribute; }
}
}
[AttributeUsage(AttributeTargets.Method)]
public class AutoCompleteAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Class)]
public class TransactionAttribute : ContextAttribute
{
private TransactionOption m_TransactionOption;
private bool m_bDone = false;
private bool m_bContextConsistent = false;
private SqlTransaction m_SqlTransaction = null;
public TransactionAttribute(TransactionOption m_TransactionOption)
: base(Transaction.PropertyName)
{
this.m_TransactionOption = m_TransactionOption;
}
//Define Name property.
//This is a read-only attribute.
public TransactionOption TransactionContext
{
get {return this.m_TransactionOption;}
}
public override bool IsContextOK(Context ctx, IConstructionCallMessage ctor)
{
if(m_TransactionOption == TransactionOption.RequiresNew)
return false;
TransactionAttribute transactionProperty = ctx.GetProperty(Transaction.PropertyName) as TransactionAttribute;
if(m_TransactionOption == TransactionOption.Required)
{
if(transactionProperty == null)
return false;
}
return true;
/*
if(m_TransactionOption == TransactionOption.NotSupported)
return true;
if(m_TransactionOption == TransactionOption.Disabled)
return true;
if(m_TransactionOption == TransactionOption.Supported)
return true;
return true;
*/
}
public override void GetPropertiesForNewContext(IConstructionCallMessage ctor)
{
ctor.ContextProperties.Add(this);
}
public bool Done
{
get { return m_bDone; }
}
public bool ContextConsistent
{
get { return m_bContextConsistent; }
}
public void SetAbort()
{
m_bContextConsistent = false;
m_bDone = true;
}
public void EnableCommit()
{
if(m_bDone)
return;
m_bContextConsistent = true;
}
public void DisableCommit()
{
if(m_bDone)
return;
m_bContextConsistent = false;
}
public void SetComplete()
{
if(m_bDone)
return;
m_bContextConsistent = true;
m_bDone = true;
}
public SqlTransaction DbTransaction
{
get { return m_SqlTransaction; }
set { m_SqlTransaction = value; }
}
}
public class TransactionMessageSink : IMessageSink
{
private IMessageSink m_Next;
private TransactionAttribute m_TransactionAttribute;
internal TransactionMessageSink(TransactionAttribute transactionProperty, IMessageSink ims)
{
m_Next = ims;
m_TransactionAttribute = transactionProperty;
}
public IMessageSink NextSink
{
get { return m_Next; }
}
public IMessage SyncProcessMessage(IMessage imCall)
{
// Perform whatever preprocessing is needed on the message
if (!(imCall is IMethodMessage))
return m_Next.SyncProcessMessage(imCall);
IMethodMessage imm = imCall as IMethodMessage;
bool bAutoComplete = (Attribute.GetCustomAttribute(imm.MethodBase, typeof(AutoCompleteAttribute)) != null);
m_TransactionAttribute.DisableCommit();
SqlConnection Connection = (SqlConnection)DbConnectionAttribute.Connection;
if(Connection == null)
return m_Next.SyncProcessMessage(imCall);
#if DEBUGGING_TRXS
Console.WriteLine("[" + Thread.CurrentContext.ContextID + "]" + " Beginning Transaction...");
#endif
SqlTransaction dbTransaction = m_TransactionAttribute.DbTransaction = Connection.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
// Dispatch the call on the object
IMessage imReturn = m_Next.SyncProcessMessage(imCall);
if(dbTransaction != null)
{
IMethodReturnMessage methodReturn = imReturn as IMethodReturnMessage;
Exception exc = methodReturn.Exception;
if (exc != null)
{
m_TransactionAttribute.SetAbort();
}
else
{
if(bAutoComplete)
m_TransactionAttribute.SetComplete();
}
if(!m_TransactionAttribute.Done)
m_TransactionAttribute.SetAbort();
if(m_TransactionAttribute.ContextConsistent)
{
#if DEBUGGING_TRXS
Console.WriteLine("[" + Thread.CurrentContext.ContextID + "]" + " Commiting Transaction...");
#endif
dbTransaction.Commit();
}
else
{
#if DEBUGGING_TRXS
Console.WriteLine("[" + Thread.CurrentContext.ContextID + "]" + " Aborting Transaction...");
#endif
dbTransaction.Rollback();
}
dbTransaction.Dispose();
dbTransaction = null;
}
return imReturn;
}
public IMessageCtrl AsyncProcessMessage(IMessage im, IMessageSink ims)
{
// TODO: Find some way to also allow AsyncMessages to work (and ideally, be tracked)
return m_Next.AsyncProcessMessage(im, ims);
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.