Transazioni automatiche e classi .NET Framework

Le istanze di una classe .NET Framework possono prendere parte a una transazione automatica, sempre che la classe venga appositamente preparata. Ciascuna risorsa cui accede un oggetto o un'istanza di una classe viene inserita nella transazione. Se ad esempio un oggetto utilizza ADO.NET per accreditare denaro su un conto in un database, il gestore delle risorse del database determinerà se tale oggetto può essere eseguito in una transazione. In caso positivo l'impiego del database nella transazione avverrà automaticamente.

Per preparare una classe a partecipare a una transazione automatica, attenersi alla seguente procedura:

  1. Applicare TransactionAttribute alla classe.

  2. Derivare la classe dalla classe ServicedComponent.

  3. Firmare l'assembly con un nome sicuro.

    Per firmare l'assembly utilizzando gli attributi, creare una coppia di chiavi mediante Sn.exe:

    sn -k TestApp.snk
    

    Per firmare l'assembly con un nome sicuro, aggiungere l'attributo di assembly AssemblyKeyFileAttribute o AssemblyKeyNameAttribute, specificando il nome del file contenente la coppia di chiavi.

    <assembly: AssemblyKeyFileAttribute("TestApp.snk")>
    [C#]
    [assembly: AssemblyKeyFileAttribute("TestApp.snk")]
    

    Per informazioni dettagliate, vedere Firma di un assembly con un nome sicuro.

  4. Registrare l'assembly che contiene la classe nel catalogo COM+.

    Se il client che chiama le istanze della classe è gestito da Common Language Runtime, la registrazione verrà effettuata automaticamente. Se tuttavia si prevede che possano essere create e chiamate istanze della classe da un client non gestito, utilizzare .NET Services Installation Tool (Regsvcs.exe) per eseguire la registrazione manualmente.

L'esempio che segue mostra come applicare TransactionAttribute a una classe derivata dalla classe ServicedComponent.

<Transaction(TransactionOption.Required)> Public Class SampleClass
   Inherits ServicedComponent
   '. . .
End Class
[C#]
[Transaction(TransactionOption.Required)]
public class SampleClass(): ServicedComponent
{
  //. . .
}

Quando si applica l'attributo di transazione è possibile utilizzare indifferentemente Transaction, transaction, TransactionAttribute e transactionattribute. Utilizzando ad esempio Transaction o transactionattribute, si otterranno risultati identici.

Nella tabella che segue sono elencate e descritte tutte le variazioni dei costruttori.

Valore dell'attributo Descrizione
Disabled Elimina il controllo delle transazioni automatiche sull'oggetto. Un oggetto cui è applicato questo valore di attributo può avvalersi direttamente del Distributed Transaction Coordinator (DTC) per un supporto transazionale.
[Transaction(TransactionOption.Disabled)]
NotSupported Indica che l'oggetto non viene eseguito nell'ambito di una transazione. Quando una richiesta viene elaborata, il corrispondente contesto dell'oggetto viene creato senza transazione, indipendentemente dal fatto che esista una transazione attiva.
[Transaction(TransactionOption.NotSupported)]
Supported Indica che l'oggetto viene eseguito nel contesto di una transazione esistente. Se non è in corso alcuna transazione, l'oggetto verrà eseguito senza transazioni.
[Transaction(TransactionOption.Supported)]
Required

(valore predefinito)

Indica che l'oggetto richiede una transazione. Viene eseguito nell'ambito di una transazione esistente. Se non è in corso alcuna transazione, l'oggetto ne inizierà una.
[Transaction(TransactionOption.Required)]
RequiresNew Indica che l'oggetto richiede una transazione e che viene iniziata una nuova transazione per ciascuna richiesta.
[Transaction(TransactionOption.RequiresNew)]

Esempio di classe

L'esempio di codice che segue illustra vari elementi di una transazione automatica. In questo esempio sia la classe transazionale che il client che chiama la classe sono gestiti dal 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;
  }
}

Vedere anche

Transazioni automatiche | Opzioni di voto nelle transazioni automatiche | Scrittura dei componenti serviti