Tok transakcí do služeb pracovních postupů a mimo ně
Služby pracovních postupů a klienti se mohou účastnit transakcí. Aby se operace služby stala součástí okolí transakce, umístěte Receive aktivitu v rámci TransactedReceiveScope aktivity. Všechna volání provedená určitou aktivitou Send nebo aktivitou SendReply v rámci TransactedReceiveScope transakce bude provedena také v okolí transakce. Klientská aplikace pracovního postupu může vytvořit okolí transakce pomocí TransactionScope aktivity a volání operací služby pomocí okolí transakce. Toto téma vás provede vytvořením služby pracovního postupu a klienta pracovního postupu, který se účastní transakcí.
Upozorňující
Pokud je instance služby pracovního postupu načtena v rámci transakce a pracovní postup obsahuje Persist aktivitu, instance pracovního postupu bude blokovat, dokud transakce nevysadí časový limit.
Důležité
Pokaždé, když použijete příkaz TransactedReceiveScope , který se doporučuje umístit do pracovního postupu všechny příjemce v rámci TransactedReceiveScope aktivit.
Důležité
Při použití TransactedReceiveScope a doručení zpráv v nesprávném pořadí se pracovní postup při pokusu o doručení první zprávy mimo objednávku přeruší. Musíte se ujistit, že pracovní postup je vždy v konzistentním zastavování, když idles pracovního postupu. To vám umožní restartovat pracovní postup z předchozího bodu trvalosti v případě přerušení pracovního postupu.
Vytvoření sdílené knihovny
Vytvořte nové prázdné řešení sady Visual Studio.
Přidejte nový projekt knihovny tříd s názvem
Common
. Přidejte odkazy na následující sestavení:System.Activities.dll
System.ServiceModel.dll
System.ServiceModel.Activities.dll
System.Transactions.dll
Přidejte do projektu novou třídu volanou
PrintTransactionInfo
Common
. Tato třída je odvozena z NativeActivity a přetížení Execute metody.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); } } } }
Jedná se o nativní aktivitu, která zobrazuje informace o okolí transakce a používá se jak ve službě, tak v klientských pracovních postupech používaných v tomto tématu. Sestavte řešení, aby byla tato aktivita dostupná v části Společné v sadě nástrojů.
Implementace služby pracovního postupu
Přidejte do projektu novou službu pracovního postupu WCF, která je
Common
volánaWorkflowService
. Chcete-li to provést, klikněte pravým tlačítkem naCommon
projekt, vyberte Přidat, Nová položka ..., Vyberte pracovní postup v části Nainstalované šablony a vyberte Služba pracovního postupu WCF.Odstraňte výchozí
ReceiveRequest
hodnoty aSendResponse
aktivity.WriteLine Přetáhněte aktivitu do
Sequential Service
aktivity. Nastavte text vlastnost tak"Workflow Service starting ..."
, jak je znázorněno v následujícím příkladu.! [Přidání aktivity WriteLine do aktivity sekvenční služby(./media/flowing-transactions-into-and-out-of-workflow-services/add-writeline-sequential-service.jpg)
Přetáhněte akci za aktivitou TransactedReceiveScopeWriteLine . TransactedReceiveScope Aktivitu najdete v části Zasílání zpráv v sadě nástrojů. Aktivita TransactedReceiveScope se skládá ze dvou částí Požadavek a Text. Část Požadavek obsahuje Receive aktivitu. Část Body obsahuje aktivity, které se mají provést v rámci transakce po přijetí zprávy.
TransactedReceiveScope Vyberte aktivitu a klikněte na tlačítko Proměnné. Přidejte následující proměnné.
Poznámka:
Datová proměnná, která je tam ve výchozím nastavení, můžete odstranit. Můžete také použít existující proměnnou popisovače.
Receive Přetáhněte aktivitu v části TransactedReceiveScope Požadavek aktivity. Nastavte následující vlastnosti:
Vlastnost Hodnota Cancreateinstance True (zaškrtněte políčko) OperationName StartSample ServiceContractName ITransactionSample Pracovní postup by měl vypadat takto:
Klikněte na odkaz Definovat... v aktivitě Receive a proveďte následující nastavení:
Sequence Přetáhněte aktivitu do části Tělo objektu TransactedReceiveScope. Sequence V rámci aktivity přetáhněte dvě WriteLine aktivity a nastavte Text vlastnosti, jak je znázorněno v následující tabulce.
Aktivita Hodnota 1. WriteLine "Služba: Příjem dokončeno" 2. WriteLine "Služba: Received = " + requestMessage Pracovní postup by teď měl vypadat takto:
PrintTransactionInfo
Přetáhněte aktivitu za druhou WriteLine aktivitu v textuTransactedReceiveScope aktivity.Assign Přetáhněte aktivitu za
PrintTransactionInfo
aktivitu a nastavte její vlastnosti podle následující tabulky.Vlastnost Hodnota Do replyMessage Hodnota "Služba: Odesílání odpovědí." Přetáhněte aktivitu za aktivitou WriteLineAssign a nastavte její Text vlastnost na "Služba: Zahájit odpověď".
Pracovní postup by teď měl vypadat takto:
Klikněte pravým tlačítkem myši na Receive aktivitu a vyberte Vytvořit SendReply a vložte ji za poslední WriteLine aktivitu. Klikněte na odkaz Definovat... v aktivitě
SendReplyToReceive
a proveďte následující nastavení.Přetáhněte aktivitu za aktivitou WriteLine
SendReplyToReceive
a nastavte její Text vlastnost na "Service: Reply sent" (Služba: Odpověď odeslána).WriteLine Přetáhněte aktivitu v dolní části pracovního postupu a nastavte její Text vlastnost na "Service: Workflow end, press ENTER to exit" (Služba: Pracovní postup končí).
Dokončený pracovní postup služby by měl vypadat takto:
Implementace klienta pracovního postupu
Přidejte do projektu novou aplikaci pracovního postupu WCF, která je
Common
volánaWorkflowClient
. Chcete-li to provést, klikněte pravým tlačítkem myši naCommon
projekt, vyberte Přidat, Nová položka ..., Vyberte pracovní postup v části Nainstalované šablony a vyberte Aktivita.Sequence Přetáhněte aktivitu na návrhovou plochu.
Sequence V rámci aktivity přetáhněte WriteLine aktivitu a nastavte její Text vlastnost na
"Client: Workflow starting"
. Pracovní postup by teď měl vypadat takto:TransactionScope Přetáhněte aktivitu za aktivitouWriteLine. TransactionScope Vyberte aktivitu, klikněte na tlačítko Proměnné a přidejte následující proměnné.
Sequence Přetáhněte aktivitu do těla TransactionScope aktivity.
PrintTransactionInfo
Přetažení aktivity v rámciSequencePřetáhněte aktivitu za aktivitou WriteLine
PrintTransactionInfo
a nastavte její Text vlastnost na "Client: Beginning Send". Pracovní postup by teď měl vypadat takto:Přetáhněte aktivitu za aktivitou SendAssign a nastavte následující vlastnosti:
Vlastnost Hodnota EndpointConfigurationName workflowServiceEndpoint OperationName StartSample ServiceContractName ITransactionSample Pracovní postup by teď měl vypadat takto:
Klikněte na odkaz Definovat... a proveďte následující nastavení:
Klikněte pravým tlačítkem myši na Send aktivitu a vyberte Vytvořit receiveReply. Aktivita ReceiveReply se automaticky umístí po aktivitě Send .
Klikněte na definovat... odkaz na ReceiveReplyForSend aktivity a proveďte následující nastavení:
WriteLine Přetáhněte aktivitu mezi Send aktivitami a ReceiveReply aktivitami a nastavte její Text vlastnost na "Client: Send complete" (Klient: Odeslat dokončeno).
Přetáhněte aktivitu za aktivitou WriteLineReceiveReply a nastavte její Text vlastnost na "Client side: Reply received = " + replyMessage
PrintTransactionInfo
Přetáhněte aktivitu za aktivitouWriteLine.WriteLine Přetáhněte aktivitu na konec pracovního postupu a nastavte jeho Text vlastnost na "Klient pracovní postup končí". Dokončený pracovní postup klienta by měl vypadat jako v následujícím diagramu.
Sestavte řešení.
Vytvoření aplikace služby
Přidejte do řešení nový projekt konzolové aplikace volaný
Service
. Přidejte odkazy na následující sestavení:System.Activities.dll
System.ServiceModel.dll
System.ServiceModel.Activities.dll
Otevřete vygenerovaný soubor Program.cs a následující kód:
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(); }; }
Do projektu přidejte následující soubor app.config.
<?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>
Vytvoření klientské aplikace
Přidejte do řešení nový projekt konzolové aplikace volaný
Client
. Přidejte odkaz na System.Activities.dll.Otevřete soubor program.cs a přidejte následující kód.
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; } }