次の方法で共有


WS トランザクション フロー

TransactionFlow サンプル では、クライアントが調整するトランザクションの使用例を示し、WS-Atomic Transaction プロトコルまたは OleTransactions プロトコルを用いたトランザクション フローのクライアントおよびサーバーのオプションを解説しています。 このサンプルは、電卓サービスを実装する 作業の開始 に基づいていますが、操作は、TransactionFlowAttribute 列挙型を使用して、どの程度のトランザクション フローが有効になっているかを判断する の使用を示すために属性付けされています。 フローされたトランザクションのスコープ内では、要求された操作のログがデータベースに書き込まれ、クライアント調整トランザクションが完了するまで保持されます。クライアント トランザクションが完了しない場合、Web サービス トランザクションはデータベースに対する適切な更新がコミットされないようにします。

手記

このサンプルのセットアップ手順とビルド手順は、このトピックの最後にあります。

サービスとトランザクションへの接続を開始すると、クライアントは複数のサービス操作にアクセスします。 サービスのコントラクトは次のように定義され、各操作で 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);
}

これにより、処理される順序で操作が定義されます。

  • Add 操作要求には、フローされたトランザクションが含まれている必要があります。

  • Subtract 操作要求には、フローされたトランザクションが含まれる場合があります。

  • Multiply 操作要求には、明示的な NotAllowed 設定を介してフローされたトランザクションを含めてはなりません。

  • Divide 操作要求には、TransactionFlow 属性の省略によってフローされたトランザクションを含めてはなりません。

トランザクション フローを有効にするには、適切な操作属性に加えて、<transactionFlow> プロパティが有効になっているバインドを使用する必要があります。 このサンプルでは、サービスの構成によって、メタデータ Exchange エンドポイントに加えて、TCP エンドポイントと HTTP エンドポイントが公開されます。 TCP エンドポイントと HTTP エンドポイントは次のバインディングを使用します。どちらのバインドでも、<transactionFlow> プロパティが有効になっています。

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

手記

システム提供の netTcpBinding では transactionProtocol を指定できます。一方、システム提供の wsHttpBinding では、より相互運用可能な WSAtomicTransactionOctober2004 プロトコルのみが使用されます。 OleTransactions プロトコルは、Windows Communication Foundation (WCF) クライアントでのみ使用できます。

ICalculator インターフェイスを実装するクラスの場合、すべてのメソッドは、TransactionScopeRequiredに設定されたプロパティ true 属性付きで属性付けされます。 この設定では、メソッド内で実行されるすべてのアクションがトランザクションのスコープ内で発生することを宣言します。 この場合、実行されるアクションにはログ データベースへの記録が含まれます。 操作要求にフローされたトランザクションが含まれている場合、アクションは受信トランザクションのスコープ内で発生するか、新しいトランザクション スコープが自動的に生成されます。

手記

TransactionScopeRequired プロパティは、サービス メソッドの実装に対してローカルな動作を定義し、トランザクションをフローするためのクライアントの機能や要件を定義しません。

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

クライアントでは、操作に対するサービスの TransactionFlowOption 設定が、クライアントによって生成された ICalculator インターフェイスの定義に反映されます。 また、サービスの transactionFlow プロパティの設定は、クライアントのアプリケーション構成に反映されます。 クライアントは、適切な endpointConfigurationNameを選択することで、トランスポートとプロトコルを選択できます。

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

手記

このサンプルの観察された動作は、どのプロトコルまたはトランスポートが選択されても同じです。

サービスへの接続を開始すると、クライアントはサービス操作の呼び出しに関する新しい TransactionScope を作成します。

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

操作の呼び出しは次のとおりです。

  • Add 要求は、必要なトランザクションをサービスにフローし、サービスのアクションはクライアントのトランザクションのスコープ内で発生します。

  • 最初の Subtract 要求では、許可されたトランザクションもサービスにフローされ、サービスのアクションはクライアントのトランザクションのスコープ内で再度発生します。

  • 2 番目の Subtract 要求は、TransactionScopeOption.Suppress オプションで宣言された新しいトランザクション スコープ内で実行されます。 これにより、クライアントの最初の外部トランザクションが抑制され、要求はトランザクションをサービスに伝達しません。 この方法を使用すると、クライアントはトランザクションを明示的にオプトアウトし、サービスへのトランザクションのフローが不要な場合に保護することができます。 サービスのアクションは、新しい未接続のトランザクションのスコープ内で発生します。

  • Multiply 要求は、ICalculator インターフェイスのクライアントによって生成された定義に、TransactionFlowAttributeTransactionFlowOptionに設定された NotAllowed が含まれているため、サービスにトランザクションをフローしません。

  • Divide インターフェイスのクライアントによって生成された定義に ICalculatorが含まれていないため、TransactionFlowAttribute 要求はトランザクションをサービスにフローしません。 サービスのアクションは、別の新規および未接続のトランザクションのスコープ内で再び発生します。

