Partager via


Flux de transactions vers et depuis des services de workflow

Les services et clients de workflow peuvent participer aux transactions. Pour qu'une opération de service fasse partie d'une transaction ambiante, placez une activité Receive dans une activité TransactedReceiveScope. Tous les appels effectués par une activité Send ou SendReply au sein de l’activité TransactedReceiveScope seront également effectués dans la transaction ambiante. Une application cliente de workflow peut créer une transaction ambiante en utilisant l’activité TransactionScope et appeler des opérations de service à l’aide de la transaction ambiante. Cette rubrique vous guide dans la création d’un service de workflow et d’un client de workflow qui participent à des transactions.

Avertissement

Si une instance de service de workflow est chargée dans une transaction et que le workflow contient une activité Persist, l’instance de workflow est bloquée le temps que la transaction expire.

Important

Lorsque vous utilisez une activité TransactedReceiveScope, il est recommandé de placer toutes les réceptions dans le workflow dans les activités TransactedReceiveScope.

Important

Lorsque vous utilisez TransactedReceiveScope et les messages arrivent dans le mauvais ordre incorrect, le workflow est abandonné lorsque vous tentez de livrer le premier message dans le désordre. Vous devez vous assurer que votre workflow est toujours à un point d'arrêt cohérent lorsqu'il est inactif. Cela vous permet de redémarrer le workflow à partir d'un point de persistance précédent s'il est abandonné.

Créer une bibliothèque partagée

  1. Créez une solution Visual Studio vide.

  2. Ajoutez un nouveau projet de bibliothèque de classes nommé Common. Ajoutez des références aux assemblys suivants :

    • System.Activities.dll

    • System.ServiceModel.dll

    • System.ServiceModel.Activities.dll

    • System.Transactions.dll

  3. Ajoutez une nouvelle classe nommée PrintTransactionInfo au projet Common. Cette classe est dérivée de NativeActivity et surcharge la méthode Execute.

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

    Il s’agit d’une activité native qui affiche des informations sur la transaction ambiante et est utilisée dans les workflows du service et du client utilisés dans cette rubrique. Générez la solution pour rendre cette activité disponible dans la section Commun de la boîte à outils.

