Dela via


Beteende för tjänsttransaktion

Exemplet Transaktioner visar användningen av en klientkoordinerad transaktion och inställningarna för ServiceBehaviorAttribute och OperationBehaviorAttribute för att kontrollera tjänstens transaktionsbeteende. Det här exemplet baseras på det Komma igång exempel som implementerar en kalkylatortjänst, men utökas för att underhålla en serverlogg för de utförda åtgärderna i en databastabell och en tillståndskänslig totalkörning för kalkylatoråtgärderna. Beständiga skrivningar till serverloggtabellen är beroende av resultatet av en klientkoordinerad transaktion – om klienttransaktionen inte slutförs säkerställer webbtjänsttransaktionen att uppdateringarna till databasen inte checkas in.

Kommentar

Installationsproceduren och bygginstruktionerna för det här exemplet finns i slutet av den här artikeln.

Kontraktet för tjänsten definierar att alla åtgärder kräver att en transaktion flödas med begäranden:

[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);
}

För att aktivera inkommande transaktionsflöde konfigureras tjänsten med det systembaserade wsHttpBinding med attributet transactionFlow inställt på true. Den här bindningen använder det samverkande protokollet WSAtomicTransactionOctober2004:

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

När du har initierat både en anslutning till tjänsten och en transaktion kommer klienten åt flera tjänståtgärder inom transaktionens omfång och slutför sedan transaktionen och stänger anslutningen:

// 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();

I tjänsten finns det tre attribut som påverkar beteendet för tjänsttransaktionen, och de gör det på följande sätt:

  • På :ServiceBehaviorAttribute

    • Egenskapen TransactionTimeout anger den tidsperiod inom vilken en transaktion måste slutföras. I det här exemplet är det inställt på 30 sekunder.

    • Egenskapen TransactionIsolationLevel anger den isoleringsnivå som tjänsten stöder. Detta krävs för att matcha klientens isoleringsnivå.

    • Egenskapen ReleaseServiceInstanceOnTransactionComplete anger om tjänstinstansen återvinns när en transaktion slutförs. Genom att ställa in den på falseunderhåller tjänsten samma tjänstinstans över åtgärdsbegäranden. Detta krävs för att behålla den löpande summan. Om den är inställd truepå genereras en ny instans efter varje slutförd åtgärd.

    • Egenskapen TransactionAutoCompleteOnSessionClose anger om utestående transaktioner slutförs när sessionen stängs. Genom att ange den till falsemåste de enskilda åtgärderna antingen ange OperationBehaviorAttribute.TransactionAutoComplete egenskapen till true eller uttryckligen kräva ett anrop till OperationContext.SetTransactionComplete() metoden för att slutföra transaktioner. Det här exemplet visar båda metoderna.

  • På :ServiceContractAttribute

    • Egenskapen SessionMode anger om tjänsten korrelerar lämpliga begäranden till en logisk session. Eftersom den här tjänsten innehåller åtgärder där egenskapen OperationBehaviorAttribute TransactionAutoComplete är inställd på false (Multiplicera och dividera) SessionMode.Required måste anges. Åtgärden Multiplicera slutför till exempel inte transaktionen och förlitar sig i stället på ett senare anrop för att dividera för att slutföra med hjälp av SetTransactionComplete metoden. Tjänsten måste kunna fastställa att dessa åtgärder utförs inom samma session.
  • På :OperationBehaviorAttribute

    • Egenskapen TransactionScopeRequired anger om åtgärdens åtgärder ska utföras inom ett transaktionsomfång. Detta är inställt på true för alla åtgärder i det här exemplet och eftersom klienten flödar sin transaktion till alla åtgärder sker åtgärderna inom omfånget för den klienttransaktionen.

    • Egenskapen TransactionAutoComplete anger om transaktionen där metoden körs slutförs automatiskt om inga ohanterade undantag inträffar. Som tidigare beskrivits är detta inställt på true för åtgärderna Lägg till och Subtrahera, men false för åtgärderna Multiplicera och Dela. Åtgärderna Lägg till och subtrahera slutför sina åtgärder automatiskt, Dividera slutför sina åtgärder via ett explicit anrop till SetTransactionComplete metoden och Multiplicera slutför inte sina åtgärder utan förlitar sig i stället på och kräver ett senare anrop, till exempel dividera, för att slutföra åtgärderna.

Implementeringen av den tilldelade tjänsten är följande:

[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
}

