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
Creare una nuova soluzione Visual Studio vuota.
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
Aggiungere una nuova classe denominata
PrintTransactionInfo
al progettoCommon
. 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
Aggiungere un nuovo servizio flusso di lavoro WCF, denominato
WorkflowService
, al progettoCommon
. A tale scopo, fare clic con il pulsante destro del mouse sul progettoCommon
, selezionare Aggiungi, Nuovo elemento..., quindi selezionare Flusso di lavoro in Modelli installati e infine selezionare Servizio flusso di lavoro WCF.Eliminare le attività
ReceiveRequest
eSendResponse
predefinite.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)
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.
Selezionare l'attività TransactedReceiveScope e fare clic sul pulsante Variabili. Aggiungere le variabili seguenti.
Nota
È possibile eliminare la variabile relativa ai dati, presente per impostazione predefinita. È possibile utilizzare anche la variabile dell'handle esistente.
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:
Fare clic sul collegamento Definisci... nell'attività Receive e configurare le impostazioni seguenti:
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:
Trascinare l'attività
PrintTransactionInfo
dopo la seconda attività WriteLine nella sezione Corpo nell'attività TransactedReceiveScope.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". 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:
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.Trascinare e rilasciare un'attività WriteLine dopo l'attività
SendReplyToReceive
e impostarne la proprietà Text su "Servizio: Risposta inviata".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:
Implementare il client flusso di lavoro
Aggiungere una nuova applicazione flusso di lavoro WCF, denominata
WorkflowClient
, al progettoCommon
. A tale scopo, fare clic con il pulsante destro del mouse sul progettoCommon
, selezionare Aggiungi, Nuovo elemento..., quindi selezionare Flusso di lavoro in Modelli installati e infine selezionare Attività.Trascinare e rilasciare un'attività Sequence sull'area di progettazione.
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:Trascinare un'attività TransactionScope dopo l'attività WriteLine. Selezionare l'attività TransactionScope, fare clic sul pulsante Variabili e aggiungere le variabili seguenti.
Trascinare e rilasciare un'attività Sequence nel corpo dell'attività TransactionScope.
Trascinare e rilasciare un'attività
PrintTransactionInfo
all'interno dell'attività Sequence.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: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:
Fare clic sul collegamento Definisci... e configurare le impostazioni seguenti:
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.
Fare clic sul collegamento Definisci nell'attività ReceiveReplyForSend e configurare le impostazioni seguenti:
Trascinare un'attività WriteLine tra le attività Send e ReceiveReply e impostarne la proprietà Text su "Client: Send complete".
Trascinare e rilasciare un'attività WriteLine dopo l'attività ReceiveReply e impostarne la proprietà Text su "Client side: Reply received = " + replyMessage
Trascinare un'attività
PrintTransactionInfo
dopo l'attività WriteLine.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.
Compilare la soluzione.
Creare l'applicazione di servizio
Aggiungere un nuovo progetto Applicazione console denominato
Service
alla soluzione. Aggiungere riferimenti agli assembly riportati di seguito:System.Activities.dll
System.ServiceModel.dll
System.ServiceModel.Activities.dll
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(); }; }
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
Aggiungere un nuovo progetto Applicazione console denominato
Client
alla soluzione. Aggiungere un riferimento a System.Activities.dll.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; } }