The Transaction Class

The Transaction class from the System.Transactions namespace, introduced in .NET 2.0, represents the transaction that all .NET transaction managers work with:

[Serializable]
public class Transaction : IDisposable,ISerializable
{
   public static Transaction Current
   {get;set;}

   public void Rollback(); //Abort the transaction
   public void Dispose();

   //More members
}

Developers rarely need to interact with the Transaction class directly. The main use of the Transaction class is to manually abort a transaction by calling the Rollback() method. Additional features of the Transaction class include enlisting resource managers, setting the isolation level, subscribing to transaction events, cloning the transaction for concurrent threads, and obtaining the transaction status and other information.

The Ambient Transaction

.NET 2.0 defined a concept called the ambient transaction, which is the transaction in which your code executes. To obtain a reference to the ambient transaction, call the static Current property of Transaction:

Transaction ambientTransaction = Transaction.Current;

If there is no ambient transaction, Current will return null. Every piece of code, be it client or service, can always reach out for its ambient transaction. The ambient transaction object is stored in the thread local storage (TLS). As a result, when the thread winds its way across multiple objects and methods on the same call chain, all objects and methods can access their ambient transactions.

In the context of WCF, the ambient transaction is paramount. When present, any resource manager will automatically enlist in the ambient transaction. When a client calls a WCF service, if the client has an ambient transaction and the binding and the contract are configured to allow transaction flow, the ambient transaction will propagate to the service.

Warning

The client cannot propagate an already aborted transaction to the service. Doing so will yield an exception.

Local Versus Distributed Transactions

The Transaction class is used both for local and distributed transactions. Each transaction object has two identifiers used to identify the local and the distributed transaction. You obtain the transaction identifiers by accessing the TransactionInformation property of the Transaction class:

[Serializable]
public class Transaction : IDisposable,ISerializable
{
   public TransactionInformation TransactionInformation
   {get;}
   //More members
}

The TransactionInformation property is of the type TransactionInformation, defined as:

public class TransactionInformation
{
   public Guid DistributedIdentifier
   {get;}
   public string LocalIdentifier
   {get;}
   //More members
}

TransactionInformation offers access to the two identifiers. The main use of these identifiers is for logging, tracing, and analysis. In this chapter, I will use the identifiers as a convenient way to demonstrate transaction flow in code as a result of configuration.

The local transaction identifier

The local transaction identifier (local ID) contains both an identifier for the LTM in the current app domain as well as an ordinal number enumerating the transaction. You access the local ID via the LocalIdentifier property of TransactionInformation. The local ID is always available with the ambient transaction, and as such is never null: as long as there is an ambient transaction, it will have a valid local ID.

The value of the local ID has two parts: a constant GUID that is unique for each app domain and represents the assigned LTM for that app domain, and an incremented integer enumerating the transactions managed so far by that LTM.

For example, if a service traces three consecutive transactions, starting with the first call, it will get something like this:

8947aec9-1fac-42bb-8de7-60df836e00d6:1
8947aec9-1fac-42bb-8de7-60df836e00d6:2
8947aec9-1fac-42bb-8de7-60df836e00d6:3

The GUID is constant per app domain. If the service is hosted in the same app domain as the client, they will have the same GUID. If the client makes a cross-app domain call, the client will have its own unique GUID identifying its own local LTM.

The distributed transaction identifier

The distributed transaction identifier (distributed ID) is generated automatically whenever an LTM- or KTM-managed transaction is promoted to a DTC-managed transaction (for example, when the ambient transaction flows to another service). You access the distributed ID via the DistributedIdentifier property of TransactionInformation. The distributed ID is unique per transaction, and no two transactions will ever have the same distributed ID. Most importantly, the distributed ID will be uniform across the service boundaries and across the entire call chain, from the topmost client through every service and object down the call chain. As such, it is useful in logging and tracing. Note that for a transaction that has not yet been promoted, the value of the distributed ID will be Guid.Empty. The distributed ID is usually Guid.Empty on the client side when the client is the root of the transaction and it has not yet called a service, and on the service side it will be empty if the service does not use the client’s transaction and instead starts its own local transaction.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.27.45