Transaktionsfluss in Workflowdienste und aus Workflowdiensten

Workflowdienste und Clients können an Transaktionen teilnehmen. Damit ein Dienstvorgang Teil einer Ambient-Transaktion wird, fügen Sie eine Receive-Aktivität in eine TransactedReceiveScope-Aktivität ein. Alle Aufrufe, die von einer Send-Aktivität oder einer SendReply-Aktivität in TransactedReceiveScope durchgeführt werden, werden auch in der Ambient-Transaktion durchgeführt. Eine Workflowclientanwendung kann mit der TransactionScope-Aktivität eine Ambient-Transaktion erstellen und Dienstvorgänge mithilfe der Ambient-Transaktion aufrufen. In diesem Thema wird die Erstellung eines Workflowdiensts und Workflowclients, die an Transaktionen teilnehmen, erläutert.

Warnung

Wenn eine Workflowdienstinstanz innerhalb einer Transaktion geladen wird und der Workflow eine Persist-Aktivität enthält, wird die Workflowinstanz blockiert, bis die Transaktion ein Timeout hat.

Wichtig

Es wird empfohlen, bei Verwendung von TransactedReceiveScope alle empfangenen Nachrichten im Workflow in TransactedReceiveScope-Aktivitäten zu platzieren.

Wichtig

Wenn Sie TransactedReceiveScope verwenden und Nachrichten in der falschen Reihenfolge eintreffen, wird beim Versuch, die erste der Nachrichten außerhalb der normalen Reihenfolge zu übermitteln, der Workflow abgebrochen. Sie müssen sicherstellen, dass der Workflow im Leerlauf stets einen konsistenten Haltepunkt aufweist. Falls der Workflow abgebrochen wird, können Sie ihn auf diese Weise anhand eines früheren Persistenzpunkts erneut starten.

Erstellen einer freigegebenen Bibliothek

  1. Erstellen Sie eine neue leere Visual Studio-Projektmappe.

  2. Fügen Sie ein neues Klassenbibliotheksprojekt mit dem Namen Common hinzu. Fügen Sie Verweise auf die folgenden Assemblys hinzu:

    • System.Activities.dll

    • System.ServiceModel.dll

    • System.ServiceModel.Activities.dll

    • System.Transactions.dll

  3. Fügen Sie dem PrintTransactionInfo-Projekt eine neue Klasse mit dem Namen Common hinzu. Diese Klasse wird von NativeActivity abgeleitet und überlädt die 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);  
                }  
            }  
        }  
    
    }  
    

    Diese native Aktivität, in der Informationen zur Ambient-Transaktion angezeigt werden, wird in den in diesem Thema verwendeten Dienst- und Clientworkflows eingesetzt. Erstellen Sie die Projektmappe, um diese Aktivität im Abschnitt Allgemein der Toolbox verfügbar zu machen.

