Flowing transaction into a workflow using WF4

One of the things that wasn’t possible in Windows Workflow Foundation 3 was flowing transaction over a WCF service request into a workflow. We could have transactions on the client, we could have transactions on the server but they would not be able to cooperate.

Fortunately that is one the problems that Windows Workflow Foundation 4 solves for us. [:)]

 

In WF4 we can use the ReceiveAndSendreply template to configure a workflow as a service and accept WCF calls. That works just fine but doesn’t allow for transactions. If we want to use transactions we need to add the TransactedReceiveScope to the workflow. Move the ReceiveRequest activity into the Request part and the SendResponse activity into the Body part. Don’t forget the last part because leaving the SendResponse below the TransactedReceiveScope means things will not work and the error message will be less that helpful [:(]

 

image

This is enough to make all work done during the message receive part of a transaction. To show what is happening with transactions I am using the following code to record and return the transactional status:

using System.Text;


using System.Transactions;


 


public class TransactionReport


{


    public static string GetReport()


    {


        var sb = new StringBuilder();


 


        if (Transaction.Current == null)


        {


            sb.Append("No transaction");


        }


        else


        {


            sb.AppendFormat("TransactionInformation\n");


            sb.AppendFormat("\tLocalIdentifier {0}\n", Transaction.Current.TransactionInformation.LocalIdentifier);


            sb.AppendFormat("\tDistributedIdentifier {0}\n", Transaction.Current.TransactionInformation.DistributedIdentifier);


            sb.AppendFormat("\tStatus {0}\n", Transaction.Current.TransactionInformation.Status);


            sb.AppendFormat("\tIsolationLevel {0}\n", Transaction.Current.IsolationLevel);


        }


 


        return sb.ToString();


    }


}

 

Adding a console application with a service reference with the following code:

using System;


using Client.ServiceReference1;


 


namespace Client


{


    class Program


    {


        static void Main(string[] args)


        {


            var proxy = new ServiceClient();


            var result = proxy.PostData();


 


            Console.WriteLine(result);


 


 


            Console.ReadLine();


        }


    }


}

Produces the following output:

image

No big surprises there. The only thing I am missing is the ability to control the IsolationLevel which seems to be fixed at Serializable.

 

 

Flowing transactions from the client

The first step we need to take for client transactions to flow to the service is do the service call inside of a transaction using this client code:

using System;


using System.Transactions;


using Client.ServiceReference1;


 


namespace Client


{


    class Program


    {


        static void Main(string[] args)


        {


 


            using (var tx = new TransactionScope())


            {


                Console.WriteLine(TransactionReport.GetReport());


 


                var proxy = new ServiceClient();


                var result = proxy.PostData();


 


                Console.WriteLine(result);


 


                Console.WriteLine(TransactionReport.GetReport());


            }


 


            Console.ReadLine();


        }


    }


}

If we run the code now we get the following output:

image

The transaction is there on the client but DistributedIdentifier is still empty so the transaction doesn’t flow to the service yet.

 

Before transactions will flow we need to do two things. First of all we need a WCF binding that can flow transactions. So far we have been using the BasicHttpBinding, the default for an HTTP endpoint in the .NET 4 default configuration, which doesn’t support transactions. So we need to switch to something like WSHttpBinding that does. Next we need to enable transaction flow because it is disabled by default. All of this can be done by adding a little extra configuration to the web.config file.

<bindings>


  <wsHttpBinding>


    <binding transactionFlow="true"/>


  </wsHttpBinding>


</bindings>


<services>


  <service name="Service1">


    <endpoint address=""


              binding="wsHttpBinding"


              contract="IService" />


  </service>


</services>



With this in place all we need to do is update the client service reference and transactions will flow from the client to the service.



image



 



Keep in mind that flowing transactions across a network boundary is a very powerful but also a very dangerous concept. You might be letting someone else, from a different organization, place locks on your database. So make sure you understand the implications of flowing transactions before you open up a whole can of worms!



 



Nice [:)]



 









Enjoy!



[f1]
[f2]

4 thoughts on “Flowing transaction into a workflow using WF4

  1. Suppose the workflow service is calling WCF ado.net data service, will this transaction flow from client to workflow service to ado.net data service

  2. I use this to define a transactional scope in within I can call transactional services, but if I throw an exception in the workflow, the transaction isn’t rollback.
    I need help, please.

  3. @raullm,

    If the client doesn’t catch and handle the error in its transaction this should be rolled back and that should trigger the service transaction to rollback.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>