När du kör exemplet visas åtgärdsbegäranden och svar i klientkonsolfönstret. Tryck på RETUR i klientfönstret för att stänga av klienten.

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.

Loggningen av tjänståtgärdsbegäranden visas i tjänstens konsolfönster. Tryck på RETUR i klientfönstret för att stänga av klienten.

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

Observera att förutom att behålla den löpande summan av beräkningarna rapporterar tjänsten skapandet av instanser (en instans för det här exemplet) och loggar åtgärdsbegäranden till en databas. Eftersom alla begäranden flödar klientens transaktion resulterar eventuella misslyckade transaktioner i alla databasåtgärder som återställs. Detta kan demonstreras på flera olika sätt:

  • Kommentera ut klientens anrop till tx.Complete() och kör igen – detta resulterar i att klienten avslutar transaktionsomfånget utan att slutföra transaktionen.

  • Kommentera ut anropet till åtgärden Dividera tjänst – det här resultatet hindrar åtgärden som initierades av åtgärden Multiplicera från att slutföras och därmed misslyckas även klientens transaktion.

  • Generera ett ohanterat undantag var som helst i klientens transaktionsomfång – detta förhindrar på samma sätt klienten från att slutföra sin transaktion.

Resultatet av något av dessa är att ingen av de åtgärder som utförs inom det omfånget har checkats in och antalet rader som sparats i databasen inte ökar.

Kommentar

Som en del av byggprocessen kopieras databasfilen till mappen bin. Du måste titta på den kopian av databasfilen för att se de rader som sparas i loggen i stället för filen som ingår i Visual Studio-projektet.

Så här konfigurerar du, skapar och kör exemplet

  1. Kontrollera att du har installerat SQL Server 2005 Express Edition eller SQL Server 2005. I tjänstens App.config-fil kan databasen connectionString anges eller så kan databasinteraktionerna inaktiveras genom att värdet appSettings usingSql anges till false.

  2. Om du vill skapa C# eller Visual Basic .NET-versionen av lösningen följer du anvisningarna i Skapa Windows Communication Foundation-exempel.

  3. Om du vill köra exemplet i en konfiguration med en eller flera datorer följer du anvisningarna i Köra Windows Communication Foundation-exempel.

Om du kör exemplet mellan datorer måste du konfigurera Microsoft Distributed Transaction Coordinator (MSDTC) för att aktivera nätverkstransaktionsflöde och använda verktyget WsatConfig.exe för att aktivera nätverksstöd för WCF-transaktioner (Windows Communication Foundation).

Så här konfigurerar du Microsoft Distributed Transaction Coordinator (MSDTC) för att stödja körning av exemplet mellan datorer

  1. På tjänstdatorn konfigurerar du MSDTC så att inkommande nätverkstransaktioner tillåts.

    1. Från Start-menyn går du till Kontrollpanelen, sedan Administrationsverktyg och sedan Komponenttjänster.

    2. Högerklicka på Min dator och välj Egenskaper.

    3. På fliken MSDTC klickar du på Säkerhetskonfiguration.

    4. Kontrollera nätverks-DTC-åtkomst och Tillåt inkommande trafik.

    5. Klicka på Ja för att starta om MS DTC-tjänsten och klicka sedan på OK.

    6. Stäng dialogrutan genom att klicka på OK.

  2. På tjänstdatorn och klientdatorn konfigurerar du Windows-brandväggen så att den inkluderar Microsoft Distributed Transaction Coordinator (MSDTC) i listan över undantagna program:

    1. Kör Windows-brandväggsprogrammet från Kontrollpanelen.

    2. På fliken Undantag klickar du på Lägg till program.

    3. Bläddra till mappen C:\WINDOWS\System32.

    4. Välj Msdtc.exe och klicka på Öppna.

    5. Klicka på OK för att stänga dialogrutan Lägg till program och klicka på OK igen för att stänga Applet för Windows-brandväggen.

  3. På klientdatorn konfigurerar du MSDTC så att utgående nätverkstransaktioner tillåts:

    1. Från Start-menyn går du till Kontrollpanelen, sedan Administrationsverktyg och sedan Komponenttjänster.

    2. Högerklicka på Min dator och välj Egenskaper.

    3. På fliken MSDTC klickar du på Säkerhetskonfiguration.

    4. Kontrollera Nätverks-DTC-åtkomst och Tillåt utgående trafik.

    5. Klicka på Ja för att starta om MS DTC-tjänsten och klicka sedan på OK.

    6. Stäng dialogrutan genom att klicka på OK.