Przepływ transakcji usług WS
Przykładowy 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 opiera się na Wprowadzenie, który implementuje usługę kalkulatora, lecz operacje zostały przypisane w celu pokazania, jak używać TransactionFlowAttribute
wraz z wyliczeniem TransactionFlowOption do 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.
Notatka
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. Umowa dotycząca usługi jest określona w następujący sposób, gdzie każda z operacji pokazuje inne ustawienie dla 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 operacji
Add
musi zawierać transakcję przepływową.Żądanie operacji
Subtract
może zawierać transakcję przepływową.Żądanie operacji
Multiply
nie może zawierać transakcji przepływanej za pośrednictwem jawnego ustawienia NotAllowed.Żądanie operacji
Divide
nie może zawierać transakcji przepływanej przez pominięcie atrybutuTransactionFlow
.
Aby włączyć przepływ transakcji, oprócz odpowiednich atrybutów operacji należy używać powiązań z włączoną właściwością <transactionFlow>. 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>
Notatka
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 interfejs ICalculator
, wszystkie metody są przypisywane z właściwością TransactionScopeRequired ustawioną na true
. To ustawienie deklaruje, że wszystkie akcje wykonywane w ramach metody występują w zakresie transakcji. W takim przypadku podjęte działania obejmują rejestrowanie w bazie danych logów. Jeśli żądanie operacji zawiera przepływaną transakcję, akcje są wykonywane w zakresie transakcji przychodzącej lub zostanie automatycznie wygenerowany nowy zakres transakcji.
Notatka
Właściwość TransactionScopeRequired definiuje zachowanie lokalne implementacji metod usługi i nie definiuje możliwości lub wymagania klienta w zakresie 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
}
Po stronie klienta ustawienia TransactionFlowOption
usługi dla operacji są odzwierciedlane w definicji interfejsu ICalculator
wygenerowanej przez klienta. Ponadto ustawienia właściwości transactionFlow
usługi są odzwierciedlane w konfiguracji aplikacji klienta. Klient może wybrać transport i protokół, wybierając odpowiednią endpointConfigurationName
.
// Create a client using either wsat or oletx endpoint configurations
CalculatorClient client = new CalculatorClient("WSAtomicTransaction_endpoint");
// CalculatorClient client = new CalculatorClient("OleTransactions_endpoint");
Notatka
Obserwowane zachowanie tego przykładu jest takie samo niezależnie od wybranego protokołu lub transportu.
Po zainicjowaniu połączenia z usługą, klient systemu tworzy nowe TransactionScope
w kontekście wywołań 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
przekazuje wymaganą transakcję do usługi, a działania usługi odbywają się w zakresie transakcji klienta.Pierwsze żądanie
Subtract
obsługuje transakcję objętą pozwoleniem do usługi i ponownie działania usługi odbywają się w ramach transakcji klienta.Drugie żądanie
Subtract
jest wykonywane w ramach nowego zakresu transakcji zadeklarowanego przy użyciu opcjiTransactionScopeOption.Suppress
. To tłumi początkową zewnętrzną transakcję klienta, a żądanie nie przekazuje 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. Działania usługi odbywają się w ramach nowej i niepowiązanej transakcji.Żądanie
Multiply
nie przesyła transakcji do usługi, ponieważ definicja interfejsuICalculator
wygenerowana przez klienta zawiera TransactionFlowAttribute ustawiony na TransactionFlowOptionNotAllowed
.Żądanie
Divide
nie przekazuje transakcji do usługi, ponieważ ponownie wykreowana definicja interfejsuICalculator
klienta nie zawieraTransactionFlowAttribute
. 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 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 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 zostaje zakończony i wszystkie działania podjęte w tym zakresie zostają 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 gdziekolwiek w obszarze TransactionScope
klienta wystąpił wyjątek, transakcja nie może zostać dokonana. Powoduje to, że rekordy zarejestrowane w tym zakresie nie zostaną zatwierdzone w bazie danych. Ten efekt można zaobserwować, powtarzając przebieg próbki po wykomentowaniu wywołania, aby ukończyć zewnętrzną funkcję TransactionScope
. W takim przebiegu rejestrowane są tylko ostatnie 3 akcje (z drugiej Subtract
, Multiply
i żądania Divide
), ponieważ transakcja klienta nie przepływa do nich.
Aby skonfigurować, skompilować i uruchomić przykładowy program
Aby skompilować wersję rozwiązania w języku C# lub Visual Basic na platformie .NET, postępuj zgodnie z instrukcjami w Building the Windows Communication Foundation Samples.
Upewnij się, że zainstalowano program SQL Server Express Edition lub SQL Server i że parametry połączenia zostały poprawnie ustawione w pliku konfiguracji aplikacji usługi. Aby uruchomić przykład bez użycia bazy danych, ustaw wartość
usingSql
w pliku konfiguracji aplikacji usługi nafalse
.Aby uruchomić przykład w konfiguracji pojedynczej lub między maszynami, postępuj zgodnie z instrukcjami w Uruchamianie przykładów programu Windows Communication Foundation.
Notatka
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 Configuring WS-Atomic Transaction Support.
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.
Z menu Start przejdź do Panelu sterowania , następnie do Narzędzi administracyjnych , a potem do Usług składników .
Rozwiń węzeł Component Services. Otwórz folder Komputery.
Kliknij prawym przyciskiem myszy Mój komputer i wybierz pozycję właściwości .
Na karcie MSDTC kliknij pozycję Konfiguracja zabezpieczeń.
Sprawdź dostęp do sieci DTC i zezwalaj na połączenia przychodzące .
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 Panelu sterowania , potem do Narzędzi administracyjnych , a potem do Usług składników .
Rozwiń Component Services. Otwórz folder Komputery. Wybierz koordynatora transakcji rozproszonych.
Kliknij prawym przyciskiem myszy koordynatora DTC i wybierz pozycję właściwości .
Na karcie Zabezpieczeń sprawdź dostęp do sieci DTC i Zezwól na przychodzące.
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
, a następnie Narzędzia administracyjne, a następnie Usługi składników.Kliknij prawym przyciskiem myszy Mój komputer i wybierz właściwości .
Na karcie MSDTC kliknij pozycję Konfiguracja zabezpieczeń.
Sprawdź dostęp do sieci DTC i zezwól na połączenia wychodzące.
Kliknij przycisk OK, a następnie kliknij przycisk Tak, aby ponownie uruchomić usługę MSDTC.
Kliknij przycisk OK, aby zamknąć okno dialogowe.