Problem
You need to create a .NET class that participates in automatic transactions.
Solution
Use the appropriate custom attributes from the System.EnterpriseServices namespace.
The sample contains a component that participates in automatic transactions. The component has a single method, TranTest( ) , that instructs the transaction to succeed or fail based on an argument success .
The sample also contains code that instantiates the component that participates in the automatic transaction. A checkbox on the form is used to specify the success parameter when the TranTest( ) method is called.
The C# code is shown in Examples Example 6-1 and Example 6-2.
Example 6-1. ServicedComponentCS Project File: SC0601.cs
// Namespaces, variables, and constants using System.EnterpriseServices; using System.Runtime.CompilerServices; using System.Reflection; // . . . namespace AdoDotNetCookbookCS.ServicedComponentCS { [Transaction(TransactionOption.Required)] public class SC0601 : ServicedComponent { [AutoComplete] public void TranTest(bool success) { // . . . Do some work. if(success) { // don't need the next line since AutoComplete // ContextUtil.SetComplete( ); } else { // Vote to abort. ContextUtil.SetAbort( ); // Raise an exception. throw new System.Exception( "Error in Serviced Component 0601. " + "Transaction aborted."); } } } }
Example 6-2. File: AutoTransactionForm.cs
// Namespaces, variables, and constants using System; using System.Windows.Forms; using AdoDotNetCookbookCS.ServicedComponentCS; // . . . SC0601 sc = new SC0601( ); try { sc.TranTest(transactionSucceedCheckBox.Checked); MessageBox.Show("Transaction successful.", "Automatic Transactions", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch(Exception ex) { MessageBox.Show(ex.Message, "Automatic Transactions", MessageBoxButtons.OK, MessageBoxIcon.Error); }
Discussion
The .NET Common Language Runtime (CLR) supports both manual and automatic transaction models. The automatic distributed transaction model supported by the .NET CLR is the same as that supported by Microsoft Transaction Server (MTS) and COM+. The .NET Framework provides support for transactional components through the EnterpriseServices namespace that provides .NET objects with access to COM+ services.
There are two key benefits to automatic transactions:
The main drawback is:
During the lifetime of an automatic transaction, the objects participating in it can vote to either commit the transaction they are participating in by calling the static SetComplete( ) method of the ContextUtil class or to abort the transaction by calling the static SetAbort( ) method of the ContextUtil class. In the absence of an explicit vote, the default is to commit the transaction. The transaction is committed once it completes if none of the participating objects have voted to abort.
Alternatively, you can apply the AutoCompleteAttribute attribute to a transactional method. This attribute instructs .NET to vote to commit the transaction, provided no exceptions are encountered in the method. If an unhandled exception is thrown, the transaction is automatically rolled back.
The .NET Framework classes must be prepared before they can participate in an automatic transaction. Once an object is marked to participate in a transaction, it will automatically execute within a transaction. The object's transactional behavior is controlled by the value of the transaction attribute for the .NET class, ASP.NET page, or XML web service method using the object. This allows the instantiated object to be configured programmatically to participate automatically in an existing transaction, to start a new transaction, or to not participate in a transaction. The following steps prepare a class to participate in an automatic transaction:
Table 6-1. TransactionOption Enumeration
Value |
Description |
---|---|
Disabled |
Automatic transactions do not control the object: [Transaction(TransactionOption.Disabled)] |
NotSupported |
The object does not run in the scope of transactions: [Transaction(TransactionOption.NotSupported)] |
Supported |
The object runs in context of an existing transaction, if one exists. The object runs without a transaction if one does not exist. [Transaction(TransactionOption.Supported)] |
Required |
The object requires a transaction and runs in context of an existing transaction, if one exists. The object starts a transaction if one does not exist. [Transaction(TransactionOption.Required)] |
RequiresNew |
The object requires a transaction. A new transaction is started for each request. [Transaction(TransactionOption.RequiresNew)] |
sn -k MyApp.snk
Add the AssemblyKeyFileAttribute or AssemblyKeyNameAttribute assembly attribute to specify the file containing the key pair. The following code is used in the solution to sign the assembly:
[assembly: AssemblyDelaySign(false)] [assembly: AssemblyKeyFile( @"C:ADOCookbookCSServicedComponentCS" + "AdoDotNetCookbookCSServicedComponent.snk")] [assembly: AssemblyKeyName("AdoDotNetCookbookCSServicedComponent")]
regsvcs /appname:MyApp MyAssembly.dll
This step isn't strictly required. If a client calling the class is managed by the CLR, the registration will be performed automatically.
Connecting to Data
Retrieving and Managing Data
Searching and Analyzing Data
Adding and Modifying Data
Copying and Transferring Data
Maintaining Database Integrity
Binding Data to .NET User Interfaces
Working with XML
Optimizing .NET Data Access
Enumerating and Maintaining Database Objects
Appendix A. Converting from C# to VB Syntax