Compartilhar via


Transações de fluxo de entrada e saída de serviços de fluxo de trabalho

Serviços e clientes de fluxo de trabalho podem participar de transações. Para que uma operação de serviço se torne parte de uma transação ambiente, coloque uma atividade Receive dentro de uma atividade TransactedReceiveScope. Todas as chamadas feitas por uma atividade Send ou SendReply dentro do TransactedReceiveScope também serão feitas dentro da transação ambiente. Um aplicativo cliente de fluxo de trabalho pode criar uma transação ambiente usando a atividade TransactionScope e chamar operações de serviço usando a transação ambiente. Este tópico explica como criar um serviço de fluxo de trabalho e um cliente de fluxo de trabalho que participam de transações.

Aviso

Se uma instância de serviço de fluxo de trabalho for carregada em uma transação e o fluxo de trabalho contiver uma atividade Persist, a instância de fluxo de trabalho será bloqueada até que a transação atinja o tempo limite.

Importante

Sempre que você usa um TransactedReceiveScope, é recomendável colocar todos os Recebimentos no fluxo de trabalho dentro de atividades TransactedReceiveScope.

Importante

Ao usar TransactedReceiveScope, quando as mensagens chegam na ordem incorreta, o fluxo de trabalho é anulado ao tentar entregar a primeira mensagem fora de ordem. Verifique se o fluxo de trabalho sempre está em um ponto de parada consistente quando ele está ocioso. Isso permitirá reiniciar o fluxo de trabalho de um ponto de persistência anterior caso o fluxo de trabalho seja anulado.

Criar uma biblioteca compartilhada

  1. Crie uma solução vazia do Visual Studio.

  2. Adicione um projeto de biblioteca de classes chamado Common. Adicione referências aos assemblies a seguir:

    • System.Activities.dll

    • System.ServiceModel.dll

    • System.ServiceModel.Activities.dll

    • System.Transactions.dll

  3. Adicione uma nova classe chamada PrintTransactionInfo ao projeto Common. Essa classe é derivada de NativeActivity e sobrecarrega o 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);  
                }  
            }  
        }  
    
    }  
    

    Essa é uma atividade nativa que exibe informações sobre a transação de ambiente e é usada nos fluxos de trabalho do serviço e do cliente usados neste tópico. Compile a solução para disponibilizar essa atividade na seção Comum da Caixa de Ferramentas.

