Flujo de las transacciones en los servicios de flujo de trabajo

Los servicios y clientes de flujo de trabajo pueden participar en las transacciones. Para que una operación de servicio se convierta en parte de una transacción de ambiente, coloque una actividad de Receive dentro de una actividad de TransactedReceiveScope. En cualquier llamada realizada por un objeto Send o una actividad de SendReply dentro de TransactedReceiveScope también se realizará dentro de la transacción de ambiente. Una aplicación cliente del flujo de trabajo puede crear una transacción de ambiente utilizando la actividad de TransactionScope y operaciones de servicio de llamada que usen la transacción de ambiente. Este tema sirve de guía para crear un servicio de flujo de trabajo y un cliente de flujo de trabajo que participan en transacciones.

Advertencia

Si una instancia del servicio de flujo de trabajo se carga dentro de una transacción y el flujo de trabajo contiene una actividad Persist, la instancia de flujo de trabajo se bloqueará hasta que se agote el tiempo de espera de la transacción.

Importante

Siempre que use un objeto TransactedReceiveScope se recomienda que coloque todas las recepciones en el flujo de trabajo dentro de actividades TransactedReceiveScope.

Importante

Cuando se usa el objeto TransactedReceiveScope y los mensajes llegan en el orden incorrecto, el flujo de trabajo se anulará al intentar entregar el primer mensaje que lo indique. Debe asegurarse de que el flujo de trabajo siempre está en un punto de detención coherente cuando el flujo de trabajo está inactivo. De este modo, podrá reiniciar el flujo de trabajo a partir de un punto de persistencia anterior si el flujo de trabajo se anula.

Crear una biblioteca compartida

  1. Cree una nueva solución de Visual Studio vacía.

  2. Agregue un nuevo proyecto de biblioteca de clases denominado Common. Agregue referencias a los siguientes ensamblados:

    • System.Activities.dll

    • System.ServiceModel.dll

    • System.ServiceModel.Activities.dll

    • System.Transactions.dll

  3. Agregue una nueva clase denominada PrintTransactionInfo al proyecto Common. Esta clase se deriva de NativeActivity y sobrecarga el método 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);  
                }  
            }  
        }  
    
    }  
    

    Esta es una actividad nativa que muestra información acerca de la transacción de ambiente y se utiliza en ambos flujos de trabajo, de cliente y de servicio, que se usan en este tema. Compile la solución para hacer que esta actividad esté disponible en la sección Común del Cuadro de herramientas.