Implementieren des Workflowdiensts

  1. Fügen Sie einen neuen WCF-Workflowdienst mit dem Namen WorkflowService zum Common-Projekt hinzu. Klicken Sie hierzu mit der rechten Maustaste auf das Common-Projekt, und wählen Sie Hinzufügen und Neues Element... aus. Klicken Sie dann unter Installierte Vorlagen auf Workflow, und wählen Sie den WCF-Workflowdienst.

    Adding a Workflow Service

  2. Löschen Sie die ReceiveRequest-Standardaktivität und SendResponse-Standardaktivität.

  3. Ziehen Sie eine WriteLine-Aktivität in die Sequential Service-Aktivität. Legen Sie die Texteigenschaft auf "Workflow Service starting ..." fest, wie im folgenden Beispiel gezeigt.

    ![Hinzufügen einer WriteLine-Aktivität zur Aktivität Sequential Service(./media/flowing-transactions-into-and-out-of-workflow-services/add-writeline-sequential-service.jpg)

  4. Verschieben Sie eine TransactedReceiveScope-Aktivität per Drag & Drop an die Stelle nach der WriteLine-Aktivität. Die TransactedReceiveScope-Aktivität befindet sich im Abschnitt Messaging der Toolbox. Die TransactedReceiveScope-Aktivität besteht aus zwei Abschnitten: Anforderung und Text. Der Abschnitt Anforderung enthält die Receive-Aktivität. Der Abschnitt Text enthält die Aktivitäten, die in einer Transaktion ausgeführt werden, nachdem eine Nachricht empfangen wurde.

    Adding a TransactedReceiveScope activity

  5. Wählen Sie die TransactedReceiveScope-Aktivität aus, und klicken Sie auf die Schaltfläche Variablen. Fügen Sie die folgenden Variablen hinzu:

    Adding variables to the TransactedReceiveScope

    Hinweis

    Sie können die standardmäßig vorhandene Datenvariable löschen. Sie können auch die vorhandene Handlevariable verwenden.

  6. Verschieben Sie eine Receive-Aktivität per Drag & Drop im Abschnitt Anforderung der TransactedReceiveScope-Aktivität. Legen Sie die folgenden Eigenschaften fest:

    Eigenschaften Wert
    CanCreateInstance Wahr (aktivieren Sie das Kontrollkästchen)
    Vorgangsname StartSample
    ServiceContractName ITransactionSample

    Der Workflow müsste wie folgt aussehen:

    Adding a Receive activity

  7. Klicken Sie in der Receive-Aktivität auf den Link Definieren... und nehmen Sie die folgenden Einstellungen vor:

    Setting message settings for the Receive activity

  8. Ziehen Sie eine Sequence-Aktivität per Drag & Drop in den Textabschnitt vom TransactedReceiveScope. Verschieben Sie innerhalb der Sequence-Aktivität zwei WriteLine-Aktivitäten per Drag & Drop, und legen Sie die Text-Eigenschaften wie in der folgenden Tabelle gezeigt fest.

    Aktivität Wert
    1. WriteLine “Service: Receive Completed”
    2. WriteLine "Service: Received = " + requestMessage

    Der Workflow müsste jetzt wie folgt aussehen:

    Sequence after adding WriteLine activities

  9. Ziehen Sie die PrintTransactionInfo-Aktivität per Drag & Drop an die Stelle nach der zweiten WriteLine-Aktivität im Text in der TransactedReceiveScope-Aktivität.

    Sequence after adding PrintTransactionInfo

  10. Ziehen Sie eine Assign-Aktivität per Drag & Drop an die Stelle nach der PrintTransactionInfo-Aktivität, und legen Sie die Eigenschaften entsprechend der folgenden Tabelle fest.

    Eigenschaft Wert
    Beschreibung replyMessage
    Wert "Service: Sending reply."
  11. Ziehen Sie eine WriteLine-Aktivität per Drag & Drop an die Stelle nach der Assign-Aktivität, und legen Sie die Text-Eigenschaft auf „Service: Begin reply“ fest.

    Der Workflow müsste jetzt wie folgt aussehen:

    After adding Assign and WriteLine

  12. Klicken Sie mit der rechten Maustaste auf die Receive-Aktivität, wählen Sie SendReply erstellen aus, und fügen Sie die Option nach der letzten WriteLine-Aktivität ein. Klicken Sie in der SendReplyToReceive-Aktivität auf den Link Definieren... und nehmen Sie die folgenden Einstellungen vor.

    Reply message settings

  13. Ziehen Sie eine WriteLine-Aktivität per Drag & Drop an die Stelle nach der SendReplyToReceive-Aktivität, und legen Sie die Text-Eigenschaft auf „Service: Reply sent“ fest.

  14. Verschieben Sie eine WriteLine-Aktivität per Drag & Drop an das Ende des Workflows, und legen Sie die Eigenschaft Text auf "Service: Workflow ends, press ENTER to exit" fest.

    Der abgeschlossene Dienstworkflow müsste wie folgt aussehen:

    Complete Service Workflow

Implementieren des Workflowclients

  1. Fügen Sie eine neue WCF-Workflowanwendung mit dem Namen WorkflowClient zum Common-Projekt hinzu. Klicken Sie hierzu mit der rechten Maustaste auf das Common-Projekt, und wählen Sie Hinzufügen und Neues Element ... aus. Klicken Sie dann unter Installierte Vorlagen auf Workflow, und wählen Sie Aktivität.

    Add an Activity project

  2. Ziehen Sie eine Sequence-Aktivität per Drag & Drop auf die Entwurfsoberfläche.

  3. Verschieben Sie in der Sequence-Aktivität eine WriteLine-Aktivität per Drag & Drop, und legen Sie die Text-Eigenschaft auf "Client: Workflow starting" fest. Der Workflow müsste jetzt wie folgt aussehen:

    Add a WriteLine activity

  4. Verschieben Sie eine TransactionScope-Aktivität per Drag & Drop an die Stelle nach der WriteLine-Aktivität. Wählen Sie die TransactionScope-Aktivität aus, klicken Sie auf die Schaltfläche Variablen, und fügen Sie die folgenden Variablen hinzu.

    Add variables to the TransactionScope

  5. Ziehen Sie eine Sequence-Aktivität per Drag & Drop in den Text der TransactionScope-Aktivität.

  6. Verschieben Sie eine PrintTransactionInfo-Aktivität per Drag & Drop innerhalb der Sequence-Aktivität.

  7. Ziehen Sie eine WriteLine-Aktivität per Drag & Drop an die Stelle nach der PrintTransactionInfo-Aktivität, und legen Sie die Text-Eigenschaft auf „Client: Beginning Send“ fest. Der Workflow müsste jetzt wie folgt aussehen:

    Adding Client: Beginning Send activities

  8. Ziehen Sie eine Send-Aktivität per Drag & Drop an die Stelle nach der Assign-Aktivität, und legen Sie die folgenden Eigenschaften fest:

    Eigenschaft Wert
    EndpointConfigurationName workflowServiceEndpoint
    Vorgangsname StartSample
    ServiceContractName ITransactionSample

    Der Workflow müsste jetzt wie folgt aussehen:

    Setting the Send activity properties

  9. Klicken Sie auf den Link Definieren..., und legen Sie die folgenden Einstellungen fest:

    Send activity message settings

  10. Klicken Sie mit der rechten Maustaste auf die Send-Aktivität, und wählen Sie ReceiveReply erstellen aus. Die ReceiveReply-Aktivität wird automatisch nach der Send-Aktivität platziert.

  11. Klicken Sie in der ReceiveReplyForSend-Aktivität auf den Link Definieren..., und legen Sie die folgenden Einstellungen fest:

    Setting the ReceiveForSend message settings

  12. Verschieben Sie eine WriteLine-Aktivität per Drag & Drop zwischen der Send-Aktivität und der ReceiveReply-Aktivität, und legen Sie die Text-Eigenschaft auf "Client: Send complete" fest.

  13. Ziehen Sie eine WriteLine-Aktivität per Drag & Drop an die Stelle nach der ReceiveReply-Aktivität, und legen Sie die Text-Eigenschaft auf "Client side: Reply received = " + replyMessage fest.

  14. Verschieben Sie eine PrintTransactionInfo-Aktivität per Drag & Drop an die Stelle nach der WriteLine-Aktivität.

  15. Ziehen Sie eine WriteLine-Aktivität am Ende des Workflows, und legen Sie ihre Text-Eigenschaft auf "Clientworkflow endet" fest. Der abgeschlossene Clientworkflow sollte wie im folgenden Diagramm aussehen.

    The completed client workflow

  16. Erstellen Sie die Projektmappe.

Erstellen der Dienstanwendung

  1. Fügen Sie der Projektmappe ein neues Konsolenanwendungsprojekt mit dem Namen Service hinzu. Fügen Sie Verweise auf die folgenden Assemblys hinzu:

    1. System.Activities.dll

    2. System.ServiceModel.dll

    3. System.ServiceModel.Activities.dll

  2. Öffnen Sie die generierte Datei Program.cs und den folgenden 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();  
              };
          }  
    
  3. Fügen Sie dem Projekt die folgende app.config-Datei hinzu.

    <?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>  
    

Erstellen der Clientanwendung

  1. Fügen Sie der Projektmappe ein neues Konsolenanwendungsprojekt mit dem Namen Client hinzu. Fügen Sie einen Verweis auf System.Activities.dll hinzu.

  2. Öffnen Sie die Datei program.cs, und fügen Sie den folgenden Code hinzu.

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

Siehe auch