Enabling distributed transaction support

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.

Enabling transaction flow in service binding

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:

  • Use wsHttpBinding on the host application as binding
  • Set the value of the transactionFlow attribute to true on the host application binding configuration

Enabling transaction flow on the service hosting application

In this section, we will enable transaction flow in bindings for both ProductService and RemoteProductService.

  1. In the Solution Explorer, open the web.config file under the C:SOAWithWCFandLINQProjectsDistNorthwindLINQNorthwindService folder.
  2. Change the following line:
    <endpoint address="" binding="wsHttpBinding" 
       contract="LINQNorthwindService.IProductService">

    To this line:

    <endpoint address="" binding="wsHttpBinding" 
       contract="LINQNorthwindService.IProductService" 
           bindingConfiguration="transactionalWsHttpBinding">
  3. Add the following node to the 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>
  4. In this configuration section, we have set the transactionFlow attribute to true for the binding, so a transaction is allowed to flow from the client to the service.
  5. Make the same changes to the web.config file under the 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.

Modifying the service operation contract to allow a transaction flow

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:

  1. Open the IProductServiceContract.cs file under the LINQNorthwindService project.
  2. Add the following line before the 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

NotAllowed

A transaction should not be flowed; this is the default value

Allowed

Transaction may be flowed

Mandatory

Transaction must be flowed

Modifying the service operation implementation to require a transaction scope

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.

  1. Open the ProductService.cs file under the LINQNorthwindService project.
  2. Add the following line before the 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.

Note

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:

  1. Rebuild the solution. As we have set up the post-build event for the 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.
  2. In the Solution Explorer, right-click on RemoteProductServiceProxy under the Service References directory of the DistNorthwindWPF project.
  3. Select Update Service Reference from the context menu.
  4. Right-click on ProductServiceProxy under the Service References directory of the DistNorthwindWPF project.
  5. Select Update Service Reference from the context menu.

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.

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

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