Implementar o serviço de fluxo de trabalho

  1. Adicione um novo Serviço de Fluxo de Trabalho do WCF, chamado WorkflowService, ao projeto Common. Para fazer isso, clique com o botão direito do mouse no projeto Common, selecione Adicionar, Novo Item..., selecione Fluxo de Trabalho em Modelos Instalados e selecione Serviço de Fluxo de Trabalho do WCF.

    Adding a Workflow Service

  2. Exclua as atividades ReceiveRequest e SendResponse padrão.

  3. Arraste e solte uma atividade WriteLine na atividade Sequential Service. Defina a propriedade de texto como "Workflow Service starting ...", conforme mostrado no exemplo a seguir.

    ![Adicionando uma atividade WriteLine à atividade de Serviço Sequencial(./media/flowing-transactions-into-and-out-of-workflow-services/add-writeline-sequential-service.jpg)

  4. Arraste e solte um TransactedReceiveScope após a atividade WriteLine. A atividade TransactedReceiveScope pode ser encontrada na seção Mensagens da Caixa de Ferramentas. A atividade TransactedReceiveScope é composta por duas seções, Solicitação e Corpo. A seção Solicitação contém a atividade Receive. A seção Corpo contém as atividades a serem executadas em uma transação depois que uma mensagem é recebida.

    Adding a TransactedReceiveScope activity

  5. Selecione a atividade TransactedReceiveScope e clique no botão Variáveis. Adicione as variáveis a seguir.

    Adding variables to the TransactedReceiveScope

    Observação

    Você pode excluir a variável de dados que está presente por padrão. Você também pode usar a variável de identificador existente.

  6. Arraste e solte uma atividade Receive na seção Solicitação da atividade TransactedReceiveScope. Defina as seguintes propriedades:

    Propriedade Valor
    CanCreateInstance True (marque a caixa de seleção)
    OperationName StartSample
    ServiceContractName ITransactionSample

    O fluxo de trabalho deve se parecer com este:

    Adding a Receive activity

  7. Clique no link Definir... na atividade Receive e faça as seguintes configurações:

    Setting message settings for the Receive activity

  8. Arraste e solte uma atividade Sequence na seção Corpo do TransactedReceiveScope. Dentro da atividade Sequence, arraste e solte duas atividades WriteLine e defina as propriedades Text conforme mostrado na tabela a seguir.

    Atividade Valor
    1st WriteLine "Service: Receive Completed"
    2nd WriteLine "Service: Received = " + requestMessage

    Agora, o fluxo de trabalho deve se parecer com este:

    Sequence after adding WriteLine activities

  9. Arraste e solte a atividade PrintTransactionInfo após a segunda atividade WriteLine no Corpo na atividade TransactedReceiveScope.

    Sequence after adding PrintTransactionInfo

  10. Arraste e solte uma atividade Assign após a atividade PrintTransactionInfo e defina suas propriedades de acordo com a tabela a seguir.

    Propriedade Valor
    Para replyMessage
    Valor "Service: Sending reply."
  11. Arraste e solte uma atividade WriteLine após a atividade Assign e defina sua propriedade Text como "Service: Begin reply".

    Agora, o fluxo de trabalho deve se parecer com este:

    After adding Assign and WriteLine

  12. Clique com o botão direito do mouse na atividade Receive, selecione Criar SendReply e cole após a última atividade WriteLine. Clique no link Definir... na atividade SendReplyToReceive e faça as configurações a seguir.

    Reply message settings

  13. Arraste e solte uma atividade WriteLine após a atividade SendReplyToReceive e defina sua propriedade Text como "Service: Reply sent".

  14. Arraste e solte uma atividade WriteLine na parte inferior do fluxo de trabalho e defina sua propriedade Text como "Service: Workflow ends, press ENTER to exit".

    O fluxo de trabalho de serviço concluído deve ter esta aparência:

    Complete Service Workflow

Implementar o cliente de fluxo de trabalho

  1. Adicione um novo aplicativo de fluxo de trabalho do WCF, chamado WorkflowClient, ao projeto Common. Para fazer isso, clique com o botão direito do mouse no projeto Common, selecione Adicionar, Novo Item..., selecione Fluxo de Trabalho em Modelos Instalados e selecione Atividade.

    Add an Activity project

  2. Arraste e solte uma atividade Sequence na superfície de design.

  3. Dentro da atividade Sequence, arraste e solte uma atividade WriteLine e defina sua propriedade Text como "Client: Workflow starting". Agora, o fluxo de trabalho deve se parecer com este:

    Add a WriteLine activity

  4. Arraste e solte uma atividade TransactionScope após a atividade WriteLine. Selecione a atividade TransactionScope, clique no botão Variáveis e adicione as variáveis a seguir.

    Add variables to the TransactionScope

  5. Arraste e solte uma atividade Sequence no corpo da atividade TransactionScope.

  6. Arrastar e soltar uma atividade PrintTransactionInfo dentro do Sequence

  7. Arraste e solte uma atividade WriteLine após a atividade PrintTransactionInfo e defina sua propriedade Text como "Client: Beginning Send". Agora, o fluxo de trabalho deve se parecer com este:

    Adding Client: Beginning Send activities

  8. Arraste e solte uma atividade Send após a atividade Assign e defina as seguintes propriedades:

    Propriedade Valor
    EndpointConfigurationName workflowServiceEndpoint
    OperationName StartSample
    ServiceContractName ITransactionSample

    Agora, o fluxo de trabalho deve se parecer com este:

    Setting the Send activity properties

  9. Clique no link Definir... e defina as seguintes configurações:

    Send activity message settings

  10. Clique com o botão direito do mouse na atividade Send e selecione Criar ReceiveReply. A atividade ReceiveReply será colocada automaticamente após a atividade Send.

  11. Clique no link Definir... na atividade ReceiveReplyForSend e defina as seguintes configurações:

    Setting the ReceiveForSend message settings

  12. Arraste e solte uma atividade WriteLine entre as atividades Send e ReceiveReply e defina sua propriedade Text como "Client: Send complete".

  13. Arraste e solte uma atividade WriteLine após a atividade ReceiveReply e defina sua propriedade Text como "Client side: Reply received = " + replyMessage

  14. Arraste e solte uma atividade PrintTransactionInfo após a atividade WriteLine.

  15. Arraste e solte uma atividade WriteLine no final do fluxo de trabalho e defina sua propriedade Text como "Client workflow ends". O fluxo de trabalho do cliente concluído deve ser semelhante ao diagrama a seguir.

    The completed client workflow

  16. Compile a solução.

Criar o aplicativo de serviço

  1. Adicione um novo projeto de aplicativo de console chamado Service à solução. Adicione referências aos assemblies a seguir:

    1. System.Activities.dll

    2. System.ServiceModel.dll

    3. System.ServiceModel.Activities.dll

  2. Abra o arquivo Program.cs gerado e o seguinte 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. Adicione o arquivo app.config a seguir ao projeto.

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

Criar o aplicativo cliente

  1. Adicione um novo projeto de aplicativo de console chamado Client à solução. Adicione uma referência a System.Activities.dll.

  2. Abra o arquivo program.cs e adicione o código a seguir.

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

Confira também