- Partial Types
- Generics
- Nullable Value Types
- The Lightweight Transaction Manager
- Role Providers
- Summary
- References
The Lightweight Transaction Manager
In computing, a transaction is a discrete activity—an activity that is completed in its entirety or not at all. A resource manager ensures that if a transaction is initiated on some resource, the resource is restored to its original state if the transaction is not fully completed. A distributed transaction is one that spans multiple resources and therefore involves more than a single resource manager. A manager for distributed transactions has been incorporated into Windows operating systems for many years. It is the Microsoft Distributed Transaction Coordinator.
.NET Framework versions 1.0 and 1.1 provided two ways of programming transactions. One way was provided by ADO.NET. That technology’s abstract System.Data.Common.DbConnection class defined a BeginTransaction() method by which you could explicitly initiate a transaction controlled by the particular resource manager made accessible by the concrete implementation of DbConnection. The other way of programming a transaction was provided by Enterprise Services. It provided the System.EnterpriseServices.Transaction attribute that could be added to any subclass of System.EnterpriseServices.ServicedComponent to implicitly enlist any code executing in any of the class’s methods into a transaction managed by the Microsoft Distributed Transaction Coordinator.
ADO.NET provided a way of programming transactions explicitly, whereas Enterprise Services allowed you to do it declaratively. However, in choosing between the explicit style of programming transactions offered by ADO.NET and the declarative style offered by Enterprise Services, you were also forced to choose how a transaction would be handled. With ADO.NET, transactions were handled by a single resource manager, whereas with Enterprise Services, a transaction incurred the overhead of involving the Microsoft Distributed Transaction Coordinator, regardless of whether the transaction was actually distributed.
.NET 2.0 introduced the Lightweight Transaction Manager, System.Transactions.TransactionManager. As its name implies, the Lightweight Transaction Manager has minimal overhead: “...[p]erformance benchmarking done by Microsoft with SQL Server 2005, comparing the use of a [Lightweight Transaction Manager transaction] to using a native transaction directly found no statistical differences between using the two methods” (Lowy 2005, 12). If only a single resource manager is enlisted in the transaction, the Lightweight Transaction Manager allows that resource manager to manage the transaction and the Lightweight Transaction Manager merely monitors it. However, if the Lightweight Transaction Manager detects that a second resource manager has become involved in the transaction, the Lightweight Transaction Manager has the original resource manager relinquish control of the transaction and transfers that control to the Distributed Transaction Coordinator. Transferring control of a transaction in progress to the Distributed Transaction Coordinator is called promotion of the transaction.
The System.Transactions namespace allows you to program transactions using the Lightweight Transaction Manager either explicitly or implicitly. The explicit style uses the System.Transactions.CommitableTransaction class:
CommitableTransaction transaction = new CommittableTransaction(); using(SqlConnection myConnection = new SqlConnection(myConnectionString)) { myConnection.Open(); myConnection.EnlistTransaction(tx); //Do transactional work //Commit the transaction: transaction.Close(); }
The alternative, implicit style of programming, which is preferable because it is more flexible, uses the System.Transactions.TransactionScope class:
using(TransactionScope scope = new TransactionScope) { //Do transactional work: //... //Since no errors have occurred, commit the transaction: scope.Complete(); }
This style of programming a transaction is implicit because code that executes within the using block of the System.Transactions.TransactionScope instance is implicitly enrolled in a transaction. The Complete() method of a System.Transactions.TransactionScope instance can be called exactly once, and if it is called, the transaction will commit.
The System.Transactions namespace also provides a means for programming your own resource managers. However, knowing the purpose of the Lightweight Transaction Manager and the implicit style of transaction programming provided with the System.Transactions.TransactionScope class will suffice for the purpose of learning about the Windows Communication Foundation.