Transaction in Windows Communication Foundation (WCF)
Transaction in Windows Communication Foundation (WCF)
By : Kasim Wirama, MCDBA, MVP SQL Server
Transaction is one atomic unit of a set of works of series of operations, that all each item should be committed or no changes permanently applied to persistent store. Transaction has been primarily applied to database application. But transaction can also be applied to series of resources besides database.
Imagine that a transaction spans multiple services on multiple computers. It is what we know as distributed transaction. Possible failure in distributed transaction is more possible compared to centralized transaction, primarily due to exception by the network. To address this issue, OASIS organization proposes Web Service Atomic Transaction standard (WS-Atomic Transaction) that addresses how to handle transaction in web service environment with two phase commit.
Implementation of two phase commit could be found on MSDTC (Microsoft Distributed Transaction Coordinator). Basically MSDTC is OLE transaction, as we know that OLE is Microsoft technology, so you can use OLE if your web service environment implements Microsoft technology. Another alternative is System.Transaction in .NET 2.0. System.Transaction is more technology independent compared to MSDTC.
I have tried transaction implementation in WCF, for this exploration I use WCF with MSDTC and System.Transaction.
More specific to WCF, you need to know. Transaction in WCF doesn’t work with basic HTTP, it works if you use TCP protocol or advanced HTTP protocol, and you need to turn on transaction for these protocol and adjust this configuration to WCF client as well along with updated proxy at WCF client.
Let’s look each configuration and setting on WCF service and WCF client
WCF serviceService contract interface
First you need to add System.Transaction.DLL, and also declare the namespace in service contract implementation class.
Add attribute TransactionFlow for required Operation contract, if you require client initiate transaction, set the option Mandatory for the attribute as sample code show below :
[TransactionFlow(TransactionFlowOption.Mandatory)]
string StringMethod();
Service implementation
In service implementation, add TransactionIsolationLevel attribute property of ServiceBehaviour and for each implementation of operation contracts that are marked with TransactionFlow attribute, add attribute OperationBehaviour with property TransactionScopeRequired to True and TransactionAutoComplete. If you need to span transaction over several method or if instanceContextMode is set to persession, set this to false. If you use concurrencymode to multiple, you need to set the transactionautocomplete to true, because all transaction on all thread should be committed/rollback before session ends.
Here is sample code
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,TransactionIsolationLevel = System.Transactions.IsolationLevel.RepeatableRead)]
public class OperationImpl : IOperation
{
[OperationBehavior(TransactionScopeRequired = true,TransactionAutoComplete = false)]
public string StringMethod()
{ ....
}
}
Add binding to TCP protocol
You can create service endpoint with option TCP or advanced web service protocol (ws2007HttpBinding). And create binding that is bound to the endpoint. When you create binding, be sure to set TransactionFlow property is set to true, if you choose TCP protocol, you need to choose option in TransactionProtocol property whether bind to OLETransactions, WSAtomicTransactionOctober2004 or WSAtomicTransaction11. for my own exploration, I set to OLETransactions, so I can use with MSDTC. For endpoint address, if you set to TCP binding, prefix it with net.tcp// for example : net.tcp://localhost:9002/Service/Service.svc
Proxy generation
You generate proxy for client that will distribute to and compile with WCF client.
WCF clientAttach proxy to WCF client
Attach the proxy and compile WCF client, so WCF definition will be updated into WCF client assembly.
After that, include System.Transaction dll in reference and in namespace.
Add binding to TCP protocol
Similar to create TCP binding protocol at WCF service, you need to create same binding too, but you bind it to client side endpoint instead of service endpoint. And you need to specify same TCP address as Web service TCP address has.
Use transactional WCF
After you create TCP proxy instance in Main program, you specify TransactionOptions and TransactionScope instance. Inside scope of TransactionScope, you can reference WCF service transactional method. You can do commit by calling method Complete on TransactionScope instance. Here is the sample code :
OperationImpl.OperationClient proxy = new OperationClient("myclient_tcpBinding");
proxy.Open();
TransactionOptions tranOptions = new TransactionOptions { IsolationLevel=IsolationLevel.RepeatableRead,
Timeout = new TimeSpan(0,1,0)};
using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required, tranOptions))
{
proxy.StringMethod();
int result = proxy.Add(1, 7);
Console.WriteLine(result.ToString());
result = proxy.Add(2, 7);
Console.WriteLine(result.ToString());
proxy.AddTwo(2);
transaction.Complete();
}
proxy.Close();
When I run WCF client, runtime error was raised, the message was “The transaction has aborted”. Actually, I didn’t know for sure what made it error, until I found something interesting when I was looking for workaround in Microsoft forum. It said that at one of WCF method, there should also have TransactionAutoComplete to true, or specify it explicitly inside the method to commit method like this one : OperationContext.Current.SetTransactionComplete();
After I add this one line of code in one of WCF service method, WCF transaction works as expected.
With systematic approach, setting up transaction in WCF is easy and will perform similar to any other transaction in Microsoft technologies that implements transaction.