Monday, August 06, 2007

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.

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;
}
}

No comments: