Flusso delle transazioni WS
Questo esempio TransactionFlow dimostra l'uso di una transazione coordinata dal client e le opzioni client e server per il flusso delle transazioni mediante il protocollo WS-Atomic Transaction o OleTransactions. Questo esempio si basa su Introduzione che implementa un servizio calcolatrice, ma le operazioni vengono attribuite per dimostrare l'uso di TransactionFlowAttribute
con l'enumerazione TransactionFlowOption per la determinazione del grado di abilitazione del flusso delle transazioni. All'interno dell'ambito della transazione propagata, viene scritto un log delle operazioni richieste in un database che persiste fino a che la transazione coordinata dal client non è stata completata; se la transazione client non viene completata, la transazione del servizio Web assicura che non venga eseguito il commit degli aggiornamenti appropriati al database.
Nota
La procedura di installazione e le istruzioni di compilazione per questo esempio si trovano alla fine di questo argomento.
Dopo avere avviato una connessione con il servizio e una transazione, il client accede ad alcune operazioni del servizio. Il contratto per il servizio è definito come segue, con ognuna delle operazioni che dimostra un'impostazione diversa per TransactionFlowOption
.
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
double Add(double n1, double n2);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
double Subtract(double n1, double n2);
[OperationContract]
[TransactionFlow(TransactionFlowOption.NotAllowed)]
double Multiply(double n1, double n2);
[OperationContract]
double Divide(double n1, double n2);
}
Questo definisce le operazioni nell'ordine in cui devono essere elaborate:
Una richiesta di operazione
Add
deve includere una transazione propagata.Una richiesta di operazione
Subtract
può includere una transazione propagata.Una richiesta di operazione
Multiply
non deve includere una transazione propagata mediante l'impostazione esplicita NotAllowed.Una richiesta di operazione
Divide
non deve includere una transazione propagata mediante l'omissione di un attributoTransactionFlow
.
Per abilitare il flusso delle transazioni, oltre agli attributi appropriati dell'operazione è necessario usare associazioni con la proprietà <transactionFlow> abilitata. In questo esempio, la configurazione del servizio espone un endpoint TCP e un endpoint HTTP oltre a un endpoint di scambio dei metadati. L'endpoint TCP e l'endpoint HTTP usano le associazioni seguenti, le cui proprietà <transactionFlow> sono abilitate.
<bindings>
<netTcpBinding>
<binding name="transactionalOleTransactionsTcpBinding"
transactionFlow="true"
transactionProtocol="OleTransactions"/>
</netTcpBinding>
<wsHttpBinding>
<binding name="transactionalWsatHttpBinding"
transactionFlow="true" />
</wsHttpBinding>
</bindings>
Nota
L'associazione netTcpBinding fornita dal sistema consente di specificare il transactionProtocol mentre la wsHttpBinding fornita dal sistema usa solo il protocollo WSAtomicTransactionOctober2004 più interoperabile. Il protocollo OleTransactions è disponibile solo per l'uso da parte dei client di Windows Communication Foundation (WCF).
Per la classe che implementa l'interfaccia ICalculator
, a tutti i metodi viene attribuita la proprietà TransactionScopeRequired impostata su true
. Questa impostazione dichiara che tutte le azioni intraprese all'interno del metodo avvengono all'interno dell'ambito di una transazione. In questo caso, le azioni intraprese includono la registrazione sul database del log. Se la richiesta dell'operazione include una transazione propagata allora le azioni avvengono all'interno dell'ambito della transazione in ingresso o viene generato automaticamente un nuovo ambito della transazione.
Nota
La proprietà TransactionScopeRequired definisce il comportamento locale alle implementazioni del metodo del servizio e non definisce la capacità o la necessità del client di propagare una transazione.
// Service class that implements the service contract.
[ServiceBehavior(TransactionIsolationLevel = System.Transactions.IsolationLevel.Serializable)]
public class CalculatorService : ICalculator
{
[OperationBehavior(TransactionScopeRequired = true)]
public double Add(double n1, double n2)
{
RecordToLog(String.Format(CultureInfo.CurrentCulture, "Adding {0} to {1}", n1, n2));
return n1 + n2;
}
[OperationBehavior(TransactionScopeRequired = true)]
public double Subtract(double n1, double n2)
{
RecordToLog(String.Format(CultureInfo.CurrentCulture, "Subtracting {0} from {1}", n2, n1));
return n1 - n2;
}
[OperationBehavior(TransactionScopeRequired = true)]
public double Multiply(double n1, double n2)
{
RecordToLog(String.Format(CultureInfo.CurrentCulture, "Multiplying {0} by {1}", n1, n2));
return n1 * n2;
}
[OperationBehavior(TransactionScopeRequired = true)]
public double Divide(double n1, double n2)
{
RecordToLog(String.Format(CultureInfo.CurrentCulture, "Dividing {0} by {1}", n1, n2));
return n1 / n2;
}
// Logging method omitted for brevity
}
Nel client, le impostazioni TransactionFlowOption
del servizio sulle operazioni vengono riflesse nella definizione generata del client relativa all'interfaccia ICalculator
. Inoltre, le impostazioni della proprietà di transactionFlow
del servizio sono riflesse nella configurazione dell'applicazione del client. Il client può determinare il trasporto e il protocollo selezionando l'endpoint endpointConfigurationName
appropriato.
// Create a client using either wsat or oletx endpoint configurations
CalculatorClient client = new CalculatorClient("WSAtomicTransaction_endpoint");
// CalculatorClient client = new CalculatorClient("OleTransactions_endpoint");
Nota
Il comportamento osservato di questo esempio è lo stesso indipendentemente dal protocollo o dal trasporto scelto.
Dopo avere avviato la connessione al servizio, il client crea un nuovo TransactionScope
intorno alle chiamate alle operazioni del servizio.
// Start a transaction scope
using (TransactionScope tx =
new TransactionScope(TransactionScopeOption.RequiresNew))
{
Console.WriteLine("Starting transaction");
// Call the Add service operation
// - generatedClient will flow the required active transaction
double value1 = 100.00D;
double value2 = 15.99D;
double result = client.Add(value1, value2);
Console.WriteLine(" Add({0},{1}) = {2}", value1, value2, result);
// Call the Subtract service operation
// - generatedClient will flow the allowed active transaction
value1 = 145.00D;
value2 = 76.54D;
result = client.Subtract(value1, value2);
Console.WriteLine(" Subtract({0},{1}) = {2}", value1, value2, result);
// Start a transaction scope that suppresses the current transaction
using (TransactionScope txSuppress =
new TransactionScope(TransactionScopeOption.Suppress))
{
// Call the Subtract service operation
// - the active transaction is suppressed from the generatedClient
// and no transaction will flow
value1 = 21.05D;
value2 = 42.16D;
result = client.Subtract(value1, value2);
Console.WriteLine(" Subtract({0},{1}) = {2}", value1, value2, result);
// Complete the suppressed scope
txSuppress.Complete();
}
// Call the Multiply service operation
// - generatedClient will not flow the active transaction
value1 = 9.00D;
value2 = 81.25D;
result = client.Multiply(value1, value2);
Console.WriteLine(" Multiply({0},{1}) = {2}", value1, value2, result);
// Call the Divide service operation.
// - generatedClient will not flow the active transaction
value1 = 22.00D;
value2 = 7.00D;
result = client.Divide(value1, value2);
Console.WriteLine(" Divide({0},{1}) = {2}", value1, value2, result);
// Complete the transaction scope
Console.WriteLine(" Completing transaction");
tx.Complete();
}
Console.WriteLine("Transaction committed");
Le chiamate alle operazioni sono come segue:
La richiesta
Add
propaga la transazione richiesta al servizio e le azioni del servizio si verificano all'interno dell'ambito della transazione del client.Anche la prima richiesta
Subtract
propaga la transazione consentita al servizio e di nuovo le azioni del servizio si verificano all'interno dell'ambito della transazione del client.La seconda richiesta
Subtract
viene eseguita all'interno di un nuovo ambito della transazione dichiarato con l'opzioneTransactionScopeOption.Suppress
. Questo sopprime la transazione esterna iniziale del client e la richiesta non propaga una transazione al servizio. Questo approccio consente a un client di rinunciare esplicitamente e protegge dalla propagazione di una transazione a un servizio quando non viene richiesta. Le azioni del servizio avvengono all'interno dell'ambito di una nuova transazione non connessa.La richiesta
Multiply
non propaga una transazione al servizio, in quanto la definizione generata del client relativa all'interfacciaICalculator
include un oggetto TransactionFlowAttribute impostato su TransactionFlowOptionNotAllowed
.La richiesta
Divide
non propaga una transazione al servizio, in quanto di nuovo la definizione generata del client relativa all'interfacciaICalculator
non include un oggettoTransactionFlowAttribute
. Le azioni del servizio avvengono nuovamente all'interno dell'ambito di un'altra nuova transazione non connessa.
Quando si esegue l'esempio, le richieste e le risposte dell'operazione vengono visualizzate nella finestra della console client. Premere INVIO nella finestra del client per arrestare il client.
Starting transaction
Add(100,15.99) = 115.99
Subtract(145,76.54) = 68.46
Subtract(21.05,42.16) = -21.11
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714
Completing transaction
Transaction committed
Press <ENTER> to terminate client.
La registrazione delle richieste di operazione del servizio viene visualizzata nella finestra della console del servizio. Premere INVIO nella finestra del client per arrestare il client.
Press <ENTER> to terminate the service.
Writing row to database: Adding 100 to 15.99
Writing row to database: Subtracting 76.54 from 145
Writing row to database: Subtracting 42.16 from 21.05
Writing row to database: Multiplying 9 by 81.25
Writing row to database: Dividing 22 by 7
Dopo un'esecuzione corretta, l'ambito della transazione del client viene completato e viene eseguito il commit di tutte le azioni intraprese all'interno di quel ambito. In particolare, i 5 record menzionati vengono resi permanenti nel database del servizio. I primi 2 di questi si sono verificati all'interno dell'ambito della transazione del client.
Se si verifica un'eccezione in un punto qualsiasi all'interno dell'oggetto TransactionScope
del client, la transazione non potrà essere completata. Ciò impedisce il commit nel database dei record registrati all'interno di quell'ambito. Questo effetto può essere osservato ripetendo l'esecuzione dell'esempio dopo avere impostato come commento la chiamata per il completamento dell'oggetto TransactionScope
esterno. In una tale esecuzione, vengono registrate solo le ultime 3 azioni (dalla seconda richiesta Subtract
e le richieste Multiply
e Divide
), in quanto la transazione client non si è propagata fino a tali azioni.
Per impostare, compilare ed eseguire l'esempio
Per compilare la versione in C# o Visual Basic .NET della soluzione, seguire le istruzioni in Generazione degli esempi Windows Communication Foundation
Verificare che sia stato installato SQL Server Express Edition o SQL Server e che la stringa di connessione sia stata impostata correttamente nel file di configurazione dell'applicazione del servizio. Per eseguire l'esempio senza usare un database, impostare il valore
usingSql
nel file di configurazione dell'applicazione del servizio sufalse
Per eseguire l'esempio in un solo computer o tra computer diversi, seguire le istruzioni in Esecuzione degli esempi di Windows Communication Foundation.
Nota
Nella configurazione con più computer abilitare Distributed Transaction Coordinator usando le istruzioni seguenti e usare lo strumento WsatConfig.exe di Windows SDK per abilitare il supporto di rete delle transazioni WCF. Per informazioni sulla configurazione di WsatConfig.exe, vedere Configurazione del supporto transazioni WS-Atomic.
Sia che si esegua l'esempio nello stesso computer o in computer diversi, è necessario configurare Microsoft Distributed Transaction Coordinator (MSDTC) per abilitare il flusso di transazioni nella rete e usare lo strumento WsatConfig.exe per abilitare il supporto in rete delle transazioni WCF.
Per configurare Microsoft Distributed Transaction Coordinator (MSDTC) per supportare l'esecuzione dell'esempio
In un computer del servizio che esegue Windows Server 2003 o Windows XP configurare MSDTC per consentire transazioni di rete in ingresso seguendo queste istruzioni.
Fare clic sul pulsante Start, scegliere Pannello di controllo, quindi Strumenti di amministrazione e infine Servizi componenti.
Espandere Servizi componenti. Aprire la cartella Computer.
Fare clic con il pulsante destro del mouse su Risorse del computer e scegliere Proprietà.
Nella scheda MSDTC fare clic su Configurazione sicurezza.
Selezionare Accesso di rete DTC e Consenti connessioni in ingresso.
Fare clic su OK, quindi su Sì per riavviare il servizio MSDTC.
Scegliere OK per chiudere la finestra di dialogo.
In un computer del servizio che esegue Windows Server 2008 o Windows Vista configurare MSDTC per consentire transazioni di rete in ingresso seguendo queste istruzioni.
Fare clic sul pulsante Start, scegliere Pannello di controllo, quindi Strumenti di amministrazione e infine Servizi componenti.
Espandere Servizi componenti. Aprire la cartella Computer. Selezionare Distributed Transaction Coordinator.
Fare clic con il pulsante destro del mouse su Distributed Transaction Coordinator, quindi scegliere Proprietà.
Nella scheda Sicurezza, selezionare Accesso di rete DTC e Consenti connessioni in ingresso.
Fare clic su OK, quindi su Sì per riavviare il servizio MSDTC.
Scegliere OK per chiudere la finestra di dialogo.
Nel computer client configurare MSDTC per consentire le transazioni di rete in uscita.
Fare clic sul pulsante Start, scegliere
Control Panel
, quindi Strumenti di amministrazione e infine Servizi componenti.Fare clic con il pulsante destro del mouse su Risorse del computer e scegliere Proprietà.
Nella scheda MSDTC fare clic su Configurazione sicurezza.
Selezionare Accesso di rete DTC e Consenti connessioni in uscita.
Fare clic su OK, quindi su Sì per riavviare il servizio MSDTC.
Scegliere OK per chiudere la finestra di dialogo.