Partage via


Flux de transactions WS

L’exemple TransactionFlow illustre l’utilisation d’une transaction coordonnée par le client et les options de serveur pour le flux de transactions à l’aide du protocole WS-Atomic Transaction ou OleTransactions. Cet exemple est basé sur la Prise en main, qui implémente un service de calculatrice. Toutefois, les opérations sont attribuées pour illustrer l’utilisation de TransactionFlowAttribute avec l’énumération TransactionFlowOption afin de déterminer le degré d’activation du flux de transaction. Dans l'étendue de la transaction passée, un journal des opérations demandées est écrit dans une base de données et est conservé jusqu'à ce que la transaction coordonnée par le client soit terminée. Si la transaction cliente ne se termine pas, la transaction de service Web garantit que les mises à jour appropriées de la base de données ne sont pas validées.

Remarque

La procédure d’installation et les instructions de génération de cet exemple se trouvent à la fin de cette rubrique.

Après avoir lancé une connexion au service et une transaction, le client accède à plusieurs opérations de service. Le contrat de service est défini comme suit avec chacune des opérations qui montrent un paramètre différent pour 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);
}

Cela définit les opérations dans l’ordre dans lequel elles doivent être traitées :

  • Une demande d’opération Add doit inclure une transaction passée.

  • Une demande d’opération Subtract peut inclure une transaction passée.

  • Une demande d’opération Multiply ne doit pas inclure une transaction transmise via le paramètre NotAllowed explicite.

  • Une demande d’opération Divide ne doit pas inclure une transaction transmise par l’omission d’un attribut TransactionFlow.

Pour activer le flux de transactions, les liaisons avec la propriété transactionFlow><activée doivent être utilisées en plus des attributs d’opération appropriés. Dans cet exemple, la configuration du service expose un point de terminaison TCP et un point de terminaison HTTP en plus d’un point de terminaison Exchange de métadonnées. Le point de terminaison TCP et le point de terminaison HTTP utilisent les liaisons suivantes, dont les deux ont la propriété transactionFlow><activée.

<bindings>
  <netTcpBinding>
    <binding name="transactionalOleTransactionsTcpBinding"
             transactionFlow="true"
             transactionProtocol="OleTransactions"/>
  </netTcpBinding>
  <wsHttpBinding>
    <binding name="transactionalWsatHttpBinding"
             transactionFlow="true" />
  </wsHttpBinding>
</bindings>

Remarque

Le netTcpBinding fourni par le système autorise la spécification de la transactionProtocol, tandis que le protocole wsHttpBinding fourni par le système utilise uniquement le protocole WSAtomicTransactionOctober2004 plus interopérable. Le protocole OleTransactions est disponible uniquement pour une utilisation par les clients Windows Communication Foundation (WCF).

Pour la classe qui implémente l’interface ICalculator, toutes les méthodes sont attribuées avec TransactionScopeRequired propriété définie sur true. Ce paramètre déclare que toutes les actions effectuées dans la méthode se produisent dans l’étendue d’une transaction. Dans ce cas, les actions effectuées incluent l’enregistrement dans la base de données de journal. Si la demande d’opération inclut une transaction transmise, les actions se produisent dans l’étendue de la transaction entrante ou une nouvelle étendue de transaction est générée automatiquement.

Remarque

La propriété TransactionScopeRequired définit le comportement local dans les implémentations de méthode de service et ne définit pas la capacité ou l’exigence du client pour le flux d’une transaction.

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

Sur le client, les paramètres du service TransactionFlowOption pour les opérations se reflètent dans la définition générée de l’interface ICalculator par le client. En outre, les paramètres de propriété transactionFlow du service sont reflétés dans la configuration de l’application du client. Le client peut sélectionner le transport et le protocole en sélectionnant la endpointConfigurationNameappropriée.

// Create a client using either wsat or oletx endpoint configurations
CalculatorClient client = new CalculatorClient("WSAtomicTransaction_endpoint");
// CalculatorClient client = new CalculatorClient("OleTransactions_endpoint");

Remarque

Le comportement observé de cet exemple est le même quel que soit le protocole ou le transport choisi.

Une fois la connexion au service initialisée, le client crée un TransactionScope autour des appels aux opérations de service.

// 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");

Les appels aux opérations sont comme suit :

  • La demande Add transfère la transaction requise au service et les actions du service se produisent dans l’étendue de la transaction du client.

  • La première requête Subtract transfère également la transaction autorisée vers le service, et les actions du service se déroulent à nouveau dans le cadre de la transaction du client.

  • La deuxième requête Subtract est effectuée dans une nouvelle étendue de transaction déclarée avec l’option TransactionScopeOption.Suppress. Cela supprime la transaction externe initiale du client et la requête ne circule pas vers le service. Cette approche permet à un client de refuser et de se protéger explicitement contre le flux d’une transaction vers un service lorsqu’il n’est pas nécessaire. Les actions du service se produisent dans l’étendue d’une nouvelle transaction non connectée.

  • La requête Multiply ne génère pas de transaction vers le service, car la définition générée par le client de l’interface ICalculator inclut un TransactionFlowAttribute défini sur TransactionFlowOptionNotAllowed.

  • La requête Divide ne génère pas de transaction vers le service, car à nouveau la définition générée par le client de l’interface ICalculator n’inclut pas de TransactionFlowAttribute. Les actions du service se produisent à nouveau dans l’étendue d’une autre transaction nouvelle et non connectée.

