A transaction in WCF is a set of operations that follow some properties, collectively known as ACID. Here, if a single operation fails, the entire system fails automatically. When an order is placed online, a transaction takes place. The following example can be helpful to understand the process of transaction in simpler terms.
Suppose you have ordered an LCD television from an online store and you are going to pay the amount by your credit card. When you enter the requisite information to place the order, two operations occur simultaneously.
One, the specified amount gets debited from your bank account and second, the vendor account is credited with the same amount. Both the operations must execute successfully in order to have a successful transaction.
The four properties followed by a WCF transaction are the following −
Atomic − All the operations must act as a single indivisible operation at the completion of a transaction.
Consistency − Whatever may be the operation set, the system is always in a state of consistency, i.e., the outcome of the transaction is always as per the expectation.
Isolation − The intermediary state of system is not visible to any entities of the outer world till the transaction is completed.
Durability − Committed state is maintained regardless of any kind of failure (hardware, power outage, etc.)
While configuring a WCF transaction, there are some factors that demand consideration. These are binding and operation behavior.
Binding − The bindings that support transaction in WCF are only a few and it is vital to make a choice from only these bindings, which remain disabled by default and should be enabled to get the requisite support for transaction. These bindings are as follows −
Operation behavior − While a binding facilitates the path for transaction propagation, an operation takes care of transaction processing as well as operation configuration. Operation behavior primarily uses two attributes: TransactionFlow and TransactionScopeRequired. Here, it should be noted that TransactionFlow has mainly three values and these are: Allowed, Mandatory, and NotAllowed.
The following code shows whether or not changing the configuration of binding and operation contract facilitates the propagation of client.
<bindings> <wsHttpBinding> <binding name = "MandatoryTransBinding" transactionFlow = "true"> <reliableSession enabled ="true"/> </binding> </wsHttpBinding> </bindings>
WCF uses three types of protocols for transaction −
Of all the three, WS-AT is an interoperable protocol and enables the flow of distributed transaction across firewalls. However, this protocol should not be used when the transaction is strictly based on Microsoft technology.
There are two phases in a WCF transaction as shown in the following figure.
Prepare Phase − In this phase, the transaction manager checks whether all the entities are ready to commit for the transaction or not.
Commit Phase − In this phase, the commitment of entities get started in reality.
The following figure illustrates the functions of both the phases of a WCF transaction.
To enable a WCF transaction successfully, one needs to follow a series of six steps in a sequential manner. The requisite steps are discussed below.
Step 1 − Creation of two WCF Services
The foremost step in this regard is to build two service projects in WCF to participate in a single transaction. Database transactions will be performed on both these services and it will be understood that how they are unified by a WCF transaction. A web application of WCFTransactions has also been created to consume the two created services in a single transaction scope.
Step 2 − Method creation and its attribution with TransactionFlow attribute
Here, an UpdateData method will be created for both the WCF services to insert into the database with OperationContract attribute. To accomplish this task, an interface class is first created with the help of the ServiceContract attribute. For enabling the transaction in the newly created method, it is attributed with TransactionFlow and transactions are permitted using is Allowed value.
[ServiceContract] public interface IService1 { [OperationContract] [TransactionFlow(TransactionFlowOption.Allowed)] void UpdateData(); }
Step 3− Implementation of WCF service with TransactionScopeRequired attribute
It is done by using the code shown below −
[OperationBehavior(TransactionScopeRequired = true)] public void UpdateData() { try { SqlConnection objConnection = new SqlConnection(strConnection); objConnection.Open(); using(SqlTransaction transaction = Program.dbConnection.BeginTransaction()) { Boolean doRollback = false; using(SqlCommand cmd = new SqlCommand( "insert into Customer (Customer name, Customer code) values ('sss', 'sss')"objConnection)) try { cmd.ExecuteNonQuery(); } catch(SqlException) { doRollback = true; break; } } if(doRollback) transaction.Rollback(); else transaction.Commit(); } finally { objConection.Close(); } }
Step 4 − Enabling Transaction Flow by WCF Service Config File
Its coding is done as follows −
<bindings> <wsHttpBinding> <binding name = "TransactionalBind" transactionFlow = "true"/> </wsHttpBinding> </bindings>
It is vital to attach the transaction permissible binding with the endpoint to expose the WCF service.
<endpoint address = "" binding = "wsHttpBinding" bindingConfiguration = "TransactionalBind" contract = "WcfService1.IService1">
Step 5 − Calling both the services in a single transaction
Here, the above two services are called in one transaction and for this purpose, the TransactionScope object is used to group both the services. The Complete method of the above object is called to commit a WCF transaction. To rollback, the Dispose method is to be called.
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew)) { try { // Call your webservice transactions here ts.Complete(); } catch (Exception ex) { ts.Dispose(); } }
The small piece of the complete code in which WCF transactions have been grouped in one scope is depicted below −
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew)) { try { ServiceReference1.Service1Client obj = newServiceReference1.Service1Client(); obj.UpdateData(); ServiceReference2.Service1Client obj1 = new ServiceReference2.Service1Client(); obj1.UpdateData(); ts.Complete(); } catch (Exception ex) { ts.Dispose(); } }
Step 6 − Testing WCF transaction
Testing is done in the 6th and final step and after calling the 1st WCF service, an exception is forced.