Participating in Transactions in XML Web Services Created Using ASP.NET

The transaction support for XML Web services leverages the support found in the common language runtime, which is based on the same distributed transaction model found in Microsoft Transaction Server (MTS) and COM+ Services. The model is based on declaratively deciding whether an object participates in a transaction, rather than writing specific code to handle committing and rolling back a transaction. For an XML Web service created using ASP.NET, you can declare an XML Web service'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.

The TransactionOption property of the WebMethod attribute specifies how an XML Web service method participates in a transaction. Although this declarative level represents the logic of a transaction, it is one step removed from the physical transaction. A physical transaction occurs when a transactional object accesses a data resource, such as a database or message queue. The transaction associated with the object automatically flows to the appropriate resource manager. A .NET Framework data provider, such as the .NET Framework Data Provider for SQL Server or the .NET Framework Data Provider for OLE DB, looks up the transaction in the object's context and enlists in the transaction through the Distributed Transaction Coordinator (DTC). The entire transaction occurs automatically.

XML Web service methods can only participate in a transaction as the root of a new transaction. As the root of a new transaction, all interactions with resource managers, such as servers running Microsoft SQL Server, Microsoft Message Queuing (also known as MSMQ), and Microsoft Host Integration Server maintain the ACID properties required to run robust distributed applications. 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.

To participate in a transaction from an XML Web service method

  1. Declare an XML Web service.

    <%@ WebService Language="C#" Class="Orders" %>
    [Visual Basic]
    <%@ WebService Language="VB" Class="Orders" %>
    
  2. Add an Assembly directive to System.EnterpriseServices.

    <%@ Assembly name="System.EnterpriseServices,Version=1.0.3300.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" %>
    
  3. Add references to the System.Web.Services and System.EnterpriseServices namespaces.

    using System.Web.Services;
    using System.EnterpriseServices;
    [Visual Basic]
    Imports System.Web.Services
    Imports System.EnterpriseServices
    
  4. Declare an XML Web service method, setting the TransactionOption property of the WebMethod attribute to TransactionOption.RequiresNew.

    [ WebMethod(TransactionOption=TransactionOption.RequiresNew)]
    public int DeleteAuthor(string lastName)  
    [Visual Basic]
    < WebMethod(TransactionOption:=TransactionOption.RequiresNew)> _
    Public Function DeleteAuthor(lastName As String) As Integer
    

The following code example shows an XML Web service that exposes a single XML Web service method, called DeleteDatabase. 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.

<%@ WebService Language="C#" Class="Orders" %>
<%@ Assembly name="System.EnterpriseServices,Version=1.0.3300.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" %>

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

public class Orders : WebService
{
   [ WebMethod(TransactionOption=TransactionOption.RequiresNew)]
   public int DeleteAuthor(string lastName)  
   {
      String deleteCmd = "DELETE FROM authors WHERE au_lname='" + 
                          lastName + "'" ;
      String exceptionCausingCmdSQL = "DELETE FROM NonExistingTable WHERE
                                       au_lname='" + lastName + "'" ;

      SqlConnection sqlConn = new SqlConnection(
        "Persist Security Info=False;Integrated Security=SSPI;database=pubs;server=myserver");

      SqlCommand deleteCmd = new SqlCommand(deleteCmdSQL,sqlConn);
      SqlCommand exceptionCausingCmd = new
                 SqlCommand(exceptionCausingCmdSQL,sqlConn);
   
      // This command should execute properly.
      deleteCmd.Connection.Open();
      deleteCmd.ExecuteNonQuery();

      // This command results in an exception, so the first command is
      // automatically rolled back.  Since the XML Web service method is
      // participating in a transaction, and an exception occurs, ASP.NET
      // automatically aborts the transaction.  The deleteCmd that
      // executed properly is rolled back.

      int cmdResult = exceptionCausingCmd.ExecuteNonQuery();

      sqlConn.Close();
       
      return cmdResult;
   }
}
[Visual Basic]
<%@ WebService Language="VB" Class="Orders" %>
<%@ assembly name="System.EnterpriseServices" %>

Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Web.Services
Imports System.Web.Util
Imports System.EnterpriseServices

Public Class  Orders

 <WebMethod(TransactionOption:=TransactionOption.RequiresNew)> _
 Public Function DeleteAuthor (lastName as String) as Integer   
     
   Dim deleteCmdSQL As String = "DELETE FROM authors WHERE au_lname='" + _ 
                          lastName + "'" 
   Dim exceptionCausingCmdSQL As String = "DELETE FROM " + _
      "NonExistingTable WHERE au_lname='" + lastName + "'" 

   Dim sqlConn As SqlConnection = New SqlConnection( _
        "Persist Security Info=False;Integrated Security=SSPI;database=pubs;server=myserver")

   Dim deleteCmd As SqlCommand  = New SqlCommand(deleteCmdSQL,sqlConn)
   Dim exceptionCausingCmd As SqlCommand  = New _
                 SqlCommand(exceptionCausingCmdSQL,sqlConn)
   
   ' This command should execute properly.
   deleteCmd.Connection.Open()
   deleteCmd.ExecuteNonQuery()

   ' This command results in an exception, so the first command is
   ' automatically rolled back. Since the XML Web service method is
   ' participating in a transaction, and an exception occurs, ASP.NET
   ' automatically aborts the transaction. The deleteCmd that
   ' executed properly is rolled back.

   Dim cmdResult As Integer = exceptionCausingCmd.ExecuteNonQuery()
   sqlConn.Close()
   
   Return cmdResult
  End Function
End Class

Note When the method implementing the XML Web service method is not called due to an Internet request for the file with an .asmx extension in which it resides or is associated with, the value of the TransactionOption property has no affect. This can happen when the class in which the method resides is a member of a project within Visual Studio .NET and the XML Web service is not invoked using a proxy class. In Visual Studio .NET, a proxy class is generated when a Web Reference is added.

See Also

Processing Transactions | TransactionOption Enumeration | WebMethodAttribute.TransactionOption Property | Building XML Web Services Using ASP.NET