Udostępnij za pośrednictwem


Zachowanie transakcji usługi

W przykładzie Transakcje przedstawiono użycie transakcji koordynowanej przez klienta oraz ustawień atrybutów ServiceBehaviorAttribute i OperationBehaviorAttribute w celu kontrolowania zachowania transakcji usługi. Ten przykład jest oparty na temacie Wprowadzenie , który implementuje usługę kalkulatora, ale jest rozszerzony w celu obsługi dziennika serwera wykonanych operacji w tabeli bazy danych oraz stanowej sumy bieżącej dla operacji kalkulatora. Utrwalone zapisy w tabeli dziennika serwera są zależne od wyniku skoordynowanej transakcji klienta — jeśli transakcja klienta nie zostanie ukończona, transakcja usługi sieci Web gwarantuje, że aktualizacje bazy danych nie zostaną zatwierdzone.

Uwaga

Procedura instalacji i instrukcje kompilacji dla tego przykładu znajdują się na końcu tego tematu.

Kontrakt usługi definiuje, że wszystkie operacje wymagają przepływu transakcji z żądaniami:

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

Aby włączyć przepływ transakcji przychodzących, usługa jest skonfigurowana z udostępnionym przez system atrybutem wsHttpBinding z atrybutem transactionFlow ustawionym na truewartość . To powiązanie używa międzyoperacyjnego protokołu WSAtomicTransactionOctober2004:

<bindings>
  <wsHttpBinding>
    <binding name="transactionalBinding" transactionFlow="true" />
  </wsHttpBinding>
</bindings>

Po zainicjowaniu połączenia z usługą i transakcją klient uzyskuje dostęp do kilku operacji usługi w zakresie tej transakcji, a następnie kończy transakcję i zamyka połączenie:

// Create a client
CalculatorClient client = new CalculatorClient();

