Transacties naar en uit workflowservices stromen
Werkstroomservices en -clients kunnen deelnemen aan transacties. Als u een servicebewerking wilt laten deelnemen aan een omgevingstransactie, plaatst u een Receive activiteit binnen een TransactedReceiveScope activiteit. Alle aanroepen van een Send of een SendReply activiteit binnen de TransactedReceiveScope activiteit worden ook uitgevoerd binnen de omgevingstransactie. Een werkstroomclienttoepassing kan een omgevingstransactie maken met behulp van de TransactionScope activiteits- en oproepservicebewerkingen met behulp van de omgevingstransactie. In dit onderwerp wordt uitgelegd hoe u een werkstroomservice en werkstroomclient maakt die deelneemt aan transacties.
Waarschuwing
Als een werkstroomservice-exemplaar wordt geladen binnen een transactie en de werkstroom een Persist activiteit bevat, wordt het werkstroomexemplaren geblokkeerd totdat er een time-out optreedt voor de transactie.
Belangrijk
Wanneer u een TransactedReceiveScope app gebruikt, wordt aanbevolen om alle ontvangstbewerkingen in de werkstroom binnen TransactedReceiveScope activiteiten te plaatsen.
Belangrijk
Wanneer het gebruik TransactedReceiveScope en de berichten in de verkeerde volgorde binnenkomen, wordt de werkstroom afgebroken wanneer het eerste bericht buiten de order wordt bezorgd. U moet ervoor zorgen dat uw werkstroom altijd op een consistent stoppunt staat wanneer de werkstroom inactief is. Hierdoor kunt u de werkstroom opnieuw starten vanaf een eerder persistentiepunt als de werkstroom wordt afgebroken.
Een gedeelde bibliotheek maken
Maak een nieuwe lege Visual Studio-oplossing.
Voeg een nieuw klassebibliotheekproject toe met de naam
Common
. Voeg verwijzingen toe aan de volgende assembly's:System.Activities.dll
System.ServiceModel.dll
System.ServiceModel.Activities.dll
System.Transactions.dll
Voeg een nieuwe klasse toe die aan het
Common
project wordt aangeroepenPrintTransactionInfo
. Deze klasse is afgeleid van NativeActivity en overbelast de Execute methode.using System; using System; using System.Activities; using System.Transactions; namespace Common { public class PrintTransactionInfo : NativeActivity { protected override void Execute(NativeActivityContext context) { RuntimeTransactionHandle rth = context.Properties.Find(typeof(RuntimeTransactionHandle).FullName) as RuntimeTransactionHandle; if (rth == null) { Console.WriteLine("There is no ambient RuntimeTransactionHandle"); } Transaction t = rth.GetCurrentTransaction(context); if (t == null) { Console.WriteLine("There is no ambient transaction"); } else { Console.WriteLine("Transaction: {0} is {1}", t.TransactionInformation.DistributedIdentifier, t.TransactionInformation.Status); } } } }
Dit is een systeemeigen activiteit die informatie weergeeft over de omgevingstransactie en wordt gebruikt in zowel de service- als clientwerkstromen die in dit onderwerp worden gebruikt. Bouw de oplossing om deze activiteit beschikbaar te maken in de sectie Algemeen van de Werkset.
De werkstroomservice implementeren
Voeg een nieuwe WCF-werkstroomservice toe, aangeroepen
WorkflowService
aan hetCommon
project. Als u dit wilt doen, klikt u met de rechtermuisknop op hetCommon
project, selecteert u Toevoegen, Nieuw item ..., selecteert u Werkstroom onder Geïnstalleerde sjablonen en selecteert u WCF-werkstroomservice.Verwijder de standaard
ReceiveRequest
- enSendResponse
activiteiten.Sleep een WriteLine activiteit naar de activiteit en zet deze
Sequential Service
neer. Stel de teksteigenschap in op"Workflow Service starting ..."
zoals wordt weergegeven in het volgende voorbeeld.! [Een WriteLine-activiteit toevoegen aan de sequentiële serviceactiviteit (./media/flowing-transactions-into-and-out-of-workflow-services/add-writeline-sequential-service.jpg)
Sleep een TransactedReceiveScope na de activiteit en zet deze WriteLine neer. De TransactedReceiveScope activiteit vindt u in de sectie Berichten van de Werkset. De TransactedReceiveScope activiteit bestaat uit twee secties Aanvraag en Hoofdtekst. De sectie Aanvraag bevat de Receive activiteit. De sectie Hoofdtekst bevat de activiteiten die binnen een transactie moeten worden uitgevoerd nadat een bericht is ontvangen.
Selecteer de TransactedReceiveScope activiteit en klik op de knop Variabelen . Voeg de volgende variabelen toe.
Notitie
U kunt de gegevensvariabele die er standaard is, verwijderen. U kunt ook de bestaande handlevariabele gebruiken.
Sleep een Receive activiteit in de sectie Aanvraag van de activiteit en zet deze TransactedReceiveScope neer. Stel de volgende eigenschappen in:
Eigenschappen Weergegeven als CanCreateInstance Waar (schakel het selectievakje in) OperationName StartSample ServiceContractName ITransactionSample De werkstroom moet er als volgt uitzien:
Klik op de koppeling Definiëren... in de Receive activiteit en voer de volgende instellingen uit:
Sleep een Sequence activiteit en zet deze neer in de sectie Hoofdtekst van de TransactedReceiveScope. Sleep twee WriteLine activiteiten binnen de Sequence activiteit en zet deze neer en stel de Text eigenschappen in zoals wordt weergegeven in de volgende tabel.
Activiteit Weergegeven als 1e WriteLine "Service: Ontvangen voltooid" 2e WriteLine "Service: Received = " + requestMessage De werkstroom moet er nu als volgt uitzien:
Sleep de activiteit en zet deze
PrintTransactionInfo
neer na de tweede WriteLine activiteit in de hoofdtekst van de TransactedReceiveScope activiteit.Sleep een Assign activiteit na de
PrintTransactionInfo
activiteit en stel de eigenschappen ervan in volgens de volgende tabel.Eigenschappen Weergegeven als Tot replyMessage Weergegeven als "Service: Antwoord verzenden." Sleep een WriteLine activiteit na de activiteit en stel de Assign eigenschap ervan in Text op 'Service: Begin antwoord'.
De werkstroom moet er nu als volgt uitzien:
Klik met de rechtermuisknop op de Receive activiteit en selecteer SendReply maken en plak deze na de laatste WriteLine activiteit. Klik op de koppeling Definiëren... in de
SendReplyToReceive
activiteit en voer de volgende instellingen uit.Sleep een WriteLine activiteit na de
SendReplyToReceive
activiteit en stel deze eigenschap in Text op 'Service: Antwoord verzonden'.Sleep een WriteLine activiteit onder aan de werkstroom en stel de eigenschap in Text op 'Service: Werkstroom eindigt, druk op Enter om af te sluiten'.
De voltooide servicewerkstroom moet er als volgt uitzien:
De werkstroomclient implementeren
Voeg een nieuwe WCF-werkstroomtoepassing toe, aangeroepen
WorkflowClient
aan hetCommon
project. Als u dit wilt doen, klikt u met de rechtermuisknop op hetCommon
project, selecteert u Toevoegen, Nieuw item ..., selecteert u Werkstroom onder Geïnstalleerde sjablonen en selecteert u Activiteit.Sleep een Sequence activiteit naar het ontwerpoppervlak en zet deze neer.
Sleep een WriteLine activiteit binnen de Sequence activiteit en zet deze neer en stel de eigenschap in Text op
"Client: Workflow starting"
. De werkstroom moet er nu als volgt uitzien:Sleep een TransactionScope activiteit en zet deze neer na de WriteLine activiteit. Selecteer de TransactionScope activiteit, klik op de knop Variabelen en voeg de volgende variabelen toe.
Sleep een Sequence activiteit naar de hoofdtekst van de activiteit en zet deze TransactionScope neer.
Een activiteit slepen en neerzetten
PrintTransactionInfo
binnen de SequenceSleep een WriteLine activiteit na de activiteit en stel Text de
PrintTransactionInfo
eigenschap ervan in op 'Client: Begin verzenden'. De werkstroom moet er nu als volgt uitzien:Sleep een Send activiteit na de Assign activiteit en stel de volgende eigenschappen in:
Eigenschappen Weergegeven als EndpointConfigurationName workflowServiceEndpoint OperationName StartSample ServiceContractName ITransactionSample De werkstroom moet er nu als volgt uitzien:
Klik op de koppeling Definiëren... en voer de volgende instellingen in:
Klik met de rechtermuisknop op de Send activiteit en selecteer ReceiveReply maken. De ReceiveReply activiteit wordt automatisch na de Send activiteit geplaatst.
Klik op definiëren... link op de ReceiveReplyForSend-activiteit en maak de volgende instellingen:
Sleep een WriteLine activiteit tussen de activiteiten en ReceiveReply stel de SendText eigenschap in op 'Client: Send complete'.
Sleep een WriteLine activiteit na de activiteit en stel de ReceiveReply eigenschap ervan in Text op 'Clientzijde: Beantwoorden ontvangen = ' + replyMessage
Sleep een
PrintTransactionInfo
activiteit en zet deze neer na de WriteLine activiteit.Sleep een WriteLine activiteit aan het einde van de werkstroom en zet Text deze neer op 'Client workflow ends'. De voltooide clientwerkstroom moet eruitzien als in het volgende diagram.
Bouw de oplossing.
De servicetoepassing maken
Voeg een nieuw consoletoepassingsproject toe dat aan de oplossing wordt aangeroepen
Service
. Voeg verwijzingen toe aan de volgende assembly's:System.Activities.dll
System.ServiceModel.dll
System.ServiceModel.Activities.dll
Open het gegenereerde Program.cs-bestand en de volgende code:
static void Main() { Console.WriteLine("Building the server."); using (WorkflowServiceHost host = new WorkflowServiceHost(new DeclarativeServiceWorkflow(), new Uri("net.tcp://localhost:8000/TransactedReceiveService/Declarative"))) { //Start the server host.Open(); Console.WriteLine("Service started."); Console.WriteLine(); Console.ReadLine(); //Shutdown host.Close(); }; }
Voeg het volgende bestand app.config toe aan het project.
<?xml version="1.0" encoding="utf-8" ?> <!-- Copyright © Microsoft Corporation. All rights reserved. --> <configuration> <system.serviceModel> <bindings> <netTcpBinding> <binding transactionFlow="true" /> </netTcpBinding> </bindings> </system.serviceModel> </configuration>
De clienttoepassing maken
Voeg een nieuw consoletoepassingsproject toe dat aan de oplossing wordt aangeroepen
Client
. Voeg een verwijzing toe naar System.Activities.dll.Open het program.cs-bestand en voeg de volgende code toe.
class Program { private static AutoResetEvent syncEvent = new AutoResetEvent(false); static void Main(string[] args) { //Build client Console.WriteLine("Building the client."); WorkflowApplication client = new WorkflowApplication(new DeclarativeClientWorkflow()); client.Completed = Program.Completed; client.Aborted = Program.Aborted; client.OnUnhandledException = Program.OnUnhandledException; //Wait for service to start Console.WriteLine("Press ENTER once service is started."); Console.ReadLine(); //Start the client Console.WriteLine("Starting the client."); client.Run(); syncEvent.WaitOne(); //Sample complete Console.WriteLine(); Console.WriteLine("Client complete. Press ENTER to exit."); Console.ReadLine(); } private static void Completed(WorkflowApplicationCompletedEventArgs e) { Program.syncEvent.Set(); } private static void Aborted(WorkflowApplicationAbortedEventArgs e) { Console.WriteLine("Client Aborted: {0}", e.Reason); Program.syncEvent.Set(); } private static UnhandledExceptionAction OnUnhandledException(WorkflowApplicationUnhandledExceptionEventArgs e) { Console.WriteLine("Client had an unhandled exception: {0}", e.UnhandledException); return UnhandledExceptionAction.Cancel; } }