Condividi tramite


Propagazione di transazioni all'interno e all'esterno di servizi flusso di lavoro

Servizi e client del flusso di lavoro possono partecipare alle transazioni. Affinché un'operazione del servizio diventi parte di una transazione di ambiente, posizionare un'attività Receive all'interno di un'attività TransactedReceiveScope. Qualsiasi chiamata effettuata da un'attività Send o un'attività SendReply all'interno di TransactedReceiveScope verrà effettuata anche all'interno della transazione di ambiente. Un'applicazione client del flusso di lavoro può creare una transazione di ambiente tramite l'attività TransactionScope e chiamare operazioni del servizio utilizzando la transazione di ambiente. In questo argomento viene illustrato il processo di creazione di un servizio flusso di lavoro e di un client flusso di lavoro che partecipano a transazioni.

Avviso

Se un'istanza del servizio flusso di lavoro viene caricata all'interno di una transazione e il flusso di lavoro contiene un'attività Persist, l'istanza del flusso di lavoro verrà interrotta finché non si verifica il timeout della transazione.

Importante

Ogni volta che si utilizza un oggetto TransactedReceiveScope, è consigliabile posizionare tutte le attività Receive del flusso di lavoro all'interno delle attività TransactedReceiveScope.

Importante

Quando si utilizza l'oggetto TransactedReceiveScope e i messaggi arrivano nell'ordine non corretto, il flusso di lavoro verrà interrotto quando si tenterà di consegnare il primo messaggio nell'ordine non corretto. È necessario assicurarsi che il flusso di lavoro sia sempre in corrispondenza di un punto di interruzione coerente quando il flusso di lavoro è inattivo. In questo modo sarà possibile riavviare il flusso di lavoro da un punto di persistenza precedente nel caso in cui il flusso di lavoro venga interrotto.

Creare una libreria condivisa

  1. Creare una nuova soluzione Visual Studio vuota.

  2. Aggiungere un nuovo progetto della libreria di classi denominato Common. Aggiungere riferimenti agli assembly riportati di seguito:

    • System.Activities.dll

    • System.ServiceModel.dll

    • System.ServiceModel.Activities.dll

    • System.Transactions.dll

  3. Aggiungere una nuova classe denominata PrintTransactionInfo al progetto Common. Questa classe è derivata da NativeActivity ed esegue l'overload del metodo 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);  
                }  
            }  
        }  
    
    }  
    

    Si tratta di un'attività nativa che visualizza informazioni sulla transazione di ambiente e viene utilizzata sia nei flussi di lavoro del servizio che del client utilizzati nel presente argomento. Compilare la soluzione per rendere disponibile questa attività nella sezione Common della Casella degli strumenti.

