Freigeben über


WS-Transaktionsfluss

Das TransactionFlow-Beispiel veranschaulicht die Verwendung einer client-koordinierten Transaktion sowie der Client- und Serveroptionen für den Transaktionsfluss mithilfe des WS-Atomic Transaction- oder OleTransactions-Protokolls. Dieses Beispiel basiert auf dem Beispiel Erste Schritte, das einen Rechnerdienst implementiert. Die Vorgänge sollen jedoch die Verwendung von TransactionFlowAttribute mit der TransactionFlowOption-Enumeration veranschaulichen, die ermittelt, in welchem Umfang der Transaktionsfluss aktiviert ist. Innerhalb des Gültigkeitsbereichs der flussgesteuerten Transaktion wird ein Protokoll der angeforderten Vorgänge in eine Datenbank geschrieben und bleibt erhalten, bis die vom Client koordinierte Transaktion abgeschlossen wurde . Wenn die Clienttransaktion nicht abgeschlossen ist, stellt die Webdiensttransaktion sicher, dass die entsprechenden Aktualisierungen der Datenbank nicht zugesichert werden.

Anmerkung

Die Einrichtungsverfahren und Build-Anweisungen für dieses Beispiel befinden sich am Ende dieses Themas.

Nach dem Initiieren einer Verbindung mit dem Dienst und einer Transaktion greift der Client auf mehrere Dienstvorgänge zu. Der Vertrag für den Dienst ist folgendermaßen definiert, dabei veranschaulicht jeder der Vorgänge eine andere Einstellung für die TransactionFlowOption.

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
    [OperationContract]
    [TransactionFlow(TransactionFlowOption.Mandatory)]
    double Add(double n1, double n2);
    [OperationContract]
    [TransactionFlow(TransactionFlowOption.Allowed)]
    double Subtract(double n1, double n2);
    [OperationContract]
    [TransactionFlow(TransactionFlowOption.NotAllowed)]
    double Multiply(double n1, double n2);
    [OperationContract]
    double Divide(double n1, double n2);
}

Dadurch werden die Vorgänge in der Reihenfolge definiert, in der sie verarbeitet werden sollen:

  • Eine Add-Vorgangsanforderung muss einen Transaktionsfluss beinhalten.

  • Eine Subtract-Vorgangsanforderung kann einen Transaktionsfluss beinhalten.

  • Eine Multiply Vorgangsanforderung darf keine Transaktion enthalten, die über die explizite Einstellung "NotAllowed" abgewickelt wurde.

  • Eine Divide-Vorgangsanforderung darf keinen Transaktionsfluss durch die Auslassung eines TransactionFlow-Attributs beinhalten.

Um den Transaktionsfluss zu aktivieren, müssen Bindungen mit aktivierter <transactionFlow>-Eigenschaft zusätzlich zu den entsprechenden Vorgangsattributen verwendet werden. In diesem Beispiel macht die Konfiguration des Diensts zusätzlich zu einem Metadaten-Exchange-Endpunkt einen TCP-Endpunkt und einen HTTP-Endpunkt verfügbar. Der TCP-Endpunkt und der HTTP-Endpunkt verwenden die folgenden Bindungen, von denen beide die <transactionFlow>-Eigenschaft aktiviert haben.

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

Anmerkung

Die vom System bereitgestellte netTcpBinding ermöglicht die Festlegung des transactionProtocol, während die vom System bereitgestellte wsHttpBinding nur das interoperablere WSAtomicTransactionOctober2004-Protokoll verwendet. Das OleTransactions-Protokoll ist nur für die Verwendung durch Windows Communication Foundation (WCF)-Clients verfügbar.

Für die Klasse, die die ICalculator-Schnittstelle implementiert, werden alle Methoden mit auf TransactionScopeRequired festgelegter true-Eigenschaft attributiert. Diese Einstellung deklariert, dass alle Aktionen, die innerhalb der Methode ausgeführt werden, innerhalb des Bereichs einer Transaktion auftreten. In diesem Fall umfassen die ausgeführten Aktionen die Aufzeichnung in der Protokolldatenbank. Wenn die Vorgangsanforderung eine ablaufende Transaktion enthält, werden die Aktionen innerhalb des Gültigkeitsbereichs der eingehenden Transaktion oder ein neuer Transaktionsbereich automatisch generiert.

Anmerkung

Die TransactionScopeRequired-Eigenschaft definiert das lokale Verhalten für die Dienstmethodenimplementierungen und definiert nicht die Fähigkeit oder Anforderung des Clients für den Fluss einer Transaktion.The TransactionScopeRequired property defines behavior local to the service method implementations and does not define the client's ability to or requirement for flowing a transaction.

// Service class that implements the service contract.
[ServiceBehavior(TransactionIsolationLevel = System.Transactions.IsolationLevel.Serializable)]
public class CalculatorService : ICalculator
{
    [OperationBehavior(TransactionScopeRequired = true)]
    public double Add(double n1, double n2)
    {
        RecordToLog(String.Format(CultureInfo.CurrentCulture, "Adding {0} to {1}", n1, n2));
        return n1 + n2;
    }

    [OperationBehavior(TransactionScopeRequired = true)]
    public double Subtract(double n1, double n2)
    {
        RecordToLog(String.Format(CultureInfo.CurrentCulture, "Subtracting {0} from {1}", n2, n1));
        return n1 - n2;
    }

    [OperationBehavior(TransactionScopeRequired = true)]
    public double Multiply(double n1, double n2)
    {
        RecordToLog(String.Format(CultureInfo.CurrentCulture, "Multiplying {0} by {1}", n1, n2));
        return n1 * n2;
    }

    [OperationBehavior(TransactionScopeRequired = true)]
    public double Divide(double n1, double n2)
    {
        RecordToLog(String.Format(CultureInfo.CurrentCulture, "Dividing {0} by {1}", n1, n2));
        return n1 / n2;
    }

    // Logging method omitted for brevity
}

Auf dem Client werden die TransactionFlowOption-Einstellungen des Diensts für die Vorgänge in der generierten Definition des Clients für die ICalculator-Schnittstelle wiedergegeben. Außerdem werden die transactionFlow Eigenschafteneinstellungen des Diensts in der Anwendungskonfiguration des Clients wiedergegeben. Der Client kann den Transport und das Protokoll auswählen, indem er die entsprechende endpointConfigurationNameauswählt.

// Create a client using either wsat or oletx endpoint configurations
CalculatorClient client = new CalculatorClient("WSAtomicTransaction_endpoint");
// CalculatorClient client = new CalculatorClient("OleTransactions_endpoint");

Anmerkung

Das beobachtete Verhalten dieses Beispiels ist unabhängig davon, welches Protokoll oder welcher Transport gewählt wird, identisch.

Nach der Initiierung der Verbindung zu dem Dienst erstellt der Client einen neuen TransactionScope um die Aufrufe der Dienstvorgänge.

// Start a transaction scope
using (TransactionScope tx =
            new TransactionScope(TransactionScopeOption.RequiresNew))
{
    Console.WriteLine("Starting transaction");

    // Call the Add service operation
    //  - generatedClient will flow the required active transaction
    double value1 = 100.00D;
    double value2 = 15.99D;
    double result = client.Add(value1, value2);
    Console.WriteLine("  Add({0},{1}) = {2}", value1, value2, result);

    // Call the Subtract service operation
    //  - generatedClient will flow the allowed active transaction
    value1 = 145.00D;
    value2 = 76.54D;
    result = client.Subtract(value1, value2);
    Console.WriteLine("  Subtract({0},{1}) = {2}", value1, value2, result);

    // Start a transaction scope that suppresses the current transaction
    using (TransactionScope txSuppress =
                new TransactionScope(TransactionScopeOption.Suppress))
    {
        // Call the Subtract service operation
        //  - the active transaction is suppressed from the generatedClient
        //    and no transaction will flow
        value1 = 21.05D;
        value2 = 42.16D;
        result = client.Subtract(value1, value2);
        Console.WriteLine("  Subtract({0},{1}) = {2}", value1, value2, result);

        // Complete the suppressed scope
        txSuppress.Complete();
    }

    // Call the Multiply service operation
    // - generatedClient will not flow the active transaction
    value1 = 9.00D;
    value2 = 81.25D;
    result = client.Multiply(value1, value2);
    Console.WriteLine("  Multiply({0},{1}) = {2}", value1, value2, result);

    // Call the Divide service operation.
    // - generatedClient will not flow the active transaction
    value1 = 22.00D;
    value2 = 7.00D;
    result = client.Divide(value1, value2);
    Console.WriteLine("  Divide({0},{1}) = {2}", value1, value2, result);

    // Complete the transaction scope
    Console.WriteLine("  Completing transaction");
    tx.Complete();
}