サンプルを実行すると、操作要求と応答がクライアント コンソール ウィンドウに表示されます。 クライアント ウィンドウで Enter キーを押して、クライアントをシャットダウンします。

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.

サービス操作要求のログは、サービスのコンソール ウィンドウに表示されます。 クライアント ウィンドウで Enter キーを押して、クライアントをシャットダウンします。

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

正常に実行されると、クライアントのトランザクション スコープが完了し、そのスコープ内で実行されたすべてのアクションがコミットされます。 具体的には、5 つのレコードがサービスのデータベースに保持されます。 これらの最初の 2 つは、クライアントのトランザクションのスコープ内で発生しました。

クライアントの TransactionScope 内の任意の場所で例外が発生した場合、トランザクションを完了できません。 これにより、そのスコープ内でログに記録されたレコードがデータベースにコミットされません。 この効果は、外側の TransactionScopeを完了するために呼び出しをコメントアウトした後にサンプル実行を繰り返すことによって観察できます。 このような実行では、最後の 3 つのアクション (2 番目の SubtractMultiply、および Divide 要求) のみがログに記録されます。これは、クライアント トランザクションがそれらへのフローを行わなかったためです。

サンプルを設定、ビルド、実行するには

  1. ソリューションの C# または Visual Basic .NET バージョンをビルドするには、「Windows Communication Foundation サンプルのビルド」の手順に従います。

  2. SQL Server Express Edition または SQL Server がインストールされていること、および接続文字列がサービスのアプリケーション構成ファイルに正しく設定されていることを確認します。 データベースを使用せずにサンプルを実行するには、サービスのアプリケーション構成ファイルの usingSql 値を falseに設定します。

  3. 単一または複数のコンピューター間の構成でサンプルを実行するには、「Windows Communication Foundation Samplesの実行」の手順に従います。

    手記

    マシン間構成の場合は、次の手順に従って分散トランザクション コーディネーターを有効にし、Windows SDK の WsatConfig.exe ツールを使用して WCF トランザクション ネットワークのサポートを有効にします。 WsatConfig.exeの設定については、「WS-Atomic トランザクションサポート の設定を参照してください。

同じコンピューターまたは別のコンピューターでサンプルを実行する場合でも、Microsoft 分散トランザクション コーディネーター (MSDTC) を構成してネットワーク トランザクション フローを有効にし、WsatConfig.exe ツールを使用して WCF トランザクション のネットワーク サポートを有効にする必要があります。

サンプルの実行をサポートするように Microsoft 分散トランザクション コーディネーター (MSDTC) を構成するには

  1. Windows Server 2003 または Windows XP を実行しているサービス コンピューターで、次の手順に従って、受信ネットワーク トランザクションを許可するように MSDTC を構成します。

    1. [スタート] メニューから、[コントロール パネル]に移動し、[管理ツール]を選択して、[コンポーネント サービス]に進みます。

    2. [コンポーネント サービス] を展開します。 コンピューター フォルダーを開きます。

    3. [マイ コンピューター] を右クリックし、[プロパティ]を選択します。

    4. [MSDTC] タブで、[セキュリティ構成] をクリックします。

    5. ネットワーク DTC アクセス を確認し、で受信を許可します。

    6. [OK] クリックし、[はい] クリックして MSDTC サービスを再起動します。

    7. ダイアログ ボックスを閉じるには [OK] をクリックします。

  2. Windows Server 2008 または Windows Vista を実行しているサービス コンピューターで、次の手順に従って、受信ネットワーク トランザクションを許可するように MSDTC を構成します。

    1. [スタート] メニューから、[コントロール パネル]に移動し、[管理ツール]を選択して、[コンポーネント サービス]に進みます。

    2. [コンポーネント サービス] を展開します。 コンピューター フォルダーを開きます。 分散トランザクション コーディネーターを選択します。

    3. [DTC コーディネーター] を右クリックし、[プロパティ] を選択します。

    4. [セキュリティ] タブで、[ネットワーク DTC アクセス] および [受信を許可する] チェック ボックスをオンにします。

    5. [OK] クリックし、[はい] クリックして MSDTC サービスを再起動します。

    6. ダイアログ ボックスを閉じるには [OK] をクリックします。

  3. クライアント コンピューターで、送信ネットワーク トランザクションを許可するように MSDTC を構成します。

    1. の [スタート] メニューから、[Control Panel] に移動し、[管理ツール] し、[コンポーネント サービス] します。

    2. [マイ コンピューター] を右クリックし、[プロパティ]を選択します。

    3. [MSDTC] タブで、[セキュリティ構成] をクリックします。

    4. [ネットワーク DTC アクセス] および [送信を許可する] チェック ボックスをオンにします。

    5. [OK] クリックし、[はい] クリックして MSDTC サービスを再起動します。

    6. ダイアログ ボックスを閉じるには [OK] をクリックします。