Vorgehensweise: Erstellen eines TransaktionsdienstsHow to: Create a Transactional Service

In diesem Beispiel werden diverse Aspekte der Erstellung eines Transaktionsdiensts und die Nutzung einer von einem Client initiierten Transaktion für die Koordinierung von Dienstvorgängen veranschaulicht.This sample demonstrates various aspects of creating a transactional service and the use of a client-initiated transaction to coordinate service operations.

Erstellen eines TransaktionsdienstsCreating a transactional service

  1. Erstellen Sie einen Dienstvertrag, und fügen Sie den Vorgängen die gewünschte Einstellung aus der TransactionFlowOption-Enumeration hinzu, um die Anforderungen für eingehende Transaktionen festzulegen.Create a service contract and annotate the operations with the desired setting from the TransactionFlowOption enumeration to specify the incoming transaction requirements. Beachten Sie, dass Sie auch das TransactionFlowAttribute auf die zu implementierende Dienstklasse platzieren können.Note that you can also place the TransactionFlowAttribute on the service class being implemented. Hierdurch wird die Einzelimplementierung einer Schnittstelle, die diese Transaktionseinstellungen nutzt, anstelle von allen Implementierungen ermöglicht.This allows for a single implementation of an interface to use these transaction settings, instead of every implementation.

    [ServiceContract]  
    public interface ICalculator  
    {  
        [OperationContract]  
        // Use this to require an incoming transaction  
        [TransactionFlow(TransactionFlowOption.Mandatory)]  
        double Add(double n1, double n2);  
        [OperationContract]  
        // Use this to permit an incoming transaction  
        [TransactionFlow(TransactionFlowOption.Allowed)]  
        double Subtract(double n1, double n2);  
    }  
    
  2. Erstellen Sie eine Implementierungsklasse, und verwenden Sie ServiceBehaviorAttribute, um optional ein TransactionIsolationLevel und einen TransactionTimeout anzugeben.Create an implementation class, and use the ServiceBehaviorAttribute to optionally specify a TransactionIsolationLevel and a TransactionTimeout. Beachten Sie, dass in vielen Fällen der standardmäßige TransactionTimeout von 60 Sekunden und die standardmäßige TransactionIsolationLevel mit dem Wert Unspecified angemessen sind.You should note that in many cases, the default TransactionTimeout of 60 seconds and the default TransactionIsolationLevel of Unspecified are appropriate. Für jeden Vorgang können Sie das OperationBehaviorAttribute-Attribut nutzen, um festzulegen, ob die innerhalb der Methode durchgeführte Arbeit innerhalb des Umfangs eines Transaktionsumfangs gemäß dem Wert des TransactionScopeRequired-Attributs erfolgen soll.For each operation, you can use the OperationBehaviorAttribute attribute to specify whether work performed within the method should occur within the scope of a transaction scope according to the value of the TransactionScopeRequired attribute. In diesem Fall stimmt die für die Add-Methode verwendete Transaktion mit der obligatorischen eingehenden Transaktionen überein, die vom Client kommt, und die für die Subtract-Methode verwendete Transaktion entspricht entweder der eingehenden Transaktion, wenn eine solche vom Client übergeben wurde, oder einer neuen implizit oder lokal erstellten Transaktion.In this case, the transaction used for the Add method is the same as the mandatory incoming transaction that is flowed from the client, and the transaction used for the Subtract method is either the same as the incoming transaction if one was flowed from the client, or a new implicitly and locally created transaction.

    [ServiceBehavior(  
        TransactionIsolationLevel = System.Transactions.IsolationLevel.Serializable,  
        TransactionTimeout = "00:00:45")]  
    public class CalculatorService : ICalculator  
    {  
        [OperationBehavior(TransactionScopeRequired = true)]  
        public double Add(double n1, double n2)  
        {  
            // Perform transactional operation  
            RecordToLog(String.Format("Adding {0} to {1}", n1, n2));  
            return n1 + n2;  
        }  
    
        [OperationBehavior(TransactionScopeRequired = true)]  
        public double Subtract(double n1, double n2)  
        {  
            // Perform transactional operation  
            RecordToLog(String.Format("Subtracting {0} from {1}", n2, n1));  
            return n1 - n2;  
        }  
    
        private static void RecordToLog(string recordText)  
        {  
            // Database operations omitted for brevity  
            // This is where the transaction provides specific benefit  
            // - changes to the database will be committed only when  
            // the transaction completes.  
        }  
    }  
    
  3. Konfigurieren Sie die Bindungen in der Konfigurationsdatei, wobei Sie angeben, dass der Transaktionskontext übergeben werden sollte, und die dafür zu verwendenden Protokolle festlegen.Configure the bindings in the configuration file, specifying that the transaction context should be flowed, and the protocols to be used to do so. Weitere Informationen finden Sie unter ServiceModel-Transaktionskonfiguration.For more information, see ServiceModel Transaction Configuration. Der Bindungstyp wird im binding-Attribut des Endpunktelements angegeben.Specifically, the binding type is specified in the endpoint element’s binding attribute. Die <Endpunkt > Element enthält eine bindingConfiguration -Attribut, das auf die Bindungskonfiguration mit dem Namen transactionalOleTransactionsTcpBinding, wie in der folgenden Beispielkonfiguration gezeigt.The <endpoint> element contains a bindingConfiguration attribute that references a binding configuration named transactionalOleTransactionsTcpBinding, as shown in the following sample configuration.

    <service name="CalculatorService">  
      <endpoint address="net.tcp://localhost:8008/CalcService"  
        binding="netTcpBinding"  
        bindingConfiguration="transactionalOleTransactionsTcpBinding"  
        contract="ICalculator"  
        name="OleTransactions_endpoint" />  
    </service>  
    

    Der Transaktionsfluss wird auf Konfigurationsebene mithilfe des transactionFlow-Attributs aktiviert, und das Transaktionsprotokoll wird über das transactionProtocol-Attribut angegeben (wie in folgender Konfiguration gezeigt).Transaction flow is enabled at the configuration level by using the transactionFlow attribute, and the transaction protocol is specified using the transactionProtocol attribute, as shown in the following configuration.

    <bindings>  
      <netTcpBinding>  
        <binding name="transactionalOleTransactionsTcpBinding"  
          transactionFlow="true"  
          transactionProtocol="OleTransactions"/>  
      </netTcpBinding>  
    </bindings>  
    

Unterstützung mehrerer TransaktionsprotokolleSupporting multiple transaction protocols

  1. Für eine optimale Leistung sollten Sie das OleTransactions-Protokoll für Szenarien im Zusammenhang mit Client und Dienst mithilfe von Windows Communication Foundation (WCF) beschrieben verwenden.For optimal performance, you should use the OleTransactions protocol for scenarios involving a client and service written using Windows Communication Foundation (WCF). Allerdings ist das WS-AtomicTransaction (WS-AT)-Protokoll für Szenarien nützlich, bei denen Interoperabilität mit Protokollstapeln eines Drittanbieters erforderlich ist.However, the WS-AtomicTransaction (WS-AT) protocol is useful for scenarios when interoperability with third-party protocol stacks is required. Sie können konfigurieren, dass WCF-Diensten für beide Protokolle zu unterstützen, indem Sie mehrere Endpunkte mit den entsprechenden protokollspezifischen Bindungen bereitstellen, wie in der folgenden Beispielkonfiguration gezeigt.You can configure WCF services to accept both protocols by providing multiple endpoints with appropriate protocol-specific bindings, as shown in the following sample configuration.

    <service name="CalculatorService">  
      <endpoint address="http://localhost:8000/CalcService"  
        binding="wsHttpBinding"  
        bindingConfiguration="transactionalWsatHttpBinding"  
        contract="ICalculator"  
        name="WSAtomicTransaction_endpoint" />  
      <endpoint address="net.tcp://localhost:8008/CalcService"  
        binding="netTcpBinding"  
        bindingConfiguration="transactionalOleTransactionsTcpBinding"  
        contract="ICalculator"  
        name="OleTransactions_endpoint" />  
    </service>  
    

    Das Transaktionsprotokoll wird über das transactionProtocol-Attribut festgelegt.The transaction protocol is specified using the transactionProtocol attribute. Bei der vom System bereitgestellten wsHttpBinding steht dieses Attribut nicht zur Verfügung, da diese Bindung nur das WS-AT-Protokoll nutzen kann.However, this attribute is absent from the system-provided wsHttpBinding, because this binding can only use the WS-AT protocol.

    <bindings>  
      <wsHttpBinding>  
        <binding name="transactionalWsatHttpBinding"  
          transactionFlow="true" />  
      </wsHttpBinding>  
      <netTcpBinding>  
        <binding name="transactionalOleTransactionsTcpBinding"  
          transactionFlow="true"  
          transactionProtocol="OleTransactions"/>  
      </netTcpBinding>  
    </bindings>  
    

Kontrolle des Abschlusses einer TransaktionControlling the completion of a transaction

  1. Standardmäßig führen WCF-Vorgänge automatisch Transaktionen, wenn keine nicht behandelten Ausnahmen ausgelöst werden.By default, WCF operations automatically complete transactions if no unhandled exceptions are thrown. Sie können dieses Verhalten ändern, indem Sie die TransactionAutoComplete-Eigenschaft und die SetTransactionComplete-Methode verwenden.You can modify this behavior by using the TransactionAutoComplete property and the SetTransactionComplete method. Wenn es erforderlich ist, dass ein Vorgang innerhalb derselben Transaktion erfolgt wie ein anderer Vorgang (Beispiel: ein Debit- und Kredit-Vorgang), können Sie das automatische Verhalten für den Abschluss deaktivieren, indem Sie die TransactionAutoComplete-Eigenschaft auf false festlegen (wie in folgendem Debit-Vorgangsbeispiel gezeigt).When an operation is required to occur within the same transaction as another operation (for example, a debit and credit operation), you can disable the autocomplete behavior by setting the TransactionAutoComplete property to false as shown in the following Debit operation example. Die Transaktion, die der Debit-Vorgang nutzt, wird nicht abgeschlossen, bevor eine Methode mit der TransactionAutoComplete-Eigenschaft auf true aufgerufen wird (wie in Vorgang Credit1 gezeigt) oder wenn die SetTransactionComplete-Methode aufgerufen wird, um explizit die Transaktion als abgeschlossen zu kennzeichnen (wie in Vorgang Credit2 gezeigt).The transaction the Debit operation uses is not completed until a method with the TransactionAutoComplete property set to true is called, as shown in the operation Credit1, or when the SetTransactionComplete method is called to explicitly mark the transaction as complete, as shown in the operation Credit2. Beachten Sie, dass die beiden Kreditvorgänge zu Illustrationszwecken angeführt werden und dass ein einzelner Kreditvorgang üblicher wäre.Note that the two credit operations are shown for illustration purposes, and that a single credit operation would be more typical.

    [ServiceBehavior]  
    public class CalculatorService : IAccount  
    {  
        [OperationBehavior(  
            TransactionScopeRequired = true, TransactionAutoComplete = false)]  
        public void Debit(double n)  
        {  
            // Perform debit operation  
    
            return;  
        }  
    
        [OperationBehavior(  
            TransactionScopeRequired = true, TransactionAutoComplete = true)]  
        public void Credit1(double n)  
        {  
            // Perform credit operation  
    
            return;  
        }  
    
        [OperationBehavior(  
            TransactionScopeRequired = true, TransactionAutoComplete = false)]  
        public void Credit2(double n)  
        {  
            // Perform alternate credit operation  
    
            OperationContext.Current.SetTransactionComplete();  
            return;  
        }  
    }  
    
  2. Zum Zwecke der Transaktionskorrelation erfordert ein Festlegen der TransactionAutoComplete-Eigenschaft auf false die Verwendung einer sitzungsbasierten Bindung.For the purposes of transaction correlation, setting the TransactionAutoComplete property to false requires the use of a sessionful binding. Die Anforderung wird mit der SessionMode-Eigenschaft auf ServiceContractAttribute festgelegt.This requirement is specified with the SessionMode property on the ServiceContractAttribute.

    [ServiceContract(SessionMode = SessionMode.Required)]  
    public interface IAccount  
    {  
        [OperationContract]  
        [TransactionFlow(TransactionFlowOption.Allowed)]  
        void Debit(double n);  
        [OperationContract]  
        [TransactionFlow(TransactionFlowOption.Allowed)]  
        void Credit1(double n);  
        [OperationContract]  
        [TransactionFlow(TransactionFlowOption.Allowed)]  
        void Credit2(double n);  
    }  
    