Implementare il servizio di flusso di lavoro

  1. Aggiungere un nuovo servizio flusso di lavoro WCF, denominato WorkflowService, al progetto Common. A tale scopo, fare clic con il pulsante destro del mouse sul progetto Common, selezionare Aggiungi, Nuovo elemento..., quindi selezionare Flusso di lavoro in Modelli installati e infine selezionare Servizio flusso di lavoro WCF.

    Adding a Workflow Service

  2. Eliminare le attività ReceiveRequest e SendResponse predefinite.

  3. Trascinare e rilasciare un'attività WriteLine nell'attività Sequential Service. Impostare la proprietà Text su "Workflow Service starting ..." come illustrato nell'esempio seguente.

    ![Adding a WriteLine activity to the Sequential Service activity(./media/flowing-transactions-into-and-out-of-workflow-services/add-writeline-sequential-service.jpg)

  4. Trascinare e rilasciare un'attività TransactedReceiveScope dopo l'attività WriteLine. L'attività di TransactedReceiveScope è reperibile nella sezione Messaggistica della Casella degli strumenti. L'attività TransactedReceiveScope è composta da due sezioni Richiesta e Corpo. La sezione Request contiene l'attività Receive. La sezione Corpo contiene le attività da eseguire all'interno di una transazione dopo la ricezione di un messaggio.

    Adding a TransactedReceiveScope activity

  5. Selezionare l'attività TransactedReceiveScope e fare clic sul pulsante Variabili. Aggiungere le variabili seguenti.

    Adding variables to the TransactedReceiveScope

    Nota

    È possibile eliminare la variabile relativa ai dati, presente per impostazione predefinita. È possibile utilizzare anche la variabile dell'handle esistente.

  6. Trascinare e rilasciare un'attività Receive all'interno della sezione Richiesta dell'attività TransactedReceiveScope. Impostare le proprietà seguenti:

    Proprietà valore
    CanCreateInstance True (controllare la casella di controllo)
    OperationName StartSample
    ServiceContractName ITransactionSample

    Il flusso di lavoro dovrebbe risultare analogo al seguente:

    Adding a Receive activity

  7. Fare clic sul collegamento Definisci... nell'attività Receive e configurare le impostazioni seguenti:

    Setting message settings for the Receive activity

  8. Trascinare e rilasciare un'attività Sequence nella sezione Corpo di TransactedReceiveScope. All'interno dell'attività Sequence, trascinare e rilasciare due attività WriteLine e impostare le proprietà Text come illustrato nella tabella seguente.

    Impegno Valore
    WriteLine 1 "Servizio: Ricezione completata"
    WriteLine 2 "Service: Received = " + requestMessage

    Il flusso di lavoro dovrebbe risultare analogo al seguente:

    Sequence after adding WriteLine activities

  9. Trascinare l'attività PrintTransactionInfo dopo la seconda attività WriteLine nella sezione Corpo nell'attività TransactedReceiveScope.

    Sequence after adding PrintTransactionInfo

  10. Trascinare e rilasciare un'attività Assign dopo l'attività PrintTransactionInfo e impostarne le proprietà in base alla tabella seguente.

    Proprietà valore
    Per replyMessage
    Valore "Service: Sending reply".
  11. Trascinare un'attività WriteLine dopo l'attività Assign e impostarne la proprietà Text su "Service: Begin reply".

    Il flusso di lavoro dovrebbe risultare analogo al seguente:

    After adding Assign and WriteLine

  12. Fare clic con il pulsante destro del mouse sull'attività Receive, selezionare Crea SendReply e incollarla dopo l'ultima attività WriteLine. Fare clic sul collegamento Definisci... nell'attività SendReplyToReceive e configurare le impostazioni seguenti.

    Reply message settings

  13. Trascinare e rilasciare un'attività WriteLine dopo l'attività SendReplyToReceive e impostarne la proprietà Text su "Servizio: Risposta inviata".

  14. Trascinare un'attività WriteLine nella parte inferiore del flusso di lavoro e impostarne la proprietà Text su "Service: Workflow ends, press ENTER to exit".

    Il flusso di lavoro del servizio completato dovrebbe risultare analogo al seguente:

    Complete Service Workflow

Implementare il client flusso di lavoro

  1. Aggiungere una nuova applicazione flusso di lavoro WCF, denominata WorkflowClient, al progetto Common. A tale scopo, fare clic con il pulsante destro del mouse sul progetto Common, selezionare Aggiungi, Nuovo elemento..., quindi selezionare Flusso di lavoro in Modelli installati e infine selezionare Attività.

    Add an Activity project

  2. Trascinare e rilasciare un'attività Sequence sull'area di progettazione.

  3. All'interno dell'attività Sequence, trascinare un'attività WriteLine e impostarne la proprietà Text su "Client: Workflow starting". Il flusso di lavoro dovrebbe risultare analogo al seguente:

    Add a WriteLine activity

  4. Trascinare un'attività TransactionScope dopo l'attività WriteLine. Selezionare l'attività TransactionScope, fare clic sul pulsante Variabili e aggiungere le variabili seguenti.

    Add variables to the TransactionScope

  5. Trascinare e rilasciare un'attività Sequence nel corpo dell'attività TransactionScope.

  6. Trascinare e rilasciare un'attività PrintTransactionInfo all'interno dell'attività Sequence.

  7. Trascinare e rilasciare un'attività WriteLine dopo l'attività PrintTransactionInfo e impostarne la proprietà Text su "Client: Avvio invio". Il flusso di lavoro dovrebbe risultare analogo al seguente:

    Adding Client: Beginning Send activities

  8. Trascinare un'attività Send dopo l'attività Assign e impostare le proprietà seguenti:

    Proprietà valore
    EndpointConfigurationName workflowServiceEndpoint
    OperationName StartSample
    ServiceContractName ITransactionSample

    Il flusso di lavoro dovrebbe risultare analogo al seguente:

    Setting the Send activity properties

  9. Fare clic sul collegamento Definisci... e configurare le impostazioni seguenti:

    Send activity message settings

  10. Fare clic con il pulsante destro del mouse sull'attività Send e selezionare Crea ReceiveReply. L'attività ReceiveReply sarà posizionata automaticamente dopo l'attività Send.

  11. Fare clic sul collegamento Definisci nell'attività ReceiveReplyForSend e configurare le impostazioni seguenti:

    Setting the ReceiveForSend message settings

  12. Trascinare un'attività WriteLine tra le attività Send e ReceiveReply e impostarne la proprietà Text su "Client: Send complete".

  13. Trascinare e rilasciare un'attività WriteLine dopo l'attività ReceiveReply e impostarne la proprietà Text su "Client side: Reply received = " + replyMessage

  14. Trascinare un'attività PrintTransactionInfo dopo l'attività WriteLine.

  15. Trascinare un'attività WriteLine alla fine del flusso di lavoro e impostarne la proprietà Text su "Client workflow ends". Il flusso di lavoro client completato viene visualizzato come illustrato del diagramma seguente.

    The completed client workflow

  16. Compilare la soluzione.

Creare l'applicazione di servizio

  1. Aggiungere un nuovo progetto Applicazione console denominato Service alla soluzione. Aggiungere riferimenti agli assembly riportati di seguito:

    1. System.Activities.dll

    2. System.ServiceModel.dll

    3. System.ServiceModel.Activities.dll

  2. Aprire il file Program.cs generato e il codice seguente:

          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. Aggiungere il file app.config seguente al progetto.

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

Creare l'applicazione client

  1. Aggiungere un nuovo progetto Applicazione console denominato Client alla soluzione. Aggiungere un riferimento a System.Activities.dll.

  2. Aprire il file program.cs e aggiungere il codice seguente.

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

Vedi anche