In the previous sections, we verified that the WCF service currently does not support the distributed transactions irrespective of whether these are two sequential calls to the same service or two sequential calls to two different services, with one database or with two databases.
In the following sections, we will learn how to allow this WCF service to support distributed transactions. We will allow the WCF service to participate in the client transaction. From another point of view, we will learn how to flow or propagate a client transaction across the service boundaries so that the client can include service operation calls on multiple services in the same distributed transaction.
The first thing that we need to pay attention to is the bindings. As we learned in the previous chapters, the three elements of a WCF service end point are the address, the binding, and the contract (WCF ABC). Although the address has nothing to do with the distributed transaction support, the other two elements do.
We know that WCF supports several different bindings. All of them support transactions except the following three:
BasicHttpBinding
BasicHttpContextBinding
NetPeerTcpBinding
In this chapter, we will use WSHttpBinding
as our example.
However, using a transaction-aware binding doesn't mean that a transaction will be propagated to the service. The transaction propagation is disabled by default and we have to enable it manually. Unsurprisingly, the attribute to enable the transaction flow in the bindings is called transactionFlow
.
In the following section, we will do the following to enable the transaction propagation:
In this section, we will
enable transaction flow in bindings for both ProductService
and RemoteProductService
.
C:SOAWithWCFandLINQProjectsDistNorthwindLINQNorthwindService
folder.<endpoint address="" binding="wsHttpBinding" contract="LINQNorthwindService.IProductService">
To this line:
<endpoint address="" binding="wsHttpBinding" contract="LINQNorthwindService.IProductService" bindingConfiguration="transactionalWsHttpBinding">
web.config
file inside the system.serviceModel
node and in parallel with node services:<bindings> <wsHttpBinding> <binding name="transactionalWsHttpBinding" transactionFlow="true" receiveTimeout="00:10:00" sendTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00" /> </wsHttpBinding> </bindings>
transactionFlow
attribute to true
for the binding, so a transaction is allowed to flow from the client to the service.C:SOAWithWCFandLINQProjectsDistNorthwind LINQNorthwindRemoteService
folder.In the preceding configuration file, we have verified and left the bindings for both ProductService
and RemoteProductService
to wsHttpBinding
and set the transactionFlow
attribute of the binding to true
. This will enable distributed transaction support from the WCF service binding side.
Now the service is able to participate in a propagated transaction from the client application, but the client is still not able to propagate a distributed transaction into the service. Before we enable the distributed transaction support from the client side, we need to make some more changes to the service side code, that is, modify the service operation to opt in to participate in a distributed transaction. By default, it is opted out.
Two things need to be done in order to allow an operation to participate in a propagated transaction. The first thing is to enable the transaction flow in operation contracts. Follow these steps to enable this option:
IProductServiceContract.cs
file under the LINQNorthwindService
project.UpdateProduct
method:[TransactionFlow(TransactionFlowOption.Allowed)]
In the preceding code line, we set TransactionFlowOption
in the UpdateProduct
operation to be Allowed
. This means a transaction is allowed to be propagated from the client to this operation.
The three transaction flow options for a WCF service operation are Allowed
, NotAllowed
, and Mandatory
, as shown in the following table:
Option |
Description |
---|---|
|
A transaction should not be flowed; this is the default value |
|
Transaction may be flowed |
|
Transaction must be flowed |
The second thing we need to do is specify the TransactionScopeRequired
behavior for the service operation. This has to be done on the service implementation project.
ProductService.cs
file under the LINQNorthwindService
project.UpdateProduct
method:[OperationBehavior(TransactionScopeRequired = true)]
The TransactionScopeRequired
attribute means that for the UpdateProduct
method, the whole service operation will always be executed inside one transaction. If a transaction is propagated from the client application, this operation will participate in this existing distributed transaction. If no transaction is propagated, a new transaction will be created and this operation will be run within this new transaction.
At end of this chapter, after you have finished setting up everything for transaction support and run the program, you can examine the ambient transaction inside the WCF service (Transaction.Current
) and compare it with the ambient transaction of the client to see if they are the same. You can also examine the TransactionInformation
property of the ambient transaction object to see if it is a local transaction (TransactionInformation.LocalIdentifier
) or a distributed transaction (TransactionInformation.DistributedIdentifier
).
We now need to regenerate the service proxy and the configuration files on the client project because we have changed the service interfaces. Remember that in your real project, you should avoid making any non-backward compatible service interface changes. Once the service goes live, if you have to make changes to the service interface, you should version your service and allow the client applications to migrate to the new versions of the service when they are ready to do so. To simplify our example, we will just update the proxy and configuration files and recompile our client application.
These are the steps to regenerate the configuration and proxy files:
LINQNorthwindService
project to copy all assembly files to two IIS directories, both ProductService
and RemoteProductService
should now contain the latest assemblies with distributed transaction support enabled.DistNorthwindWPF
project.DistNorthwindWPF
project.Open the App.config
file under the DistNorthwindWPF
project. You will find that the transactionFlow
attribute is now populated as true
because the code generator finds that some operations in the service now allow transaction propagation.