Friday, February 18, 2011

Transactions in ASP.NET using XmlWebServices


The transaction support for XML Web services created using ASP.NET is based on the same distributed transaction model found in the COM+ Services. This model is based on declaring attributes to decide whether an object participates in a transaction, rather than writing specific code to commit / roll back a transaction.
Once an XML Web service method is marked to participate in a transaction, it will automatically execute within the scope of a transaction. You can control an object's transactional behavior by setting a transaction attribute value on XML Web service method. The attribute value, in turn, determines the transactional behavior of the instantiated object. Thus, based on the declared attribute value, an object will automatically participate in an existing or ongoing transaction, be the root of a new transaction, or never participate in a transaction at all.
In an XML Web service created using ASP.NET, you can declare the web method�s transactional behavior by setting the TransactionOption property of the WebMethod attribute applied to an XML Web service method. If an exception is thrown while the XML Web service method is executing, the transaction is automatically aborted; conversely, if no exception occurs, the transaction is automatically committed.
Lets look at the TransactionOption enumeration:
  • Disabled: Ignores any transaction in the current context.
  • NotSupported: Creates the component in a context with no governing transaction.
  • Required: Shares a transaction if one exists, and creates a new transaction if necessary.
  • RequiresNew: Creates the component with a new transaction, regardless of the state of the current context.
  • Supported: Shares a transaction, if one exists.
To participate in a transaction from an XML Web service method:
  1. Declare an XML Web service.
    Collapse
    <%@ WebService Language="C#" Class=" DBOperations " %>
  2. Add an Assembly directive to System.EnterpriseServices.
    Collapse
    <%@ Assembly name="System.EnterpriseServices" %>
  3. Add references to the System.Web.Services and System.EnterpriseServices namespaces.
    Collapse
    using System.Web.Services;
    using System.EnterpriseServices;
  4. Declare an XML Web service method, setting the TransactionOption property of the WebMethod attribute to TransactionOption.RequiresNew.
Collapse
[ WebMethod(TransactionOption=TransactionOption.RequiresNew)]
public int DeleteAuthor(string lastName)
The following code example shows an XML Web service that exposes a single XML Web service method, called DBOperations. This XML Web service method performs a database operation that is scoped within a transaction. If the database operation does throw an exception, the transaction is automatically stopped; otherwise, the transaction is automatically committed.
Collapse
<%@ WebService Language="C#" Class=" DBOperations " %>
<%@ Assembly name="System.EnterpriseServices" %>

using System;
using System.Data;
using System.Data.SqlClient;
using System.Web.Services;
using System.EnterpriseServices;

public class DBOperations : WebService
{
    
    [ WebMethod(TransactionOption=TransactionOption.RequiresNew)]
    public int DeleteAuthor(string lastName) 
    {
    
        String delCmdSql = 
         "DELETE FROM authors WHERE au_lname='" + lastName + "'" ;
        String exceptionCausingCmdSQL = 
         "DELETE FROM NonExistingTable WHERE  au_lname='" + lastName + "'" ;
        SqlConnection myCon = 
         new SqlConnection("user id=sa;database=pubs;server=myserver");
        SqlCommand delCmd = new SqlCommand(delCmdSQL,myCon);
        SqlCommand exceptionCausingCmd = new
        SqlCommand(exceptionCausingCmdSQL,myCon);       

        // This command should execute properly.
        delCmd.Connection.Open();
        delCmd.ExecuteNonQuery();

        // This command results in an exception, so the first command is
        // automatically rolled back.        
        int cmdResult = exceptionCausingCmd.ExecuteNonQuery();        
        myCon.Close();        
        return cmdResult;        
    }    
}
Transactions across WebServices
Let us look at an example of how the transaction occurs across XML Web service methods.
Consider we are having two servers Server1 and Server2. Server1 hosts XML Web Services WService1 and WService2. Server2 hosts WService3.
WService1 exposes a Web method named WMethod1, WService2 exposes Wmethod2, and WService3 exposes Wmethod3. The Wmethod1 of WService1 is shown in the following code segment:
Collapse
[WebMethod(TransactionOption.RequiresNew)] 
public void WMethod1 () 
{
    Server1. WService2 Service2 = new Server1. WService2 ();    
    Server2.WService3 Service3 = new Server2. WService3 ();     
    Service2.WMethod2();     
    Service3.WMethod3();
}
The TransactionOption property of WMethod2 and WMethod3 are set to TransactionOption.Required.
Collapse
[WebMethod(TransactionOption.Required)] 
public void WMethod2 () 
{ 
  //Code to update a row in a table
}

