WS-Transaktionsfluss
In diesem Beispiel werden die Verwendung einer clientkoordinierten Transaktion und die Client- und Serveroptionen für den Transaktionsfluss unter Verwendung des WS-AtomicTransaction-Protokolls oder des OleTransactions-Protokolls erläutert. Dieses Beispiel basiert auf dem Beispiel 'Erste Schritte', das einen Rechnerdienst implementiert. Die Vorgänge sollen jedoch die Verwendung von TransactionFlowAttribute
mit der Enumeration TransactionFlowOption veranschaulichen, die ermittelt, in welchem Umfang der Transaktionsfluss aktiviert ist. Innerhalb des Bereichs des Transaktionsflusses wird ein Protokoll der angeforderten Vorgänge in eine Datenbank geschrieben. Dieses bleibt dort erhalten, bis die clientkoordinierte Transaktion fertiggestellt wurde. Wenn die Clienttransaktion nicht fertiggestellt wird, stellt die Webdiensttransaktion sicher, dass die entsprechenden Aktualisierungen der Datenbank nicht ausgeführt werden.
Tipp
Die Setupprozedur und die Erstellungsanweisungen für dieses Beispiel befinden sich am Ende dieses Themas.
Nach der Initiierung einer Verbindung zu 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);
}
Auf diese Weise werden die Vorgänge in der Reihenfolge, in der sie verarbeitet werden sollten, definiert:
- Eine
Add
-Vorgangsanforderung muss einen Transaktionsfluss beinhalten. - Eine
Subtract
-Vorgangsanforderung kann einen Transaktionsfluss beinhalten. - Eine
Multiply
-Vorgangsanforderung darf keinen Transaktionsfluss durch die explizite NotAllowed-Einstellung beinhalten. - Eine
Divide
-Vorgangsanforderung darf keinen Transaktionsfluss durch die Auslassung einesTransactionFlow
-Attributs beinhalten.
Um den Transaktionsfluss zu aktivieren, müssen zusätzlich zu den entsprechenden Vorgangsattributen Bindungen mit aktivierter <transactionFlow>-Eigenschaft verwendet werden. In diesem Beispiel macht die Dienstkonfiguration zusätzlich zu einem Metadatenaustausch-Endpunkt einen TCP-Endpunkt und einen HTTP-Endpunkt verfügbar. Der TCP-Endpunkt und der HTTP-Endpunkt verwenden die folgenden Bindungen, für die jeweils die <transactionFlow>-Eigenschaft aktiviert ist.
<bindings>
<netTcpBinding>
<binding name="transactionalOleTransactionsTcpBinding"
transactionFlow="true"
transactionProtocol="OleTransactions"/>
</netTcpBinding>
<wsHttpBinding>
<binding name="transactionalWsatHttpBinding"
transactionFlow="true" />
</wsHttpBinding>
</bindings>
Tipp
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 steht nur für die Verwendung durch Windows Communication Foundation (WCF)-Clients bereit.
Für die Klasse, die die ICalculator
-Schnittstelle implementiert, werden alle Methoden mit auf true festgelegter TransactionScopeRequired-Eigenschaft attributiert. Diese Einstellung deklariert, dass alle innerhalb der Methode ausgeführten Aktionen innerhalb des Bereichs einer Transaktion auftreten. In diesem Fall beinhalten die ausgeführten Aktionen auch Aufzeichnung in der Protokolldatenbank. Wenn die Vorgangsanforderung einen Transaktionsfluss beinhaltet, treten die Aktionen innerhalb des Bereichs der eingehenden Transaktion auf, oder es wird automatisch ein neuer Transaktionsbereich erstellt.
Tipp
Die TransactionScopeRequired-Eigenschaft definiert das Verhalten lokal in Bezug auf die Implementierungen der Dienstmethode und definiert nicht die Fähigkeit des Clients für oder die Notwendigkeit eines Transaktionsflusses.
// 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-Eigenschaftseinstellungen des Diensts in der Anwendungskonfiguration des Clients wiedergegeben. Der Client kann den Transport und das Protokoll auswählen, indem er den entsprechenden endpointConfigurationName
auswählt.
// Create a client using either wsat or oletx endpoint configurations
CalculatorClient client = new CalculatorClient("WSAtomicTransaction_endpoint");
// CalculatorClient client = new CalculatorClient("OleTransactions_endpoint");
Tipp
Das beobachtete Verhalten dieses Beispiels ist das gleiche, unabhängig davon, welches Protokoll oder welcher Transport ausgewählt wird.
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 übergibt die erforderliche Transaktion an den Dienst, und die Aktionen des Diensts treten innerhalb des Bereichs der Transaktion des Clients auf. - Die erste
Subtract
-Anforderung übergibt die zulässige Transaktion ebenfalls an den Dienst, und die Aktionen des Diensts treten erneut innerhalb des Bereichs der Transaktion des Clients auf. - Die zweite
Subtract
-Anforderung wird innerhalb eines neuen Transaktionsbereichs ausgeführt, der mit der TransactionScopeOption.Suppress-Option deklariert wird. Auf diese Weise wird die initiale äußere Transaktion des Clients unterdrückt, und die Anforderung übergibt keine Transaktion an den Dienst. Mithilfe dieses Verfahrens kann ein Client explizit deaktiviert werden, und es wird verhindert, dass eine Transaktion an einen Dienst übergeben wird, wenn diese nicht erforderlich ist. Die Aktionen des Diensts treten innerhalb des Bereichs einer neuen und unverbundenen Transaktion auf. - Die
Multiply
-Anforderung übergibt keine Transaktion an den Dienst, da die generierte Definition derICalculator
-Schnittstelle ein TransactionFlowAttribute beinhaltet, für das TransactionFlowOption NotAllowed festgelegt wurde. - Die
Divide
-Anforderung übergibt keine Transaktion an den Dienst, da die generierte Definition derICalculator
-Schnittstelle wiederum kein TransactionFlowAttribute beinhaltet. Die Aktionen des Diensts treten erneut innerhalb des Bereichs einer anderen neuen und unverbundenen Transaktion auf.
Wenn Sie das Beispiel ausführen, werden die Anforderungen und Antworten für den Vorgang 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 einer erfolgreichen Ausführung wird der Transaktionsbereich des Clients abgeschlossen, und alle Aktionen innerhalb des Bereichs werden ausgeführt. Vor allem werden die erwähnten fünf Datensätze in der Datenbank des Diensts beibehalten. Die beiden ersten sind innerhalb des Bereichs der Transaktion des Clients aufgetreten.
Wenn im TransactionScope
des Clients eine Ausnahme aufgetreten ist, kann die Transaktion nicht abgeschlossen werden. Dies führt dazu, dass die innerhalb des Bereichs protokollierten Datensätze nicht an die Datenbank übergeben 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 richten Sie das Beispiel ein, erstellen es und führen es aus
Stellen Sie sicher, dass Sie SQL Server 2005 Express Edition oder SQL Server 2005 installiert haben. In der Datei "App.config" des Diensts können connectionString für die Datenbank festgelegt oder die Datenbankinteraktionen deaktiviert werden, indem der usingSql-Wert für appSettings auf false festgelegt wird.
Zum Erstellen der C#- oder Visual Basic .NET-Version der Projektmappe folgen Sie den unter Erstellen der Windows Communication Foundation-Beispiele aufgeführten Anweisungen.
Verwenden Sie das Tool "WsatConfig.exe" aus der Windows SDK, um Netzwerkunterstützung für WCF-Transaktionen zu aktivieren.
Wenn Sie das Beispiel in einer Konfiguration mit einem Computer oder computerübergreifend ausführen möchten, folgen Sie den unter Durchführen der Windows Communication Foundation-Beispiele aufgeführten Anweisungen.
Wenn Sie das Beispiel auf dem gleichen Computer oder auf anderen Computern ausführen, müssen Sie Microsoft Distributed Transaction Coordinator (MSDTC) konfigurieren, um den Transaktionsfluss über das Netzwerk zu ermöglichen, und mit dem Tool "WsatConfig.exe" die Netzwerkunterstützung von WCF-Transaktionen aktivieren.
So konfigurieren Sie Microsoft Distributed Transaction Coordinator (MSDTC) zum Ausführen des Beispiels
Konfigurieren Sie auf dem Dienstcomputer MSDTC zum Zulassen von eingehenden Netzwerktransaktionen.
- Navigieren Sie im Menü Start zu Systemsteuerung, Verwaltung und Komponentendienste.
- Öffnen Sie den Ordner Computer.
- Klicken Sie mit der rechten Maustaste auf Arbeitsplatz, und wählen Sie Eigenschaften aus.
- Klicken Sie auf der Registerkarte MSDTC auf Sicherheitskonfiguration.
- Aktivieren Sie DTC-Netzwerkzugriff und Eingehende zulassen.
- Klicken Sie auf OK und dann auf Ja, um den MSDTC-Dienst neu zu starten.
- Klicken Sie auf OK, um das Dialogfeld zu schließen.
Konfigurieren Sie auf dem Dienstcomputer und auf dem Clientcomputer die Windows-Firewall so, dass Microsoft Distributed Transaction Coordinator (MSDTC) in der Liste der ausgeschlossenen Anwendungen angezeigt wird:
- Führen Sie die Windows-Firewall-Anwendung über die Systemsteuerung aus.
- Klicken Sie auf der Registerkarte Ausnahmen auf Programm hinzufügen.
- Navigieren Sie zum Ordner C:\WINDOWS\System32.
- Wählen Sie "Msdtc.exe" aus, und klicken Sie auf Öffnen.
- Klicken Sie auf OK , um das Dialogfeld Programm hinzufügen zu schließen, und klicken Sie erneut auf OK, um das Windows-Firewall-Applet zu schließen.
Konfigurieren Sie auf dem Clientcomputer MSDTC zum Zulassen von ausgehenden Netzwerktransaktionen:
- Navigieren Sie im Menü Start zu Control Panel, Verwaltung und Komponentendienste.
- Klicken Sie mit der rechten Maustaste auf Arbeitsplatz, und wählen Sie Eigenschaften aus.
- Klicken Sie auf der Registerkarte MSDTC auf Sicherheitskonfiguration.
- Aktivieren Sie DTC-Netzwerkzugriff und Ausgehende zulassen.
- Klicken Sie auf OK und dann auf Ja, um den MSDTC-Dienst neu zu starten.
- Klicken Sie auf OK, um das Dialogfeld zu schließen.
Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.