Przepływ transakcji WS
Przykład TransactionFlow demonstruje użycie transakcji koordynowanej przez klienta oraz opcji klienta i serwera dla przepływu transakcji przy użyciu protokołu WS-Atomic Transaction lub OleTransactions. Ten przykład jest oparty na artykule Wprowadzenie , które implementuje usługę kalkulatora, ale operacje są przypisywane w celu zademonstrowania użycia TransactionFlowAttribute
elementu z wyliczaniem TransactionFlowOption w celu określenia stopnia włączenia przepływu transakcji. W zakresie przepływanej transakcji dziennik żądanych operacji jest zapisywany w bazie danych i utrzymuje się do momentu zakończenia skoordynowanej transakcji klienta — jeśli transakcja klienta nie zostanie ukończona, transakcja usługi sieci Web gwarantuje, że odpowiednie aktualizacje bazy danych nie zostaną zatwierdzone.
Uwaga
Procedura instalacji i instrukcje kompilacji dla tego przykładu znajdują się na końcu tego tematu.
Po zainicjowaniu połączenia z usługą i transakcją klient uzyskuje dostęp do kilku operacji usługi. Kontrakt dla usługi jest definiowany w następujący sposób, a każda z operacji demonstruje inne ustawienie dla elementu 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);
}
Definiuje to operacje w kolejności ich przetwarzania:
Żądanie
Add
operacji musi zawierać transakcję przepływową.Subtract
Żądanie operacji może zawierać transakcję przepływową.Multiply
Żądanie operacji nie może zawierać transakcji przepływanej za pośrednictwem jawnego ustawienia NotAllowed.Divide
Żądanie operacji nie może zawierać transakcji przepływanej przez pominięcie atrybutuTransactionFlow
.
Aby włączyć przepływ transakcji, powiązania z włączoną właściwością <transactionFlow> muszą być używane oprócz odpowiednich atrybutów operacji. W tym przykładzie konfiguracja usługi uwidacznia punkt końcowy TCP i punkt końcowy HTTP oprócz punktu końcowego wymiany metadanych. Punkt końcowy TCP i punkt końcowy HTTP używają następujących powiązań, z których obie mają włączoną <właściwość transactionFlow> .
<bindings>
<netTcpBinding>
<binding name="transactionalOleTransactionsTcpBinding"
transactionFlow="true"
transactionProtocol="OleTransactions"/>
</netTcpBinding>
<wsHttpBinding>
<binding name="transactionalWsatHttpBinding"
transactionFlow="true" />
</wsHttpBinding>
</bindings>
Uwaga
Zapewniana przez system funkcja netTcpBinding umożliwia określenie wartości transactionProtocol, natomiast wsHttpBinding dostarczany przez system używa tylko bardziej współdziałającego protokołu WSAtomicTransactionOctober2004. Protokół OleTransactions jest dostępny tylko do użytku przez klientów programu Windows Communication Foundation (WCF).
Dla klasy, która implementuje ICalculator
interfejs, wszystkie metody są przypisywane z właściwością ustawioną TransactionScopeRequired na true
. To ustawienie deklaruje, że wszystkie akcje wykonywane w ramach metody występują w zakresie transakcji. W takim przypadku akcje podjęte obejmują rejestrowanie w bazie danych dzienników. Jeśli żądanie operacji zawiera przepływaną transakcję, akcje są wykonywane w zakresie transakcji przychodzącej lub zostanie automatycznie wygenerowany nowy zakres transakcji.
Uwaga
Właściwość TransactionScopeRequired definiuje zachowanie lokalne implementacji metod usługi i nie definiuje możliwości lub wymagania klienta dotyczące przepływu transakcji.
// 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
}
Na kliencie ustawienia usługi TransactionFlowOption
w operacjach są odzwierciedlane w wygenerowanej definicji interfejsu ICalculator
klienta. Ponadto ustawienia właściwości usługi transactionFlow
są odzwierciedlane w konfiguracji aplikacji klienta. Klient może wybrać transport i protokół, wybierając odpowiedni endpointConfigurationName
element .
// Create a client using either wsat or oletx endpoint configurations
CalculatorClient client = new CalculatorClient("WSAtomicTransaction_endpoint");
// CalculatorClient client = new CalculatorClient("OleTransactions_endpoint");
Uwaga
Obserwowane zachowanie tego przykładu jest takie samo niezależnie od wybranego protokołu lub transportu.
Po zainicjowaniu połączenia z usługą klient tworzy nowe TransactionScope
wywołania operacji usługi.
// 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");
Wywołania operacji są następujące:
Żądanie
Add
przepływa wymaganą transakcję do usługi, a akcje usługi są wykonywane w zakresie transakcji klienta.Pierwsze
Subtract
żądanie przepływa również dozwoloną transakcję do usługi, a następnie ponownie akcje usługi są wykonywane w zakresie transakcji klienta.Drugie
Subtract
żądanie jest wykonywane w ramach nowego zakresu transakcji zadeklarowanegoTransactionScopeOption.Suppress
za pomocą opcji . Spowoduje to pominięcie początkowej transakcji zewnętrznej klienta, a żądanie nie przepływa transakcji do usługi. Takie podejście pozwala klientowi jawnie zrezygnować i chronić przed przepływem transakcji do usługi, jeśli nie jest to wymagane. Akcje usługi są wykonywane w zakresie nowej i niezałączonej transakcji.Żądanie
Multiply
nie przepływa transakcji do usługi, ponieważ wygenerowana definicja interfejsuICalculator
klienta zawiera TransactionFlowAttribute zestaw .TransactionFlowOptionNotAllowed
Żądanie
Divide
nie przepływa transakcji do usługi, ponieważ ponownie wygenerowana definicja interfejsuICalculator
klienta nie zawieraTransactionFlowAttribute
elementu . Akcje usługi są ponownie wykonywane w zakresie innej nowej i niepołączonej transakcji.
Po uruchomieniu przykładu żądania operacji i odpowiedzi są wyświetlane w oknie konsoli klienta. Naciśnij klawisz ENTER w oknie klienta, aby zamknąć klienta.
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.
Rejestrowanie żądań operacji usługi jest wyświetlane w oknie konsoli usługi. Naciśnij klawisz ENTER w oknie klienta, aby zamknąć klienta.
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
Po pomyślnym wykonaniu zakres transakcji klienta zostanie ukończony i wszystkie akcje podjęte w tym zakresie zostaną zatwierdzone. W szczególności zanotowane 5 rekordów jest utrwalanych w bazie danych usługi. Pierwsze 2 z nich wystąpiły w zakresie transakcji klienta.
Jeśli wystąpił wyjątek w dowolnym miejscu w obrębie klienta TransactionScope
, transakcja nie może zakończyć się. Powoduje to, że rekordy zarejestrowane w tym zakresie nie zostaną zatwierdzone w bazie danych. Ten efekt można zaobserwować, powtarzając przykładowy przebieg po oznaczeniu komentarza wywołania w celu ukończenia zewnętrznego TransactionScope
. W takim przebiegu rejestrowane są tylko ostatnie 3 akcje (z drugiego Subtract
, Multiply
i Divide
żądania), ponieważ transakcja klienta nie przepływa do nich.
Aby skonfigurować, skompilować i uruchomić przykład
Aby skompilować wersję rozwiązania w języku C# lub Visual Basic dla platformy .NET, postępuj zgodnie z instrukcjami w temacie Kompilowanie przykładów programu Windows Communication Foundation
Upewnij się, że zainstalowano program SQL Server Express Edition lub SQL Server i że parametry połączenia został poprawnie ustawiony w pliku konfiguracji aplikacji usługi. Aby uruchomić przykład bez użycia bazy danych, ustaw
usingSql
wartość w pliku konfiguracji aplikacji usługi na wartośćfalse
Aby uruchomić przykład w konfiguracji pojedynczej lub między maszynami, postępuj zgodnie z instrukcjami w temacie Uruchamianie przykładów programu Windows Communication Foundation.
Uwaga
W przypadku konfiguracji między maszynami włącz koordynatora transakcji rozproszonych, korzystając z poniższych instrukcji, i użyj narzędzia WsatConfig.exe z zestawu Windows SDK, aby włączyć obsługę sieci transakcji WCF. Aby uzyskać informacje na temat konfigurowania WsatConfig.exe, zobacz Konfigurowanie obsługi transakcji niepodzielnych WS.
Niezależnie od tego, czy przykład jest uruchamiany na tym samym komputerze, czy na różnych komputerach, należy skonfigurować koordynatora transakcji rozproszonych firmy Microsoft (MSDTC), aby włączyć przepływ transakcji sieciowych i użyć narzędzia WsatConfig.exe w celu włączenia obsługi sieci transakcji WCF.
Aby skonfigurować koordynator transakcji rozproszonych firmy Microsoft (MSDTC) do obsługi uruchamiania przykładu
Na maszynie usługi z systemem Windows Server 2003 lub Windows XP skonfiguruj MSDTC, aby zezwolić na przychodzące transakcje sieciowe, postępując zgodnie z tymi instrukcjami.
W menu Start przejdź do Panel sterowania, a następnie Administracja istrative Tools, a następnie pozycję Component Services.
Rozwiń węzeł Usługi składników. Otwórz folder Komputery.
Kliknij prawym przyciskiem myszy pozycję Mój komputer i wybierz polecenie Właściwości.
Na karcie MSDTC kliknij pozycję Konfiguracja zabezpieczeń.
Sprawdź dostęp do sieci DTC i zezwalaj na ruch przychodzący.
Kliknij przycisk OK, a następnie kliknij przycisk Tak , aby ponownie uruchomić usługę MSDTC.
Kliknij przycisk OK, aby zamknąć okno dialogowe.
Na maszynie usługi z systemem Windows Server 2008 lub Windows Vista skonfiguruj MSDTC, aby zezwolić na przychodzące transakcje sieciowe, postępując zgodnie z tymi instrukcjami.
W menu Start przejdź do Panel sterowania, a następnie Administracja istrative Tools, a następnie pozycję Component Services.
Rozwiń węzeł Usługi składników. Otwórz folder Komputery. Wybierz pozycję Koordynator transakcji rozproszonych.
Kliknij prawym przyciskiem myszy pozycję Koordynator DTC i wybierz polecenie Właściwości.
Na karcie Zabezpieczenia zaznacz pozycję Dostęp do sieci DTC i Zezwalaj na ruch przychodzący.
Kliknij przycisk OK, a następnie kliknij przycisk Tak , aby ponownie uruchomić usługę MSDTC.
Kliknij przycisk OK, aby zamknąć okno dialogowe.
Na komputerze klienckim skonfiguruj msdTC, aby zezwalać na wychodzące transakcje sieciowe:
Z menu Start przejdź do
Control Panel
pozycji , a następnie Administracja istrative Tools, a następnie do pozycji Usługi składowe.Kliknij prawym przyciskiem myszy pozycję Mój komputer i wybierz polecenie Właściwości.
Na karcie MSDTC kliknij pozycję Konfiguracja zabezpieczeń.
Sprawdź dostęp do sieci DTC i zezwalaj na ruch wychodzący.
Kliknij przycisk OK, a następnie kliknij przycisk Tak , aby ponownie uruchomić usługę MSDTC.
Kliknij przycisk OK, aby zamknąć okno dialogowe.