Kontrolle der Lebensdauer einer TransaktionsdienstinstanzControlling the lifetime of a transactional service instance

  1. WCF verwendet die ReleaseServiceInstanceOnTransactionComplete Eigenschaft, um anzugeben, ob die zugrunde liegende Dienstinstanz beim Abschluss einer Transaktion freigegeben wird.WCF uses the ReleaseServiceInstanceOnTransactionComplete property to specify whether the underlying service instance is released when a transaction completes. Da hier der Standardwert true, sofern nicht anders, WCF-Verhalten auch ein effizientes und vorhersehbares "just-in-Time" konfiguriert.Since this defaults to true, unless configured otherwise, WCF exhibits an efficient and predictable "just-in-time" activation behavior. Aufrufe an einen Dienst bei einer nachfolgenden Transaktion erhalten ohne Auswirkung des Status der vorherigen Transaktion garantiert eine neue Dienstinstanz.Calls to a service on a subsequent transaction are assured a new service instance with no remnants of the previous transaction's state. Obwohl dies oft nützlich sein kann, möchten Sie eventuell den Status innerhalb der Dienstinstanz bis über den Transaktionsabschluss hinaus beibehalten.While this is often useful, sometimes you may want to maintain state within the service instance beyond the transaction completion. Beispielsweise könnte dies der Fall sein, wenn erforderliche Status oder Handle zu Ressourcen in der Anschaffung oder Wiederherstellung teuer sind.Examples of this would be when required state or handles to resources are expensive to retrieve or reconstitute. Sie können dies vornehmen, indem Sie die ReleaseServiceInstanceOnTransactionComplete-Eigenschaft auf false festlegen.You can do this by setting the ReleaseServiceInstanceOnTransactionComplete property to false. Mit dieser Einstellung stehen die Instanz und alle zugehörigen Status bei folgenden Aufrufen zur Verfügung.With that setting, the instance and any associated state will be available on subsequent calls. Achten Sie hierbei insbesondere darauf, wann und wie der Zustand und die Transaktion gelöscht und abgeschlossen werden.When using this, give careful consideration to when and how state and transactions will be cleared and completed. Das folgende Beispiel veranschaulicht die Vorgehensweise, indem die Instanz mit der runningTotal-Variablen beibehalten wird.The following sample demonstrates how to do this by maintaining the instance with the runningTotal variable.

    [ServiceBehavior(TransactionIsolationLevel = [ServiceBehavior(  
        ReleaseServiceInstanceOnTransactionComplete = false)]  
    public class CalculatorService : ICalculator  
    {  
        double runningTotal = 0;  
    
        [OperationBehavior(TransactionScopeRequired = true)]  
        public double Add(double n)  
        {  
            // Perform transactional operation  
            RecordToLog(String.Format("Adding {0} to {1}", n, runningTotal));  
            runningTotal = runningTotal + n;  
            return runningTotal;  
        }  
    
        [OperationBehavior(TransactionScopeRequired = true)]  
        public double Subtract(double n)  
        {  
            // Perform transactional operation  
            RecordToLog(String.Format("Subtracting {0} from {1}", n, runningTotal));  
            runningTotal = runningTotal - n;  
            return runningTotal;  
        }  
    
        private static void RecordToLog(string recordText)  
        {  
            // Database operations omitted for brevity  
        }  
    }  
    

    Hinweis

    Da die Lebensdauer der Instanz ein dienstinternes Verhalten ist und durch die ServiceBehaviorAttribute-Eigenschaft kontrolliert wird, sind keine Änderungen an der Dienstkonfiguration oder am Dienstvertrag erforderlich.Since the instance lifetime is a behavior that is internal to the service, and controlled through the ServiceBehaviorAttribute property, no modification to the service configuration or service contract is required to set the instance behavior. Darüber hinaus enthält die Übertragung keine Darstellung hierzu.In addition, the wire will contain no representation of this.