Distributed Transactions in WCF services – Part 3

Enabling distributed transaction propagation in WCF services is a tricky task and several factors and parameters need to be considered. Previous posts showed you that by default distributed transactions aren’t supported even if you enclose your operations you want to consume in a single “TransactionScope”. This post is the last of these series and will show you how to enable transaction support in WCF services. I assume you have already read Part 1 and Part 2 of the series, since I am gonna continue from where we stopped the last time. Let’s start.

First we need to allow the transaction to flow from the client to the service. This is done by modifying the binding configuration in the Web.config file. We have been using the wsHttpBinding in our service project, a binding that supports transactions. What we haven’t done already, is to tell that binding to enable “TransactionFlow”. Do that, by adding a “transactionFlow” attribute to the binding and setting it’s value to true.

<system.serviceModel>
    <serviceHostingEnvironment >
      <serviceActivations>
        <add factory="System.ServiceModel.Activation.ServiceHostFactory"
        relativeAddress="./NorthwindService.svc"
        service="NorthwindService.NorthwindService"/>
      </serviceActivations>
    </serviceHostingEnvironment>
    <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>
    <services>
      <service name="NorthwindService.NorthwindService">
        <endpoint address="" binding="wsHttpBinding" contract="NorthwindService.INorthwindService"
                  bindingConfiguration="transactionalWsHttpBinding">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information,
          set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <!-- To receive exception details in faults for debugging purposes,
          set the value below to true.  Set to false before deployment
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

At this time, we have configure our service binding to allow transactions flow from client to service. Next, we need to enable our service operation to opt in to participate in a distributed transaction. Open the “INorthwindService.cs” file where our service contract relies and add a “[TransactionFlow(TransactionFlowOption.Allowed)]” expression above the UpdateProduct operation.

[ServiceContract]
    public interface INorthwindService
    {
        [OperationContract]
        [FaultContract(typeof(ProductFault))]
        Product GetProduct(int id);
        [OperationContract]
        [FaultContract(typeof(ProductFault))]
        [TransactionFlow(TransactionFlowOption.Allowed)]
        bool UpdateProduct(ref Product product, ref string message);
    }

This will allow a transaction to be propagated to the UpdateProduct operation. Open the service implementation class “NorthwindService” under the NorthwindService.cs file and add a “TransactionScopeRequired” behavior attribute to the UpdateProduct implementation. This will ensure that this operation will always be executed under a transaction, either propagated by the client or not.

 [OperationBehavior(TransactionScopeRequired = true)]
        public bool UpdateProduct(ref Product product, ref string message)
// implementation code omitted -  you can find it from the previous posts

Rebuild the Service Project so that service hosted in IIS will be updated with the latest changes we have made. In the ASP.NET NorthwindClient project we created in the previous post, right click the “Reference.svcmap” under the App_WebReferences folder and select “Update service reference..”. This will regenerate the service proxy adding a “TransactionFlow” attribute equals to true in the Web.config file of the client’s project.

<system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_INorthwindService" transactionFlow="true" />
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://developer-pc/NorthwindService/NorthwindService.svc"
        binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_INorthwindService"
        contract="NorthwindServiceProxy.INorthwindService" name="WSHttpBinding_INorthwindService">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>

There are few important things left to do before we test again if distributed transactions are supported in our WCF service. The component that is actually responsible for coordinating the distributed transaction propagated by the client, is the “Microsoft Distributed Transaction Coordinator” (MDTC). If this component isn’t configured properly, the transaction will still fail. In other words, when the client propagates the transaction calling (in our specific client project) two updates simultaneously, that component is activated in order to manage the transaction. Make sure you make MDTC configurations as follow:

1. In Windows, click start and find the “run” command window. Type “dcomcnfg” and click enter. This will open the “Componet Services” window. Expand “Component Services”, then “My computers”. Right click “My computer” and select properties. Click the MDTC tab and make sure the “Use local coordinator” checkbox is checked.

MDTC1

2. Close “My computer properties” window, expand “My computer”, then expand “Distributed Transaction Coordinator” and right click the “Local DTC” item. Select properties and make sure you set the “Security” properties as follow:

MDTC2

3. The last thing left is to configure Windows Firewall allow MDTC communicate though it. Open “Allow a program or feature through Windows Firewall” from Control Panel and make sure “Distributed Transaction Coordinator” is on the list and checked as follow. If you can’t find “Distributed Transaction Coordinator” on the list, add the program from “windows\system32\msdtc.exe” location.

MDTC3

Finally we are ready to test our new configurations and propagate a transaction from the client’s project to the WCF service. I will not show if the WCF service work under valid Product Unit prices as we did in previous posts (you can test it if you want), but instead I will go straight forward and test the service by setting on purpose a negative value for the second Unit Price. If you remember, doing so till now, resulted the first product’s Unit Price to be updated despite the fact that the second UpdateProduct operation failed. If Distributed Transaction is supported now, the first product’s Unit Price update will roll back and nothing will actually change in a database level. Let’s test it. Set the client’s project as the default and Run without debugging. I entered “20” and “21” for product’s Ids. In my database, UnitPrice of product with Id:20 is 84 and UnitPrice of the second product is 13. I will enter to change first product’s unit price to 85 and second’s to -10. You can see that second’s UpdateProduct operation will fail and what we expect this time, is since these operations are called through a “TransactionScope” (look Part 2 of series) the first UpdateProduct result will have to roll back.

MDTC4

Click “Update Price” button. You will see that first product’s unit price was updated (don’t be so sure) and second’s UpdateProduct operation failed.

MDTC5

Click again the “Get Product Details” button with the same Ids.

MDTC6

We finally did it. First product’s update rolled back keeping it’s UnitPrice to 84. I hope these series helped you understand how to enable Distributed Transaction support in WCF services.



Categories: ASP.NET, WCF

Tags: , ,

7 replies

  1. Excellent demo, I would like to know how to handle transactions without using IIS, I have a WCF service on a host windows form, I handle it as a service but my question arises on how to handle the transactions, could give me a guidance for this?, Thanks.

  2. Thanks…Very nice…

  3. thanks… vey nice article…

  4. True it is a very nice demo..

  5. Thank u for the blog

  6. Great article. Well structured and goes through the scenarios step-by-step. Confirmed what I was looking for too. Thank you for taking the time to write it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: