Click here to Skip to main content
15,886,110 members
Articles / Web Development / ASP.NET

6 Steps to Enable Transactions in WCF

Rate me:
Please Sign up or sign in to vote.
4.74/5 (49 votes)
23 Jun 2021CPOL3 min read 281.6K   5.7K   125   23
6 steps to enable transactions in WCF

Table of Contents

Introduction and Goal

In this article, we will try to understand how we can implement transactions in WCF service. So we will create two WCF services which do database transactions and then unite them in one transaction. We will first understand the 6 important steps to enable transactions in WCF services. At the end of the article, we will try to force an error and see how the transaction is rolled back after the error.

Step 1: Create Two WCF Services

The first step is to create two WCF service projects which will participate in one transaction. In both of these WCF services, we will do database transactions and we will try to understand how a WCF transaction unifies them. We have also created a web application with name WCFTransactions which will consume both the services in one transaction scope.

Image 1

Step 2: Attribute Interface Methods with TransactionFlow

In both the WCF services, we will create a method called UpdateData which will insert into the database. So the first thing is to create the interface class with ServiceContract attribute and the method UpdateData with OperationContract attribute. In order to enable transaction in UpdateData method, we need to attribute it with TransactionFlow and we have specified that transactions are allowed for this method using TransactionFlowOption.Allowed enum.

C#
[ServiceContract]
public interface IService1
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void UpdateData();
}

Step 3: Attribute the Implementation with TransactionScopeRequired

The 3rd step is to attribute the implementation of the WCF services with TransactionScopeRequired as true. Below is the code snippet which has a simple database inserting function, i.e. UpdateData which is attributed by TransactionScopeRequired attribute.

C#
[OperationBehavior(TransactionScopeRequired = true)]
public void UpdateData()
{
SqlConnection objConnection = new SqlConnection(strConnection);
objConnection.Open();
SqlCommand objCommand = new SqlCommand("insert into Customer
	(CustomerName,CustomerCode) values('sss','sss')",objConnection);
objCommand.ExecuteNonQuery();
objConnection.Close();
}

Step 4: Enable Transaction Flow using WCF Service Config File

We also need to enable transactions for wsHttpBinding by setting the transactionFlow attribute to true.

XML
<bindings>
<wsHttpBinding>
<binding name="TransactionalBind" transactionFlow="true"/>
</wsHttpBinding>
</bindings>

The transaction enabled binding we need to attach with the end point through which our WCF service is exposed.

XML
<endpoint address="" binding="wsHttpBinding" 
	bindingConfiguration="TransactionalBind" contract="WcfService1.IService1">

Step 5: Call the 2 Services in One Transaction

Now that we are done with enabling our server side transaction, it’s time to call the above 2 services in 1 transaction. We need to use the TransactionScope object to group the above 2 WCF services in one transaction. To commit all the WCF transactions, we call the Complete method of the Transactionscope object. To rollback, we need to call the Dispose method.

C#
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
{
try
{

// Call your webservice transactions here
ts.Complete();
}
catch (Exception ex)
{
ts.Dispose();
}
}

Below is the complete code snippet in which we have grouped both the WCF transactions in one scope as shown below:

C#
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
{
try
{
ServiceReference1.Service1Client obj = new ServiceReference1.Service1Client();
obj.UpdateData();
ServiceReference2.Service1Client obj1 = new ServiceReference2.Service1Client();
obj1.UpdateData();
ts.Complete();
}
catch (Exception ex)
{
ts.Dispose();
}
}

Step 6: Test If Your Transaction Works

It’s time to test if the transactions really work. We are calling two services, both of which are doing an insert. After the first WCF service call, we are forcing an exception. In other words, the data insert of the first WCF service should revert back. If you check the database records, you will see no records are inserted by the WCF service.

Click to enlarge

History

  • 6th August, 2009: Initial post
  • Can I update this article? It's not mine!

For further reading do watch the below interview preparation videos and step by step video series.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect https://www.questpond.com
India India

Comments and Discussions

 
PraiseGood Job Pin
rishimuni16-Nov-15 18:03
rishimuni16-Nov-15 18:03 
Questiontransaction in basichttpbinding Pin
Afazal MD 310420921-Oct-14 3:33
professionalAfazal MD 310420921-Oct-14 3:33 
QuestionWCF Transactions Pin
avinash00118-Aug-14 2:22
avinash00118-Aug-14 2:22 
Questionunable to run the code Pin
Member 1096843025-Jul-14 21:24
Member 1096843025-Jul-14 21:24 
GeneralMy vote of 3 Pin
Balaji 3526-Nov-13 22:05
professionalBalaji 3526-Nov-13 22:05 
QuestionTransaction flow between 2 WCF services Pin
Jason Henderson21-Oct-13 5:09
Jason Henderson21-Oct-13 5:09 
AnswerRe: Transaction flow between 2 WCF services Pin
Member 436622026-Nov-13 7:48
Member 436622026-Nov-13 7:48 
GeneralRe: Transaction flow between 2 WCF services Pin
Jason Henderson26-Nov-13 9:14
Jason Henderson26-Nov-13 9:14 
GeneralMy vote of 4 Pin
Senthilkumar Rajagopal10-Oct-13 6:56
Senthilkumar Rajagopal10-Oct-13 6:56 
GeneralMy vote of 5 Pin
Manuele Camilletti5-Jun-13 0:35
professionalManuele Camilletti5-Jun-13 0:35 
GeneralMy vote of 5 Pin
Rahul.KumarSharma18-Dec-12 19:09
Rahul.KumarSharma18-Dec-12 19:09 
GeneralMy vote of 4 Pin
sameer@accenture12-Jun-12 0:21
sameer@accenture12-Jun-12 0:21 
GeneralMy vote of 5 Pin
Siddheshwar Duchal from Pune14-May-12 21:11
Siddheshwar Duchal from Pune14-May-12 21:11 
GeneralMy vote of 5 Pin
Ashok Mandial29-Sep-11 19:58
Ashok Mandial29-Sep-11 19:58 
Questionts.Dispose(); PinPopular
Maxim Novak6-Mar-11 1:27
Maxim Novak6-Mar-11 1:27 
GeneralMy vote of 4 Pin
After205014-Dec-10 22:23
After205014-Dec-10 22:23 
GeneralCan't rollback transaction Pin
tiennl_hsd15-Sep-09 23:19
tiennl_hsd15-Sep-09 23:19 
GeneralRe: Can't rollback transaction Pin
Shivprasad koirala15-Sep-09 23:22
Shivprasad koirala15-Sep-09 23:22 
GeneralRe: Can't rollback transaction Pin
mmccgg17-Sep-09 23:37
mmccgg17-Sep-09 23:37 
GeneralRe: Can't rollback transaction Pin
Abhijeet Yadav2-Nov-09 19:20
Abhijeet Yadav2-Nov-09 19:20 
GeneralRe: Can't rollback transaction Pin
kmanikandan.2010@gmail.com28-Dec-09 21:14
kmanikandan.2010@gmail.com28-Dec-09 21:14 
GeneralRe: Can't rollback transaction Pin
kmanikandan.2010@gmail.com28-Dec-09 22:12
kmanikandan.2010@gmail.com28-Dec-09 22:12 
GeneralRe: Can't rollback transaction Pin
Kent K7-Jun-11 15:06
professionalKent K7-Jun-11 15:06 
To the unitiated and as I'm sure you can attest kmanikandan, there are lots of configurations, attributes, code layouts that work but don't work 100% correctly for the behavior one is after. Therefore the value of an article diminishes when a base behavior (rolling back the transaction) doesn't work, in my opinion.

Never-the-less, thanks Shiva for the well laid out and clear article. I like how you carefully laid out each component of the whole situation. However it didn't work for me to have transaction scopes created within the WCF service methods kmanikandan, and a couple other attributes were required to get things working as desired. The following is the organization and structure of an approach that I found over days of work, to work. This works in a scenario of a .net thick client calling a WCF service hosted by IIS, which in turn uses SQL server for the backend. You must have MSDTC turned on on the IIS and SQL servers (and the client). With this setup I have 1 to several records being inserted into 7 tables, with foreign keys linking all of them in somewhat of a chain. But, if any insert doesn't work, it all rolls back - very nice.


//===interfaces======
[ServiceContract(SessionMode = SessionMode.Required)]
public partial interface IWCFServices
{
  [OperationContract]
  [TransactionFlow(TransactionFlowOption.Allowed)]
  bool ProcessesIns(Process businessObject);

  [OperationContract]
  [TransactionFlow(TransactionFlowOption.Allowed)]
  bool SubProcessesIns(SubProcess businessObject);

  etc...
}


//====service======
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, TransactionAutoCompleteOnSessionClose=true)]
public partial class WCFServices 
{