[WebMethod(TransactionOption.Required)] 
public void WMethod3 () 
{ 
  //Code to update a row in another table
}
Develop a client application named myApp that consumes Wmethod1 of WService1. Run myApp. While WMethod1 is calling WMethod3, close myApp.
What is the most likely result? What do you expect? A roll back of the updates made by WMethod2 and WMethod3?
No, the Answer is Wmethod1 continues processing, and whatever updates that are made by the WMethod2 and WMethod3 persists, because transactions do not flow across XML Web service methods.
XML Web service methods can only participate in a transaction as the root of a new transaction. XML Web service methods that call other XML Web service methods participate in different transactions, as transactions do not flow across XML Web service methods.

Indicates the transaction support of an XML Web service method.
[Visual Basic]Public Property TransactionOption As TransactionOption
[C#]public TransactionOption TransactionOption {get; set;}
[C++]public: __property TransactionOption get_TransactionOption();
public: __property void set_TransactionOption(TransactionOption);
[JScript]public function get TransactionOption() : TransactionOption;
public function set TransactionOption(TransactionOption);

Property Value

The transaction support of an XML Web service method. The default is Disabled.

Remarks

XML Web service methods can only participate as the root object in a transaction, due to the stateless nature of the HTTP protocol. XML Web service methods can invoke COM objects that participate in the same transaction as the XML Web service method, if the COM object is marked to run within a transaction in the Component Services administrative tool. If an XML Web service method with a TransactionOption property of Required or RequiresNew invokes another XML Web service method with a TransactionOption property of Required or RequiresNew, each XML Web service method participates in its own transaction, because an XML Web service method can only act as the root object in a transaction.
Item Description
Disabled Indicates that the XML Web service method does not run within the scope of a transaction. When a request is processed, the XML Web service method is executed without a transaction. [WebMethod(TransactionOption= TransactionOption.Disabled)]
NotSupported Indicates that the XML Web service method does not run within the scope of a transaction. When a request is processed, the XML Web service method is executed without a transaction. [WebMethod(TransactionOption= TransactionOption.NotSupported)]
Supported Indicates that the XML Web service method does not run within the scope of transactions. When a request is processed, the XML Web service is created without a transaction. [WebMethod(TransactionOption= TransactionOption.Supported)]
Required Indicates that the XML Web service method requires a transaction. Since XML Web service methods can only participate as the root object in a transaction, a new transaction will be created for the XML Web service method. [WebMethod(TransactionOption= TransactionOption.Required)]
RequiresNew Indicates that the XML Web service method requires a new transaction. When a request is processed, the XML Web service is created within a new transaction. [WebMethod(TransactionOption= TransactionOption.RequiresNew)]
If an exception is thrown from or not caught by an XML Web service method, the transaction is automatically aborted. If no exceptions occur the transaction is automatically committed unless the method explicitly calls SetAbort.

Example

[Visual Basic, C#] The example below begins a new transaction when the Transfer method is called.
[Visual Basic] 
<%@ WebService Language="VB" Class="Bank"%>
<%@ assembly name="System.EnterpriseServices,Version=1.0.3300.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" %>
 
Imports System
Imports System.Web.Services
Imports System.EnterpriseServices

Public Class Bank
    Inherits WebService    
    
    <WebMethod(TransactionOption := TransactionOption.RequiresNew)> _    
    Public Sub Transfer(Amount As Long, AcctNumberTo As Long, AcctNumberFrom As Long)
        
        Dim objBank As New MyCOMObject()
        
        If objBank.GetBalance(AcctNumberFrom) < Amount Then
            ' Explicitly abort the transaction.
            ContextUtil.SetAbort()
        Else
            ' Credit and Debit method explictly vote within
            ' the code for their methods whether to commit or
            ' abort the transaction.
            objBank.Credit(Amount, AcctNumberTo)
            objBank.Debit(Amount, AcctNumberFrom)
        End If
    End Sub
End Class
      

[C#] 
<%@ WebService Language="C#" Class="Bank"%>
<%@ assembly name="System.EnterpriseServices,Version=1.0.3300.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" %>
 
 using System;
 using System.Web.Services;
 using System.EnterpriseServices;
 
 public class Bank : WebService {
 
      [ WebMethod(TransactionOption=TransactionOption.RequiresNew) ]
      public void Transfer(long Amount, long AcctNumberTo, long AcctNumberFrom)  {
            MyCOMObject objBank = new MyCOMObject();
               
            if (objBank.GetBalance(AcctNumberFrom) < Amount )
               // Explicitly abort the transaction.
               ContextUtil.SetAbort();
            else {
               // Credit and Debit methods explictly vote within
               // the code for their methods whether to commit or
               // abort the transaction.
               objBank.Credit(Amount, AcctNumberTo);
               objBank.Debit(Amount, AcctNumberFrom);
            }
      }
 }
      

No comments:

Post a Comment