Lorsque vous exécutez l’exemple, les demandes et réponses de l’opération s’affichent dans la fenêtre de la console cliente. Appuyez sur Entrée dans la fenêtre du client pour arrêter le 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 journalisation des demandes d’opération de service s’affiche dans la fenêtre de console du service. Appuyez sur Entrée dans la fenêtre du client pour arrêter le 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

Après une exécution réussie, l'étendue de transaction du client se termine et toutes les actions prises dans cette étendue sont validées. Plus précisément, les 5 enregistrements notés sont conservés dans la base de données du service. Les 2 premières de ces opérations se sont produites dans la portée de la transaction du client.

Si une exception s’est produite n’importe où dans le TransactionScope du client, la transaction ne peut pas se terminer. Les enregistrements consignés dans cette étendue ne sont alors par validés dans la base de données. Pour observer cet effet, répétez l'exécution de l'exemple après avoir commenté l'appel pour qu'il termine le TransactionScope externe. Sur cette exécution, seules les 3 dernières actions (demandes de la seconde Subtract, Multiply et Divide) sont enregistrées, car la transaction cliente ne leur a pas été transmise.

Pour configurer, générer et exécuter l’exemple

  1. Pour générer la version C# ou Visual Basic .NET de la solution, suivez les instructions de Génération des exemples Windows Communication Foundation.

  2. Vérifiez que vous avez installé SQL Server Express Edition ou SQL Server et que la chaîne de connexion a été correctement définie dans le fichier de configuration de l’application du service. Pour exécuter l’exemple sans utiliser de base de données, définissez la valeur usingSql dans le fichier de configuration de l’application du service sur false.

  3. Pour exécuter l’exemple dans une configuration à un ou plusieurs ordinateurs, conformez-vous aux instructions figurant dans la rubrique Exécution des exemples Windows Communication Foundation.

    Remarque

    Pour la configuration inter-ordinateurs, activez distributed Transaction Coordinator à l’aide des instructions ci-dessous et utilisez l’outil WsatConfig.exe à partir du Kit de développement logiciel (SDK) Windows pour activer la prise en charge réseau des transactions WCF. Pour plus d’informations sur la configuration de WsatConfig.exe, consultez Configuration de la prise en charge des transactions WS-Atomic.

Que vous exécutiez l’exemple sur le même ordinateur ou sur différents ordinateurs, vous devez configurer Microsoft Distributed Transaction Coordinator (MSDTC) pour activer le flux de transactions réseau et utiliser l’outil de WsatConfig.exe pour activer la prise en charge réseau des transactions WCF.

Pour configurer Microsoft Distributed Transaction Coordinator (MSDTC) pour prendre en charge l’exécution de l’exemple

  1. Sur un ordinateur de service exécutant Windows Server 2003 ou Windows XP, configurez MSDTC pour autoriser les transactions réseau entrantes en suivant ces instructions.

    1. Dans le menu Démarrer , accédez à Panneau de configuration, puis Outils d'administration, puis Services de composants.

    2. Développez Services de composants. Ouvrez le dossier ordinateurs .

    3. Cliquez avec le bouton droit sur Mon Ordinateur et sélectionnez Propriétés.

    4. Sur l'onglet MSDTC, cliquez sur Configuration de sécurité.

    5. Cochez Accès DTC réseau et Autoriser les transactions entrantes.

    6. Cliquez sur OK, puis sur Oui pour redémarrer le service MSDTC.

    7. Cliquez sur OK pour fermer la boîte de dialogue.

  2. Sur un ordinateur de service exécutant Windows Server 2008 ou Windows Vista, configurez MSDTC pour autoriser les transactions réseau entrantes en suivant ces instructions.

    1. Dans le menu Démarrer, accédez à Panneau de configuration, puis à Outils d'administration, puis à Services de composants.

    2. Développez Services de composants. Ouvrez le dossier ordinateurs . Sélectionnez Distributed Transaction Coordinator.

    3. Cliquez avec le bouton droit sur Coordinateur DTC et sélectionnez Propriétés.

    4. Sous l’onglet Sécurité, activez Accès DTC réseau et Autoriser les transactions entrantes.

    5. Cliquez sur OK, puis sur Oui pour redémarrer le service MSDTC.

    6. Cliquez sur OK pour fermer la boîte de dialogue.

  3. Sur l’ordinateur client, configurez MSDTC pour autoriser les transactions réseau sortantes :

    1. Dans le menu Démarrer, naviguez jusqu’à Control Panel, Outils d’administration et Services de composants.

    2. Cliquez avec le bouton droit sur Mon Ordinateur, puis sélectionnez Propriétés.

    3. Sous l’onglet MSDTC, cliquez sur Configuration de sécurité.

    4. Cochez Accès DTC réseau et Autoriser les transactions sortantes.

    5. Cliquez sur OK, puis sur Oui pour redémarrer le service MSDTC.

    6. Cliquez sur OK pour fermer la boîte de dialogue.