Automatic Transactions and .NET Framework Classes
Instances of a .NET Framework class can participate in an automatic transaction, as long as you prepare the class to do so. Each resource accessed by a class instance, or object, enlists in the transaction. For example, if an object uses ADO.NET to post money on an account in a database, the resource manager for the database determines whether the object should execute in a transaction. If so, it automatically enlists the database in the transaction.
Use the following process to prepare a class to participate in an automatic transaction:
Apply the TransactionAttribute to your class.
Derive your class from the ServicedComponent Class.
Sign the assembly with a strong name.
To sign the assembly using attributes, create a key pair using Sn.exe:
sn -k TestApp.snk
Add the AssemblyKeyFileAttribute or AssemblyKeyNameAttribute assembly attribute specifying the name of the file containing the key pair to sign the assembly with a strong name.
<assembly: AssemblyKeyFileAttribute("TestApp.snk")> [C#][assembly: AssemblyKeyFileAttribute("TestApp.snk")]
For details see Signing an Assembly with a Strong Name.
Register the assembly that contains your class with the COM+ catalog.
If the client calling instances of your class is managed by the common language runtime, the registration is performed for you. However, if you anticipate that an unmanaged caller might create and call instances of your class, use the .NET Services Installation Tool (Regsvcs.exe) to perform the registration manually.
The following example shows how to apply the TransactionAttribute attribute to a class derived from the ServicedComponent class.
<Transaction(TransactionOption.Required)> Public Class SampleClass
Inherits ServicedComponent
'. . .
End Class
[C#][Transaction(TransactionOption.Required)]
public class SampleClass(): ServicedComponent
{
//. . .
}
When applying the transaction attribute, you can use Transaction, transaction, TransactionAttribute, and transactionattribute interchangeably. For example, you can use either Transaction or transactionattribute to produce identical results.
The following table lists and describes each constructor variation.
Attribute value | Description |
---|---|
Disabled | Eliminates the control of automatic transactions on the object. An object with this attribute value applied can engage the Distributed Transaction Coordinator (DTC) directly for transactional support.
|
NotSupported | Indicates that the object does not run within the scope of transactions. When a request is processed, its object context is created without a transaction, regardless of whether there is a transaction active.
|
Supported | Indicates that the object runs in the context of an existing transaction, if one exists. If no transaction exists, the object runs without a transaction.
|
Required
(default) |
Indicates that the object requires a transaction. It runs in the scope of an existing transaction, if one exists. If no transaction exists, the object starts one.
|
RequiresNew | Indicates that the object requires a transaction and a new transaction is started for each request.
|
Sample Class
The following code example demonstrates several elements of an automatic transaction. In this example, both the transactional class and the client that calls the class are managed by the runtime.
' -----------------------------------------------------------------
' TestApp.vb
' Generate a Strong name:
' sn -k TestApp.snk
' Compile the code:
' vbc /target:exe /r:System.EnterpriseServices.dll TestApp.vb
' Run TestApp:
' start TestApp.exe
' -----------------------------------------------------------------
Option Explicit
Option Strict
Imports System
Imports System.Runtime.CompilerServices
Imports System.EnterpriseServices
Imports System.Reflection
'Registration details.
'COM+ application name as it appears in the COM+ catalog.
<assembly: ApplicationName("TestApp")>
'Strong name for assembly.
<assembly: AssemblyKeyFileAttribute("TestApp.snk")>
<Transaction(TransactionOption.Required)> Public Class Account
Inherits ServicedComponent
'Provides SetComplete behavior in the absence of exceptions.
<AutoComplete()> Public Sub Debit(amount As Integer)
' Do some database work. Any exception thrown here aborts the
' transaction; otherwise, transaction commits.
End Sub
End Class
Public Class client
Public Shared Sub Main()
Dim accountX As New Account()
accountX.Debit(100)
Environment.Exit(0)
End Sub
End Class
[C#]// -----------------------------------------------------------------
// TestApp.cs
// Generate a Strong name:
// sn -k TestApp.snk
// Compile the code:
// csc /target:exe /r:System.EnterpriseServices.dll TestApp.cs
// Run TestApp:
// start TestApp.exe
// -----------------------------------------------------------------
using System;
using System.Runtime.CompilerServices;
using System.EnterpriseServices;
using System.Reflection;
//Registration details.
//COM+ application name as it appears in the COM+ catalog.
[assembly: ApplicationName("TestApp")]
//Strong name for assembly.
[assembly: AssemblyKeyFileAttribute("TestApp.snk")]
[Transaction(TransactionOption.Required)]
public class Account : ServicedComponent
{
//Provides SetComplete behavior in the absence of exceptions.
[AutoComplete]
public void Debit(int amount)
{
// Do some database work. Any exception thrown here aborts the
// transaction; otherwise, transaction commits.
}
}
public class client
{
public static int Main()
{
Account accountX = new Account();
accountX.Debit(100);
return 0;
}
}
See Also
Automatic Transactions | Voting in an Automatic Transaction | Writing Serviced Components