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, bleibt die Workflowinstanz bis zum Timeout der Transaktion hängen.

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.Dies ermöglicht es Ihnen, einen abgebrochenen Workflow von einem vorherigen Persistenzpunkt neu zu 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 den folgenden Assemblys Verweise hinzu:

    • System.Activities.dll

    • System.ServiceModel.dll

    • System.ServiceModel.Activities.dll

    • System.Transactions.dll

  3. Fügen Sie dem Common-Projekt eine neue Klasse mit dem Namen PrintTransactionInfo 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 systemeigene 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.

    Hinzufügen eines Workflowdiensts

  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

  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.

    Hinzufügen einer TransactedReceiveScope-Aktivität

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

    Hinzufügen von Variablen zu 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:

    Eigenschaft Wert
    CanCreateInstance Wahr (aktivieren Sie das Kontrollkästchen)
    OperationName StartSample
    ServiceContractName ITransactionSample

    Der Workflow müsste wie folgt aussehen:

    Hinzufügen einer Receive-Aktivität

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

    Festlegen von Meldungseinstellungen für die Receive-Aktivität

  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 Value
    1. WriteLine “Service: Receive Completed”
    2. WriteLine "Service: Received = " + requestMessage

    Der Workflow müsste jetzt wie folgt aussehen:

    Hinzufügen von WriteLine-Aktivitäten

  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.

    Nach dem Hinzufügen von 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
    An 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:

    Nach dem Hinzufügen von Assign und 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 legen Sie die folgenden Einstellungen fest.

    Einstellungen der Antwortmeldung

  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:

    Vollständiger Serviceworkflow

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.

    Aktivitätsprojekt hinzufügen

  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:

    Eine WriteLine-Aktivität hinzufügen

  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.

    Variablen zu TransactionScope hinzufügen

  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:

    Hinzufügen von Aktivitäten

  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
    OperationName StartSample
    ServiceContractName ITransactionSample

    Der Workflow müsste jetzt wie folgt aussehen:

    Festlegen der Send-Aktivitätseigenschaften

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

    Meldungseinstellungen für die Send-Aktivität

  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 auf den Link Definieren…in der ReceiveReplyForSend-Aktivität, und legen Sie die folgenden Einstellungen fest:

    Festlegen der ReceiveForSend-Meldungseinstellungen

  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. Verschieben Sie eine WriteLine-Aktivität per Drag & Drop an das Ende des Workflows, und legen Sie die Text-Eigenschaft auf "Client workflow ends" fest. Der abgeschlossene Clientworkflow sollte wie das folgende Diagramm aussehen.

    Der abgeschlossene Clientworkflow

  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 den folgenden Assemblys Verweise 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

Workflowdienste
Übersicht über Windows Communication Foundation-Transaktionen
Verwendung von TransactedReceiveScope