  //===methods=====
  [OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=false)]
  public bool ProcessesIns(Process businessObject)
  {
  //don't use transaction scope, use try catch and if error occurs it will abort the transaction back at the client.  If no error then the transaction will be passed back in an active state.
  }

  [OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=false)]
  public bool SubProcessesIns(SubProcess businessObject)
  {
  //don't use transaction scope, use try catch and if error occurs it will abort the transaction back at the client.  If no error then the transaction will be passed back in an active state.
  }

  etc.
}


//===Client usage====

      try
        {
        using (var tran = new TransactionScope(TransactionScopeOption.RequiresNew))
          {
          using (ServiceProxy<IWCFServices> service = new ServiceProxy<IWCFServices>(WCFServiceEndpointName))
            {
            //Insert process where true is returned if the method was successful.
            if (service.Proxy.ProcessIns(proc))
              {
               //Insert subprocess that has a foreign key to the process table (the process id is gotten normally immediately above but not shown above)
               if (service.Proxy.SubProcessIns(subProc))
                 {
		  //do more work and more service method calls if desired
                 }
               else
                {
                //A SubProcess record could not be created
                return false;
                }
              }
            else
              {
              //A Process record could not be created
              return false;
              }
            }//end service proxy using
          tran.Complete();//All is good if reached here so can complete the transaction.  Otherwise this will never be executed and when the end using for the transaction is hit, rollbacks will occur.
          }//transaction scope end using
        return true;
        }
      catch (Exception e)
        {
        //display e.Message
        return false;
        }


Notables: The service methods are set to require a transaction scope and not autocomplete after executing and returning. The service is set to require sessions and be a persession instance and to autocomplete on session close.

I hope this helps someone as it was a bit of effort to get working and I found no one source out there that had the whole answer!

Kent

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.