Monday, April 29, 2013

WCF - Transactions



 Transactions provide a way to perform one or more than one operations as single unit of work

Transaction characteristics
  • Atomic (either all the operations of the transactions succeed or none of them succeed )
  • Consistent (outcome is exactly what we expected it to be)
  • Isolated (Isolated transactions are "private," meaning that no one else knows about the transaction until it is committed)
  • Durable
Name space used : System.Transactions
 
WCF supports transaction on following bindings :

1.       WSHttpBinding

2.       NetTcpBinding

3.       NetNamedPipeBinding

4.       WSDualHttpBinding

5.       WSFederationHttpBinding

TransactionFlow Attribute :

It has three options:
  • Allowed: Transaction may be flowed.
  • Mandatory: Transaction must be flowed.
  • NotAllowed (default): Transaction cannot be flowed
While developing a Service Contract we have to specify the TransactionFlow attribute on each
Operation Contracts that requires a Transaction to be handled
   [ServiceContract]
    public interface ITransectionService
    {
        [OperationContract]
        [TransactionFlow(TransactionFlowOption.Allowed)]
        void Displaydata();   
    }

ServiceBehavior Attribute
The [ServiceBehavior] attribute has three properties that deal with handling and managing transactions
TransactionAutoCompleteOnSessionClose: Specifies whether pending transactions are completed either commited or rollback  when the current session closes.
TransactionIsolationLevel: Determines the isolation level(hold locks on the data) of the transaction.
TransactionTimeout: Specifies the period in which a transaction has to complete.  If the transaction has not completed before the timeout value has been reached, the transaction is rolled back.

OperationBehavior Attribute :
The [OperationBehavior] also has followingof properties related to transactions.

TransactionAutoComplete: Specifies that transactions will be auto-completed if no exceptions occur.
TransactionScopeRequired: Specifies whether the associate method requires a transaction.

 [OperationBehavior(TransactionScopeRequired = true,TransactionAutoComplete=true)]


Enable transaction flow using WCF service config file
<bindings>
      <wsHttpBinding>
        <binding name="TransactionalBind" transactionFlow="true"/>
      </wsHttpBinding>
</bindings>

 

Example :

Database Table :
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Emp](
      [AutoID] [int] IDENTITY(1,1) NOT NULL,
      [Name] [varchar](50) NULL,
      [Designation] [varchar](50) NULL,
      [Salary] [int] NULL,
 CONSTRAINT [PK_Emp] PRIMARY KEY CLUSTERED
(
      [AutoID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF

Interface:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;


namespace WcfService1
{  
    [ServiceContract]
    public interface ITransectionService
    {
        [OperationContract]
        [TransactionFlow(TransactionFlowOption.Mandatory)]
        int AddEmp(int Salary,string Name, string Designation);   
       
    }   
}


Service :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Transactions;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System.Transactions;

namespace WcfService1
{

    
    public class TransectionService : ITransectionService
    {
     
        [OperationBehavior(TransactionScopeRequired = true)]
        public int AddEmp(int Salary, string Name, string Designation)
        {
            int retval = 0;
            Emp em = new Emp();         
            em.Name = Name;
            em.Designation = Designation;
            em.Salary = Salary ;                          
         
            using (Database1Entities ctx = new Database1Entities())
            {
              
                ctx.Emps.AddObject(em);
                retval=ctx.SaveChanges();
            }

           return retval;
        }

     
    }
}


Webconfig:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
 
  <connectionStrings>

     <add name="Database1Entities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.\SQLEXPRESS;attachdbfilename=|DataDirectory|\Database1.mdf;integrated security=True;user instance=True;multipleactiveresultsets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

  </connectionStrings>
 
  <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      </assemblies>
    </compilation>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" />         
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <wsHttpBinding>
        <binding name="transactionalWsatHttpBinding" transactionFlow="true" />
      </wsHttpBinding>
    </bindings>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="false" />
    <services>
      <service name="WcfService1.TransectionService">
        <endpoint name="" address="http://localhost:56464/TransectionService.svc" bindingConfiguration="transactionalWsatHttpBinding" binding="wsHttpBinding" contract="WcfService1.ITransectionService" />

      </service>
    </services>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
</configuration>

Client :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;
using System.Data.SqlClient;
using System.Configuration;

namespace WCF_Transaction
{
    class Program
    {
        static void Main(string[] args)
        {

            //We TransactionScope object to group the WCF services  operations in one transaction.
            //Here we are colling same service TWO times with different objects.
            using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                try
                {
                    // declare object 1 to call servic method
WCF_Transaction.TransectionServiceServiceref.TransectionServiceClient Obj1 = new WCF_Transaction.TransectionServiceServiceref.TransectionServiceClient();
                    int A = Obj1.AddEmp(10000,"Employee1", "Manager");

                    // declare object 1 to call servic method
WCF_Transaction.TransectionServiceServiceref.TransectionServiceClient Obj2 = new WCF_Transaction.TransectionServiceServiceref.TransectionServiceClient();
                    int B = Obj1.AddEmp(2000,"Employee2", "Director");
                    Console.WriteLine(" Done , press enter to exit  ");
                   
                    ts.Complete();
                }
                catch
                {
                    Console.WriteLine("Unable to process transaction,press enter to exit  ");

                    ts.Dispose();
                }
                Console.ReadLine();
            }
        }
    }
     
    
}


OutPut:




1 comment :

  1. transaction fails senerio not available in this demo. and when i use ts.Rollback() method..may example is not suitable ...but i can say is as per this demo can get basic idea about

    Transactions in WCF.

    ...Waiting for next article....Lavi

    ReplyDelete