Implementar el servicio de flujo de trabajo

  1. Agregue un nuevo Servicio de flujo de trabajo de WCF, denominado WorkflowService, al proyecto Common. Para ello, haga clic con el botón secundario en el proyecto Common, seleccione Agregar, Nuevo elemento..., seleccione Flujo de trabajo en Plantillas instaladas y luego Servicio de flujo de trabajo de WCF.

    Adding a Workflow Service

  2. Elimine las actividades ReceiveRequest y SendResponse predeterminadas.

  3. Arrastre y coloque una actividad de WriteLine en la actividad de Sequential Service. Establezca la propiedad de texto en "Workflow Service starting ..." como se muestra en el siguiente ejemplo.

    ![Incorporación de una actividad WriteLine a la actividad de servicio secuencial(./media/flow-transactions-into-and-out-of-workflow-services/add-writeline-sequential-service.jpg)

  4. Arrastre y coloque una actividad TransactedReceiveScope después de la actividad de WriteLine. La actividad TransactedReceiveScope se puede encontrar en la sección Mensajería del Cuadro de herramientas. La actividad TransactedReceiveScope está compuesta por dos secciones Solicitud y Cuerpo. La sección Solicitud contiene la actividad Receive. La sección Cuerpo contiene las actividades que se ejecutan dentro de una transacción una vez recibido un mensaje.

    Adding a TransactedReceiveScope activity

  5. Seleccione la actividad TransactedReceiveScope y haga clic en el botón Variables. Agregue las variables siguientes.

    Adding variables to the TransactedReceiveScope

    Nota:

    Puede eliminar la variable de datos que está allí de forma predeterminada. También puede utilizar la variable de controlador existente.

  6. Arrastre y coloque una actividad Receive dentro de la sección Solicitud de la actividad TransactedReceiveScope. Establezca las siguientes propiedades:

    Property Value
    CanCreateInstance True (activar la casilla)
    OperationName StartSample
    ServiceContractName ITransactionSample

    El flujo de trabajo debería ser similar a este:

    Adding a Receive activity

  7. Haga clic en el vínculo Definir... en la actividad Receive y realice la siguiente configuración:

    Setting message settings for the Receive activity

  8. Arrastre y coloque una actividad de Sequence en la sección Cuerpo de TransactedReceiveScope. Dentro de la actividad de Sequence, arrastre las dos actividades de WriteLine y establezca las propiedades Text como se muestra en la siguiente tabla.

    Actividad Valor
    Primera propiedad WriteLine "Servicio: recepción completada"
    Segunda propiedad WriteLine "Servicio: recibido = " + requestMessage

    El flujo de trabajo ahora debería ser similar a este:

    Sequence after adding WriteLine activities

  9. Arrastre y coloque la actividad PrintTransactionInfo después de la segunda actividad WriteLine en la sección Cuerpo de la actividad TransactedReceiveScope.

    Sequence after adding PrintTransactionInfo

  10. Arrastre y coloque una actividad de Assign después de la actividad de PrintTransactionInfo y establezca sus propiedades según la siguiente tabla.

    Propiedad Valor
    En replyMessage
    Valor "Servicio: enviando respuesta."
  11. Arrastre y coloque una actividad de WriteLine después de la actividad de Assign y establezca su propiedad Text en "Servicio: iniciar respuesta".

    El flujo de trabajo ahora debería ser similar a este:

    After adding Assign and WriteLine

  12. Haga clic con el botón secundario en la actividad Receive, seleccione Crear SendReply y péguela después de la última actividad WriteLine. Haga clic en el vínculo Definir... en la actividad SendReplyToReceive y realice la siguiente configuración.

    Reply message settings

  13. Arrastre y coloque una actividad WriteLine después de la actividad SendReplyToReceive y establezca su propiedad Text en "Servicio: respuesta enviada".

  14. Arrastre y coloque una actividad de WriteLine en la parte inferior del flujo de trabajo y establezca su propiedad Text en "Servicio: el flujo de trabajo finaliza, presione Entrar para salir".

    El flujo de trabajo del servicio completado debería ser similar a:

    Complete Service Workflow

Implementar el cliente de flujo de trabajo

  1. Agregue una nueva aplicación Flujo de trabajo WCF, denominada WorkflowClient, al proyecto Common. Para ello, haga clic con el botón secundario en el proyecto Common, seleccione Agregar, Nuevo elemento..., seleccione Flujo de trabajo en Plantillas instaladas y seleccione Actividad.

    Add an Activity project

  2. Arrastre y coloque una actividad Sequence en la superficie de diseño.

  3. Dentro de la actividad Sequence, arrastre y coloque una actividad de WriteLine y establezca su propiedad Text en "Client: Workflow starting". El flujo de trabajo ahora debería ser similar a este:

    Add a WriteLine activity

  4. Arrastre y coloque una actividad de TransactionScope después de la actividad de WriteLine. Seleccione la actividad de TransactionScope, haga clic en el botón Variables y agregue las siguientes variables.

    Add variables to the TransactionScope

  5. Arrastre y coloque una actividad de Sequence en el cuerpo de la actividad de TransactionScope.

  6. Arrastre y coloque una actividad de PrintTransactionInfo dentro de Sequence.

  7. Arrastre y coloque una actividad WriteLine después de la actividad PrintTransactionInfo y establezca su propiedad Text en "Cliente: comenzando envío". El flujo de trabajo ahora debería ser similar a este:

    Adding Client: Beginning Send activities

  8. Arrastre y coloque una actividad de Send después de la actividad de Assign y establezca las siguientes propiedades:

    Propiedad Valor
    EndpointConfigurationName workflowServiceEndpoint
    OperationName StartSample
    ServiceContractName ITransactionSample

    El flujo de trabajo ahora debería ser similar a este:

    Setting the Send activity properties

  9. Haga clic en el vínculo Definir... y realice la siguiente configuración:

    Send activity message settings

  10. Haga clic con el botón secundario en la actividad Send y seleccione Crear ReceiveReply. La actividad de ReceiveReply se colocará automáticamente después de la actividad de Send.

  11. Haga clic en el vínculo Definir... en la actividad ReceiveReplyForSend y realice la siguiente configuración:

    Setting the ReceiveForSend message settings

  12. Arrastre y coloque una actividad de WriteLine entre las actividades de Send y ReceiveReply, y establezca su propiedad Text en "Cliente: envío completado".

  13. Arrastre y coloque una actividad de WriteLine después de la actividad de ReceiveReply y establezca su propiedad Text en "Cliente: respuesta recibida = " + replyMessage

  14. Arrastre y coloque una actividad de PrintTransactionInfo después de la actividad de WriteLine.

  15. Arrastre y coloque una actividad WriteLine al final del flujo de trabajo y establezca su propiedad Text en "Finaliza el flujo de trabajo del cliente". El flujo de trabajo del cliente completado debe ser similar al diagrama siguiente.

    The completed client workflow

  16. Compile la solución.

Crear la aplicación de servicio

  1. Agregue un nuevo proyecto Aplicación de consola denominado Service a la solución. Agregue referencias a los siguientes ensamblados:

    1. System.Activities.dll

    2. System.ServiceModel.dll

    3. System.ServiceModel.Activities.dll

  2. Abra el archivo Program.cs generado y el siguiente código:

          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. Agregue el archivo app.config siguiente al proyecto.

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

Creación de la aplicación cliente

  1. Agregue un nuevo proyecto Aplicación de consola denominado Client a la solución. Agregue una referencia a System.Activities.dll.

  2. Abra el archivo Program.cs y agregue el siguiente código.

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

Consulte también