// Create a transaction scope with the default isolation level of Serializable
using (TransactionScope tx = new TransactionScope())
{
    Console.WriteLine("Starting transaction");

    // Call the Add service operation.
    double value = 100.00D;
    Console.WriteLine("  Adding {0}, running total={1}",
                                        value, client.Add(value));

    // Call the Subtract service operation.
    value = 45.00D;
    Console.WriteLine("  Subtracting {0}, running total={1}",
                                        value, client.Subtract(value));

    // Call the Multiply service operation.
    value = 9.00D;
    Console.WriteLine("  Multiplying by {0}, running total={1}",
                                        value, client.Multiply(value));

    // Call the Divide service operation.
    value = 15.00D;
    Console.WriteLine("  Dividing by {0}, running total={1}",
                                        value, client.Divide(value));

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

Console.WriteLine("Transaction committed");

// Closing the client gracefully closes the connection and cleans up resources
client.Close();

W usłudze istnieją trzy atrybuty, które wpływają na zachowanie transakcji usługi, i robią to w następujący sposób:

  • Na stronie :ServiceBehaviorAttribute

    • Właściwość TransactionTimeout określa okres, w którym transakcja musi zostać ukończona. W tym przykładzie jest ustawiona wartość 30 sekund.

    • Właściwość TransactionIsolationLevel określa poziom izolacji, który obsługuje usługa. Jest to wymagane do dopasowania poziomu izolacji klienta.

    • Właściwość ReleaseServiceInstanceOnTransactionComplete określa, czy wystąpienie usługi jest odzyskiwanych po zakończeniu transakcji. Ustawiając ją na falsewartość , usługa utrzymuje to samo wystąpienie usługi w żądaniach operacji. Jest to wymagane do utrzymania sumy bieżącej. Jeśli ustawiono wartość true, nowe wystąpienie jest generowane po każdej ukończonej akcji.

    • Właściwość TransactionAutoCompleteOnSessionClose określa, czy zaległe transakcje są wykonywane po zamknięciu sesji. Ustawiając ją na false, poszczególne operacje są wymagane, aby ustawić OperationBehaviorAttribute.TransactionAutoComplete właściwość na true lub jawnie wymagać wywołania OperationContext.SetTransactionComplete() metody w celu ukończenia transakcji. W tym przykładzie przedstawiono oba podejścia.

  • Na stronie :ServiceContractAttribute

    • Właściwość SessionMode określa, czy usługa koreluje odpowiednie żądania do sesji logicznej. Ponieważ ta usługa obejmuje operacje, w których właściwość OperationBehaviorAttribute TransactionAutoComplete jest ustawiona na false wartość (Pomnożenie i dzielenie), SessionMode.Required należy określić. Na przykład operacja mnożenia nie kończy transakcji, a zamiast tego opiera się na późniejszym wywołaniu dzielenia w celu ukończenia przy użyciu SetTransactionComplete metody . Usługa musi mieć możliwość określenia, czy te operacje występują w ramach tej samej sesji.
  • Na stronie :OperationBehaviorAttribute

    • Właściwość TransactionScopeRequired określa, czy akcje operacji powinny być wykonywane w zakresie transakcji. Ta wartość jest ustawiona true dla wszystkich operacji w tym przykładzie i, ponieważ klient przepływa transakcję do wszystkich operacji, akcje są wykonywane w zakresie tej transakcji klienta.

    • Właściwość TransactionAutoComplete określa, czy transakcja, w której metoda jest wykonywana automatycznie, jeśli nie wystąpią nieobsługiwane wyjątki. Zgodnie z wcześniejszym opisem dla operacji Dodawania i odejmowania jest ona ustawiona true na operacje false Mnożenie i Dzielenie. Operacje Dodawania i odejmowania wykonują akcje automatycznie, podział wykonuje akcje za pomocą jawnego wywołania SetTransactionComplete metody, a funkcja Pomnożyć nie wykonuje swoich akcji, ale zamiast tego opiera się na wywołaniu i wymaga późniejszego wywołania, takiego jak Dzielenie, w celu wykonania akcji.

Implementacja usługi przypisanej jest następująca:

[ServiceBehavior(
    TransactionIsolationLevel = System.Transactions.IsolationLevel.Serializable,
    TransactionTimeout = "00:00:30",
    ReleaseServiceInstanceOnTransactionComplete = false,
    TransactionAutoCompleteOnSessionClose = false)]
public class CalculatorService : ICalculator
{
    double runningTotal;

    public CalculatorService()
    {
        Console.WriteLine("Creating new service instance...");
    }

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public double Add(double n)
    {
        RecordToLog(String.Format(CultureInfo.CurrentCulture, "Adding {0} to {1}", n, runningTotal));
        runningTotal = runningTotal + n;
        return runningTotal;
    }

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

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

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
    public double Divide(double n)
    {
        RecordToLog(String.Format(CultureInfo.CurrentCulture, "Dividing {0} by {1}", runningTotal, n));
        runningTotal = runningTotal / n;
        OperationContext.Current.SetTransactionComplete();
        return runningTotal;
    }

    // Logging method omitted for brevity
}

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
Performing calculations...
  Adding 100, running total=100
  Subtracting 45, running total=55
  Multiplying by 9, running total=495
  Dividing by 15, running total=33
  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 service.
Creating new service instance...
  Writing row 1 to database: Adding 100 to 0
  Writing row 2 to database: Subtracting 45 from 100
  Writing row 3 to database: Multiplying 55 by 9
  Writing row 4 to database: Dividing 495 by 15

Należy pamiętać, że oprócz zachowania sumy bieżącej obliczeń usługa zgłasza tworzenie wystąpień (jedno wystąpienie dla tego przykładu) i rejestruje żądania operacji do bazy danych. Ze względu na to, że wszystkie żądania przepływają transakcję klienta, każde niepowodzenie wykonania tej transakcji powoduje wycofanie wszystkich operacji bazy danych. Można to zademonstrować na wiele sposobów:

  • Oznacz jako komentarz wywołanie tx.Completeklienta () i uruchom ponownie — powoduje to zamknięcie zakresu transakcji przez klienta bez kończenia transakcji.

  • Oznacz jako komentarz wywołanie operacji dzielenia usługi — wyniki te uniemożliwiają ukończenie akcji zainicjowanej przez operację mnożenia, a tym samym zakończenie transakcji klienta ostatecznie zakończy się niepowodzeniem.

  • Wyrzuć nieobsługiwany wyjątek w dowolnym miejscu w zakresie transakcji klienta — podobnie uniemożliwia to klientowi ukończenie transakcji.

Wynikiem któregokolwiek z tych elementów jest to, że żadna z operacji wykonywanych w tym zakresie nie zostanie zatwierdzona, a liczba wierszy utrwalionych w bazie danych nie zwiększa się.

Uwaga

W ramach procesu kompilacji plik bazy danych jest kopiowany do folderu bin. Należy przyjrzeć się tej kopii pliku bazy danych, aby obserwować wiersze utrwalone w dzienniku, a nie plik uwzględniony w projekcie programu Visual Studio.

Aby skonfigurować, skompilować i uruchomić przykład

  1. Upewnij się, że zainstalowano program SQL Server 2005 Express Edition lub SQL Server 2005. W pliku App.config usługi baza danych connectionString może być ustawiona lub interakcje z bazą danych mogą zostać wyłączone przez ustawienie wartości app Ustawienia usingSql na falsewartość .

  2. Aby skompilować wersję rozwiązania w języku C# lub Visual Basic .NET, postępuj zgodnie z instrukcjami w temacie Building the Windows Communication Foundation Samples (Tworzenie przykładów programu Windows Communication Foundation).

  3. 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.

Jeśli uruchomisz przykład między maszynami, musisz 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 programu Windows Communication Foundation (WCF).

Aby skonfigurować koordynator transakcji rozproszonych firmy Microsoft (MSDTC) do obsługi uruchamiania przykładu między maszynami

  1. Na maszynie usługi skonfiguruj MSDTC, aby zezwolić na przychodzące transakcje sieciowe.

    1. W menu Start przejdź do Panel sterowania, a następnie Administracja istrative Tools, a następnie pozycję Component Services.

    2. Kliknij prawym przyciskiem myszy pozycję Mój komputer i wybierz polecenie Właściwości.

    3. Na karcie MSDTC kliknij pozycję Konfiguracja zabezpieczeń.

    4. Sprawdź dostęp do sieci DTC i zezwalaj na ruch przychodzący.

    5. Kliknij przycisk Tak , aby ponownie uruchomić usługę MS DTC, a następnie kliknij przycisk OK.

    6. Kliknij przycisk OK, aby zamknąć okno dialogowe.

  2. Na maszynie usługi i komputerze klienckim skonfiguruj Zaporę systemu Windows, aby uwzględnić koordynatora transakcji rozproszonych firmy Microsoft (MSDTC) na liście z wyjątkiem aplikacji:

    1. Uruchom aplikację Zapora systemu Windows z Panel sterowania.

    2. Na karcie Wyjątki kliknij pozycję Dodaj program.

    3. Przejdź do folderu C:\WINDOWS\System32.

    4. Wybierz Msdtc.exe i kliknij przycisk Otwórz.

    5. Kliknij przycisk OK, aby zamknąć okno dialogowe Dodawanie programu, a następnie ponownie kliknij przycisk OK, aby zamknąć aplet Zapora systemu Windows.

  3. Na komputerze klienckim skonfiguruj msdTC, aby zezwalać na wychodzące transakcje sieciowe:

    1. W menu Start przejdź do Panel sterowania, a następnie Administracja istrative Tools, a następnie pozycję Component Services.

    2. Kliknij prawym przyciskiem myszy pozycję Mój komputer i wybierz polecenie Właściwości.

    3. Na karcie MSDTC kliknij pozycję Konfiguracja zabezpieczeń.

    4. Sprawdź dostęp do sieci DTC i zezwalaj na ruch wychodzący.

    5. Kliknij przycisk Tak , aby ponownie uruchomić usługę MS DTC, a następnie kliknij przycisk OK.

    6. Kliknij przycisk OK, aby zamknąć okno dialogowe.