Console.WriteLine("Transaction committed");

Die Aufrufe der Vorgänge sehen folgendermaßen aus:

  • Die Add Anforderung übermittelt die benötigte Transaktion an den Dienst, und dabei erfolgen die Aktionen des Dienstes im Rahmen der Client-Transaktion.

  • Die erste Subtract-Anforderung leitet auch die erlaubte Transaktion an den Dienst weiter, und erneut finden die Aktionen des Dienstes im Rahmen der Transaktion des Clients statt.

  • Die zweite Subtract Anforderung wird innerhalb eines neuen Transaktionsbereichs ausgeführt, der mit der Option TransactionScopeOption.Suppress deklariert wurde. Dadurch wird die anfängliche äußere Transaktion des Clients unterdrückt, und die Anforderung überträgt keine Transaktion an den Dienst. Dieser Ansatz ermöglicht es einem Client, sich bewusst gegen die Weiterleitung einer Transaktion an einen Dienst zu entscheiden und sich davor zu schützen, falls dies nicht erforderlich ist. Die Aktionen des Diensts erfolgen im Rahmen einer neuen und nicht verbundenen Transaktion.

  • Die Multiply-Anforderung leitet keine Transaktion an den Dienst weiter, da die vom Client generierte Definition der ICalculator-Schnittstelle eine Festlegung von TransactionFlowAttribute auf TransactionFlowOptionNotAllowedenthält.

  • Die Divide-Anforderung überträgt keine Transaktion an den Dienst, da die vom Client generierte Definition der ICalculator-Schnittstelle keine TransactionFlowAttributeenthält. Die Aktionen des Diensts treten erneut im Rahmen einer anderen neuen und nicht verbundenen Transaktion auf.

Wenn Sie das Beispiel ausführen, werden die Vorgangsanforderungen und -antworten im Clientkonsolenfenster angezeigt. Drücken Sie im Clientfenster die EINGABETASTE, um den Client zu schließen.

Starting transaction
  Add(100,15.99) = 115.99
  Subtract(145,76.54) = 68.46
  Subtract(21.05,42.16) = -21.11
  Multiply(9,81.25) = 731.25
  Divide(22,7) = 3.14285714285714
  Completing transaction
Transaction committed
Press <ENTER> to terminate client.

Die Protokollierung der Dienstvorgangsanforderungen wird im Konsolenfenster des Diensts angezeigt. Drücken Sie im Clientfenster die EINGABETASTE, um den Client zu schließen.

Press <ENTER> to terminate the service.
  Writing row to database: Adding 100 to 15.99
  Writing row to database: Subtracting 76.54 from 145
  Writing row to database: Subtracting 42.16 from 21.05
  Writing row to database: Multiplying 9 by 81.25
  Writing row to database: Dividing 22 by 7

Nach erfolgreicher Ausführung wird der Transaktionsbereich des Clients abgeschlossen, und alle Aktionen innerhalb dieses Bereichs werden festgeschrieben. Insbesondere werden die notierten 5 Datensätze in der Datenbank des Diensts gespeichert. Die ersten 2 dieser Elemente sind im Rahmen der Transaktion des Kunden aufgetreten.

Wenn eine Ausnahme innerhalb der TransactionScope des Clients aufgetreten ist, kann die Transaktion nicht abgeschlossen werden. Dies bewirkt, dass die in diesem Bereich protokollierten Datensätze nicht für die Datenbank übernommen werden. Dieser Effekt kann beobachtet werden, wenn das Beispiel erneut ausgeführt wird, nachdem der Aufruf zum Abschließen des äußeren TransactionScope auskommentiert wurde. Bei einer solchen Ausführung werden nur die letzen drei Aktionen protokolliert (die zweite Subtract-, die Multiply- und die Divide-Anforderung), da die Clienttransaktion nicht an diese übergeben wurde.

So können Sie das Beispiel einrichten, erstellen und ausführen

  1. Um die C#- oder Visual Basic .NET-Version der Lösung zu erstellen, befolgen Sie die Anweisungen in Building the Windows Communication Foundation Samples.

  2. Stellen Sie sicher, dass Sie SQL Server Express Edition oder SQL Server installiert haben und dass die Verbindungszeichenfolge in der Anwendungskonfigurationsdatei des Diensts ordnungsgemäß festgelegt wurde. Wenn Sie das Beispiel ohne Verwendung einer Datenbank ausführen möchten, legen Sie den usingSql Wert in der Anwendungskonfigurationsdatei des Diensts auf falsefest.

  3. Wenn Sie das Beispiel in einer Konfiguration mit einem Computer oder über Computer hinweg ausführen möchten, folgen Sie den Anweisungen unter Durchführen der Windows Communication Foundation-Beispiele.

    Anmerkung

    Aktivieren Sie für die computerübergreifende Konfiguration den Distributed Transaction Coordinator mithilfe der nachstehenden Anweisungen, und verwenden Sie das WsatConfig.exe Tool aus dem Windows SDK, um die WCF Transactions-Netzwerkunterstützung zu aktivieren. Weitere Informationen zum Einrichten von „WsatConfig.exe“ finden Sie unter Konfigurieren der WS-Atomic Transaction-Unterstützung.

Unabhängig davon, ob Sie das Beispiel auf demselben Computer oder auf verschiedenen Computern ausführen, müssen Sie den Microsoft Distributed Transaction Coordinator (MSDTC) konfigurieren, um den Netzwerktransaktionsfluss zu aktivieren und das WsatConfig.exe Tool zum Aktivieren der WCF-Transaktionsnetzwerkunterstützung zu verwenden.

So konfigurieren Sie den Microsoft Distributed Transaction Coordinator (MSDTC) zur Unterstützung der Ausführung des Beispiels

  1. Konfigurieren Sie auf einem Dienstcomputer, auf dem Windows Server 2003 oder Windows XP ausgeführt wird, MSDTC so, dass eingehende Netzwerktransaktionen zugelassen werden, indem Sie diese Anweisungen befolgen.

    1. Navigieren Sie im Startmenü zur Systemsteuerung, Verwaltungstools, und Komponentendienste.

    2. Erweitern Sie Komponentendienste. Öffnen Sie den Ordner Computer.

    3. Klicken Sie mit der rechten Maustaste auf Arbeitsplatz, und wählen Sie Eigenschaften aus.

    4. Klicken Sie auf der Registerkarte MSDTC auf Sicherheitskonfiguration.

    5. Aktivieren Sie DTC-Netzwerkzugriff und Eingehende zulassen.

    6. Klicken Sie auf OK, und klicken Sie dann auf Ja, um den MSDTC-Dienst neu zu starten.

    7. Klicken Sie auf OK, um das Dialogfeld zu schließen.

  2. Konfigurieren Sie auf einem Dienstcomputer unter Windows Server 2008 oder Windows Vista MSDTC, um eingehende Netzwerktransaktionen zuzulassen, indem Sie diese Anweisungen befolgen.

    1. Navigieren Sie im Startmenü zur Systemsteuerung, Verwaltungstools, und Komponentendienste.

    2. Erweitern Sie Komponentendienste. Öffnen Sie den Ordner Computer. Wählen Sie Verteilter Transaktionskoordinatoraus.

    3. Klicken Sie mit der rechten Maustaste auf Distributed Transaction Coordinator, und wählen Sie Eigenschaften aus.

    4. Aktivieren Sie auf der Registerkarte Sicherheit die Optionen DTC-Netzwerkzugriff und Eingehende zulassen.

    5. Klicken Sie auf OK, und klicken Sie dann auf Ja, um den MSDTC-Dienst neu zu starten.

    6. Klicken Sie auf OK, um das Dialogfeld zu schließen.

  3. Konfigurieren Sie auf dem Clientcomputer MSDTC so, dass ausgehende Netzwerktransaktionen zugelassen werden:

    1. Navigieren Sie vom Start-Menü zu Control Panel, dann zu Verwaltungstoolsund anschließend zu Komponentendienste.

    2. Klicken Sie mit der rechten Maustaste auf Arbeitsplatz, und wählen Sie Eigenschaften aus.

    3. Klicken Sie auf der Registerkarte MSDTC auf Sicherheitskonfiguration.

    4. Aktivieren Sie DTC-Netzwerkzugriff und Ausgehende zulassen.

    5. Klicken Sie auf OK, und klicken Sie dann auf Ja, um den MSDTC-Dienst neu zu starten.

    6. Klicken Sie auf OK, um das Dialogfeld zu schließen.