Gedrag van servicetransacties
In het voorbeeld Transacties ziet u het gebruik van een door de client gecoördineerde transactie en de instellingen van ServiceBehaviorAttribute en OperationBehaviorAttribute om het gedrag van servicetransacties te beheren. Dit voorbeeld is gebaseerd op het aan de slag-voorbeeld waarmee een rekenmachineservice wordt geïmplementeerd, maar wordt uitgebreid om een serverlogboek te onderhouden van de uitgevoerde bewerkingen in een databasetabel en een stateful uitvoeringstotaal voor de rekenmachinebewerkingen. Persistente schrijfbewerkingen naar de serverlogboektabel zijn afhankelijk van het resultaat van een gecoördineerde clienttransactie. Als de clienttransactie niet is voltooid, zorgt de webservicetransactie ervoor dat de updates voor de database niet worden doorgevoerd.
Notitie
De installatieprocedure en build-instructies voor dit voorbeeld bevinden zich aan het einde van dit artikel.
Het contract voor de service definieert dat voor alle bewerkingen een transactie moet worden gestroomd met aanvragen:
[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);
}
Als u de binnenkomende transactiestroom wilt inschakelen, wordt de service geconfigureerd met de door het systeem geleverde wsHttpBinding, waarbij het kenmerk transactionFlow is ingesteld op true
. Deze binding maakt gebruik van het interoperabele WSAtomicTransactionOctober2004-protocol:
<bindings>
<wsHttpBinding>
<binding name="transactionalBinding" transactionFlow="true" />
</wsHttpBinding>
</bindings>
Nadat zowel een verbinding met de service als een transactie is gestart, opent de client verschillende servicebewerkingen binnen het bereik van die transactie en voltooit de transactie en sluit de verbinding:
// 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();
Op de service zijn er drie kenmerken die van invloed zijn op het gedrag van de servicetransactie, en ze doen dit op de volgende manieren:
Op de
ServiceBehaviorAttribute
:De
TransactionTimeout
eigenschap geeft de periode aan waarin een transactie moet worden voltooid. In dit voorbeeld is het ingesteld op 30 seconden.De
TransactionIsolationLevel
eigenschap geeft het isolatieniveau op dat door de service wordt ondersteund. Dit is vereist om overeen te komen met het isolatieniveau van de client.De
ReleaseServiceInstanceOnTransactionComplete
eigenschap geeft aan of het service-exemplaar wordt gerecycled wanneer een transactie is voltooid. Door deze in tefalse
stellen, onderhoudt de service hetzelfde service-exemplaar in de bewerkingsaanvragen. Dit is vereist om het lopende totaal te behouden. Als dit is ingesteldtrue
op, wordt er na elke voltooide actie een nieuw exemplaar gegenereerd.De
TransactionAutoCompleteOnSessionClose
eigenschap geeft aan of openstaande transacties worden voltooid wanneer de sessie wordt gesloten. Door dezefalse
instelling in te stellen, moeten de afzonderlijke bewerkingen de OperationBehaviorAttribute.TransactionAutoComplete eigenschaptrue
instellen op of expliciet een aanroep naar de OperationContext.SetTransactionComplete() methode vereisen om transacties te voltooien. In dit voorbeeld ziet u beide benaderingen.
Op de
ServiceContractAttribute
:- De
SessionMode
eigenschap geeft aan of de service de juiste aanvragen correleert in een logische sessie. Omdat deze service bewerkingen omvat waarbij de eigenschap OperationBehaviorAttribute TransactionAutoComplete is ingesteld opfalse
(Vermenigvuldigen en Delen),SessionMode.Required
moet worden opgegeven. De bewerking Vermenigvuldigen voltooit bijvoorbeeld de transactie niet en is in plaats daarvan afhankelijk van een latere aanroep om Delen te voltooien met behulp van deSetTransactionComplete
methode. De service moet kunnen bepalen of deze bewerkingen plaatsvinden binnen dezelfde sessie.
- De
Op de
OperationBehaviorAttribute
:De
TransactionScopeRequired
eigenschap geeft aan of de acties van de bewerking moeten worden uitgevoerd binnen een transactiebereik. Dit is ingesteldtrue
op alle bewerkingen in dit voorbeeld en omdat de client de transactie naar alle bewerkingen doorloopt, vinden de acties plaats binnen het bereik van die clienttransactie.De
TransactionAutoComplete
eigenschap geeft aan of de transactie waarin de methode wordt uitgevoerd automatisch wordt voltooid als er geen onverwerkte uitzonderingen optreden. Zoals eerder beschreven, is dit ingesteldtrue
op de bewerkingen Optellen en aftrekken, maarfalse
voor de bewerkingen Vermenigvuldigen en Delen. De bewerkingen Optellen en aftrekken voltooien hun acties automatisch, de splitsing voltooit de acties via een expliciete aanroep van deSetTransactionComplete
methode en de vermenigvuldiging voltooit de acties niet, maar is afhankelijk van en vereist een latere aanroep, zoals delen, om de acties te voltooien.
De toegeschreven service-implementatie is als volgt:
[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
}
Wanneer u het voorbeeld uitvoert, worden de bewerkingsaanvragen en -antwoorden weergegeven in het clientconsolevenster. Druk op Enter in het clientvenster om de client af te sluiten.
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.
De logboekregistratie van de servicebewerkingsaanvragen wordt weergegeven in het consolevenster van de service. Druk op Enter in het clientvenster om de client af te sluiten.
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
Houd er rekening mee dat de service niet alleen het lopende totaal van de berekeningen bewaart, maar ook rapporteert dat er exemplaren worden gemaakt (één exemplaar voor dit voorbeeld) en dat de bewerkingsaanvragen worden bijgehouden in een database. Omdat alle aanvragen de transactie van de client stromen, leidt elke fout bij het voltooien van die transactie ertoe dat alle databasebewerkingen worden teruggedraaid. Dit kan op verschillende manieren worden gedemonstreerd:
Maak commentaar van de aanroep van de client naar
tx.Complete
() en voer deze opnieuw uit. Dit leidt ertoe dat de client het transactiebereik verlaat zonder de transactie te voltooien.Markeer de aanroep van de bewerking Divide-service als commentaar. Hierdoor wordt voorkomen dat de actie die door de vermenigvuldigingsbewerking wordt gestart, wordt voltooid en kan de transactie van de client uiteindelijk ook niet worden voltooid.
Gooi een onverwerkte uitzondering op een willekeurige plaats in het transactiebereik van de client. Op dezelfde manier voorkomt u dat de client de transactie voltooit.
Het resultaat van een van deze bewerkingen is dat geen van de bewerkingen die binnen dat bereik worden uitgevoerd, worden doorgevoerd en het aantal rijen dat aan de database wordt bewaard, niet oplopen.
Notitie
Als onderdeel van het buildproces wordt het databasebestand gekopieerd naar de bin-map. U moet die kopie van het databasebestand bekijken om de rijen te bekijken die in het logboek worden bewaard in plaats van het bestand dat is opgenomen in het Visual Studio-project.
Het voorbeeld instellen, compileren en uitvoeren
Zorg ervoor dat u SQL Server 2005 Express Edition of SQL Server 2005 hebt geïnstalleerd. In het app.config-bestand van de service kan de database
connectionString
worden ingesteld of de databaseinteracties worden uitgeschakeld door de waarde appSettingsusingSql
in te stellen opfalse
.Als u de C# of Visual Basic .NET-editie van de oplossing wilt bouwen, volgt u de instructies in het bouwen van de Windows Communication Foundation-voorbeelden.
Als u het voorbeeld wilt uitvoeren in een configuratie met één of meerdere computers, volgt u de instructies in Het uitvoeren van de Windows Communication Foundation-voorbeelden.
Als u het voorbeeld uitvoert op verschillende computers, moet u de MSDTC (Microsoft Distributed Transaction Coordinator) configureren om de netwerktransactiestroom in te schakelen en het hulpprogramma WsatConfig.exe gebruiken om netwerkondersteuning voor WCF-transacties (Windows Communication Foundation) in te schakelen.
De Microsoft Distributed Transaction Coordinator (MSDTC) configureren ter ondersteuning van het uitvoeren van het voorbeeld op computers
Configureer MSDTC op de servicecomputer om binnenkomende netwerktransacties toe te staan.
Navigeer in het menu Start naar Configuratiescherm, vervolgens Systeembeheer en vervolgens Component Services.
Klik met de rechtermuisknop op Mijn computer en selecteer Eigenschappen.
Klik op het tabblad MSDTC op Beveiligingsconfiguratie.
Controleer de DTC-toegang tot het netwerk en sta inkomend verkeer toe.
Klik op Ja om de MS DTC-service opnieuw op te starten en klik vervolgens op OK.
Klik op OK om het dialoogvenster te sluiten.
Configureer op de servicecomputer en de clientcomputer de Windows Firewall om de Microsoft Distributed Transaction Coordinator (MSDTC) op te nemen in de lijst met behalve toepassingen:
Voer de Windows Firewall-toepassing uit vanuit Configuratiescherm.
Klik op het tabblad Uitzonderingen op Programma toevoegen.
Blader naar de map C:\WINDOWS\System32.
Selecteer Msdtc.exe en klik op Openen.
Klik op OK om het dialoogvenster Programma toevoegen te sluiten en klik nogmaals op OK om de Windows Firewall-applet te sluiten.
Configureer MSDTC op de clientcomputer om uitgaande netwerktransacties toe te staan:
Navigeer in het menu Start naar Configuratiescherm, vervolgens Systeembeheer en vervolgens Component Services.
Klik met de rechtermuisknop op Mijn computer en selecteer Eigenschappen.
Klik op het tabblad MSDTC op Beveiligingsconfiguratie.
Controleer de DTC-toegang tot het netwerk en sta uitgaand verkeer toe.
Klik op Ja om de MS DTC-service opnieuw op te starten en klik vervolgens op OK.
Klik op OK om het dialoogvenster te sluiten.