Implémenter le service de workflow

  1. Ajoutez un nouveau service de workflow WCF, nommé WorkflowService, au projet Common. Pour ce faire, cliquez avec le bouton droit sur le projet Common, sélectionnez Ajouter, Nouvel élément..., puis Workflow sous Modèles installés et enfin Service de workflow WCF.

    Adding a Workflow Service

  2. Supprimez les activités par défaut ReceiveRequest et SendResponse.

  3. Faites glisser et déposez une activité WriteLine dans l’activité Sequential Service. Affectez à la propriété Text la valeur "Workflow Service starting ...", comme le montre l'exemple suivant.

    ![Ajout d’une activité WriteLine à l’activité de service séquentiel(./media/flowing-transactions-into-and-out-of-workflow-services/add-writeline-séquentiel-service.jpg)

  4. Faites glisser et déposez une activité TransactedReceiveScope après l’activité WriteLine. L’activité TransactedReceiveScope se trouve dans la section Messagerie de la Boîte à outils. L’activité TransactedReceiveScope est composée de deux sections : Requête et Corps. La section Requête contient l’activité Receive. La section Corps contient les activités à exécuter dans une transaction après réception d’un message.

    Adding a TransactedReceiveScope activity

  5. Sélectionnez l’activité TransactedReceiveScope et cliquez sur le bouton Variables. Ajoutez les variables suivantes.

    Adding variables to the TransactedReceiveScope

    Remarque

    Vous pouvez supprimer la variable de données proposée à cet endroit par défaut. Vous pouvez également utiliser la variable de handle existante.

  6. Faites glisser et déposez une activité Receive dans la section Requête de l’activité TransactedReceiveScope. Définissez les propriétés suivantes :

    Property Valeur
    CanCreateInstance True (activez la case à cocher)
    NomOpération StartSample
    ServiceContractName ITransactionSample

    Le workflow doit ressembler à ceci :

    Adding a Receive activity

  7. Cliquez sur le lien Définir... de l’activité Receive et effectuez les paramétrages suivants :

    Setting message settings for the Receive activity

  8. Faites glisser et déposez une activité Sequence dans la section de corps du TransactedReceiveScope. Dans l’activité Sequence, faites glisser et déposez deux activités WriteLine et définissez les propriétés Text conformément aux indications du tableau suivant.

    Activité Valeur
    1re WriteLine "Service: Receive Completed"
    2e WriteLine "Service: Received = " + requestMessage

    Le workflow doit maintenant ressembler à ceci :

    Sequence after adding WriteLine activities

  9. Faites glisser et déposez l’activité PrintTransactionInfo après la deuxième activité WriteLine du Corps de l’activité TransactedReceiveScope.

    Sequence after adding PrintTransactionInfo

  10. Faites glisser et déposez une activité Assign après l’activité PrintTransactionInfo et définissez ses propriétés conformément aux indications du tableau suivant.

    Propriété Valeur
    À replyMessage
    Valeur "Service: Sending reply."
  11. Glissez et déposez une activité WriteLine après l’activité Assign et affectez à sa propriété Text la valeur "Service: Begin reply."

    Le workflow doit maintenant ressembler à ceci :

    After adding Assign and WriteLine

  12. Cliquez avec le bouton droit sur l’activité Receive, sélectionnez et collez Create SendReply après la dernière activité WriteLine. Cliquez sur le lien Définir... de l’activité SendReplyToReceive et effectuez les paramétrages suivants.

    Reply message settings

  13. Faites glisser et déposez une activité WriteLine après l’activité SendReplyToReceive et affectez à sa propriété Text la valeur « Service: Reply sent ».

  14. Faites glisser une activité WriteLine en bas du workflow et affectez à sa propriété Text la valeur "Service: Workflow ends, press ENTER to exit."

    Le workflow de service terminé doit ressembler à ceci :

    Complete Service Workflow

Implémenter le client de workflow

  1. Ajoutez une nouvelle application de workflow WCF nommée WorkflowClient au projet Common. Pour ce faire, cliquez avec le bouton droit sur le projet Common, sélectionnez Ajouter, Nouvel élément..., puis Workflow sous Modèles installés et enfin Activité.

    Add an Activity project

  2. Faites glisser et déposez une activité Sequence sur l’aire de conception.

  3. Dans l’activité Sequence, faites glisser et déposez une activité WriteLine et affectez à sa propriété Text la valeur "Client: Workflow starting". Le workflow doit maintenant ressembler à ceci :

    Add a WriteLine activity

  4. Faites glisser une activité TransactionScope après l'activité WriteLine. Sélectionnez l'activité TransactionScope, cliquez sur le bouton Variables et ajoutez les variables suivantes.

    Add variables to the TransactionScope

  5. Faites glisser et déposez une activité Sequence dans le corps de l’activité TransactionScope.

  6. Faites glisser une activité PrintTransactionInfo dans Sequence.

  7. Faites glisser et déposez une activité WriteLine après l’activité PrintTransactionInfo et affectez à sa propriété Text la valeur "Client: Beginning Send". Le workflow doit maintenant ressembler à ceci :

    Adding Client: Beginning Send activities

  8. Faites glisser une activité Send après l'activité Assign et définissez les propriétés suivantes :

    Propriété Valeur
    EndpointConfigurationName workflowServiceEndpoint
    NomOpération StartSample
    ServiceContractName ITransactionSample

    Le workflow doit maintenant ressembler à ceci :

    Setting the Send activity properties

  9. Cliquez sur le lien Définir... et effectuez les paramétrages suivants :

    Send activity message settings

  10. Cliquez avec le bouton droit sur l’activité Send et sélectionnez Create ReceiveReply. L'activité ReceiveReply sera automatiquement placée après l'activité Send.

  11. Cliquez sur le lien Définir de l'activité ReceiveReplyForSend et effectuez les paramétrages suivants :

    Setting the ReceiveForSend message settings

  12. Faites glisser une activité WriteLine entre les activités Send et ReceiveReply et affectez à sa propriété Text la valeur "Client: Send complete."

  13. Faites glisser et déposez une activité WriteLine après l’activité ReceiveReply et affectez à sa propriété Text la valeur "Client side: Reply received = " + replyMessage

  14. Faites glisser une activité PrintTransactionInfo après l'activité WriteLine.

  15. Faites glisser et déposez une activité WriteLine à la fin du workflow et affectez à sa propriété Text la valeur "Client workflow ends". Le workflow du client terminé doit ressembler au diagramme suivant.

    The completed client workflow

  16. Générez la solution.

Créer l'application Service

  1. Ajoutez à la solution un nouveau projet d'application console nommé Service. Ajoutez des références aux assemblys suivants :

    1. System.Activities.dll

    2. System.ServiceModel.dll

    3. System.ServiceModel.Activities.dll

  2. Ouvrez le fichier Program.cs généré et le code suivant :

          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. Ajoutez le fichier app.config suivant au projet.

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

Créer l’application cliente

  1. Ajoutez à la solution un nouveau projet d'application console nommé Client. Ajoutez une référence à System.Activities.dll.

  2. Ouvrez le fichier program.cs et ajoutez le code suivant.

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

Voir aussi