none
プロセス間でトランザクションを管理したい RRS feed

  • 質問

  • プロセス間でトランザクションを管理したいと考えています。
    しかし、.NET Framework 4において標準的な方法が見つけられず、実現できない状態です。
    ご存知の方がいらっしゃれば、よい方法をご教示いただけないでしょうか。
    よろしくお願いします。

    詳細を下記します。

    利用局面

    IISでホストされるWCF WebサービスをVisual Studioユニットテストで呼び出す際の使用を想定しています。
    クライアント(VS ユニットテスト)から、データベース(以下DB)を更新するWCF Webサービスを呼び出します。
    このとき、テスト終了処理(TestCleanup)において更新されたDBをロールバックしたいと考えています。

    試行したこと

    MSDTCが目的の処理を実現するための鍵になると思って、System.Transactions.TransactionScope をクライアント・サーバーいずれにおいても利用してみました。
    擬似コードを下記します。

    // Client
    using(var scope = new TransactionScope())
    {
      server.UpdateDb();
    }
    
    // Server
    public void UpdateDb()
    {
      using(var scope = new TransactionScope())
      {
        db.Update();
        scope.Complete();
      }
    }
    

    しかし、事前に想像した通りこの単純な方法では分散トランザクションとならず、サーバー側におけるDBの変更はコミットされてしまいました。
    System.Transactions 名前空間の他のクラスの機能、例えばSystem.Transactions.TransactionのEnlist~などをMSDNライブラリーや検索エンジンでのエントリーで確認・調査してみましたが、文面や参考コードなどからは上記目的を実現するものは読み取れませんでした。これは、私の分散トランザクションに関する知識が浅いせいかもしれません。

    環境および制約

    開発環境は以下の通りです。

    • Windows 7 Ultimate x64 + IIS 7.5
    • .NET Framework 4
    • Visual Studio 2010 Ultimate
    • SQL Server 2008 Express Edition

    WCFはCustomBinding(HttpTransport + BinaryMessageEncoding)で構成しています。
    WSHttpBindingなど、WS-AtomicTransactionが利用できる(と考えています)通信はシステム想定環境から利用できません。

    ユニットテストなので、クライアントとサーバーは同一マシンという前提がとれます。DBも単一インスタンスの単一DBという前提が取れます。

    なお、単一プロセスでSystem.Transactions.TransactionScopeが動作していることは確認しています。

    2010年9月15日 18:25

すべての返信

  • WCF で分散トランザクションを行うなら、次の記事が参考になるかもしれません。

    http://msdn.microsoft.com/ja-jp/magazine/cc163432.aspx

    http://www.atmarkit.co.jp/fdotnet/wcf/wcf04/wcf04_02.html

     


    なかむら(http://d.hatena.ne.jp/griefworker)
    2010年9月15日 20:44
  • ご回答ありがとうございます。
    結論から先に申し上げますと、ご紹介いただいた記事の内容を適用するのは難しそうです。
    以下が理由になります。
    • WCFサービスのメソッド定義にトランザクション実現用の属性を付与しなければいけない。テストのみの用途なのでそれは回避したい。
    • トランザクションをサポートするためにWCFバインディングが限定される。一部の処理でHTTPに依存したコードを記述していて、テストの用途のみを目的とした改修は難しい。

    とはいえ、勉強になりました。ありがとうございました。
    他に何かあれば引き続きよろしくお願いします。

    2010年9月16日 3:38
  • 「WCF サービスを呼び出す、クライアント側で動くクラス」を単体テストしたいのでしょうか?

    その場合、サービス呼び出し部分をモックに差し替えるか、ダミーのWCFサービスを使って、対象クラスを単体テストしてはどうでしょうか。そうすればデータを壊すこともありませんし。

     

     

     


    なかむら(http://d.hatena.ne.jp/griefworker)
    2010年9月17日 0:26
  • ご回答ありがとうございます。

    > 「WCF サービスを呼び出す、クライアント側で動くクラス」を単体テストしたいのでしょうか?

    いえ、テストしたい対象はWCFサービス自体になります。WCFサービス内部で使用される個々のクラスは別個ユニットテストを実施していますが、それをまとめたものを改めてテストしたいという考えです。クライアントに対しての品質を保証したい意図です。

    DBのロールバックができないため、代替案としてテスト初期化-終了処理でバックアップ-レストアを実施してしのいでいます。これは処理速度に難点がありますが...

    2010年9月17日 0:52
  • 利用局面から推測するに、ユニットテスト後にデータベースを元に戻すことが目的なのでしょうか?

    それであれば、ユニットテストを行う前にデータベースを BACKUP して、終わったら RESTORE する、といった方式でも、大丈夫でしょうか?

    2010年10月1日 5:15
  • 利用局面から推測するに、ユニットテスト後にデータベースを元に戻すことが目的なのでしょうか?

    それであれば、ユニットテストを行う前にデータベースを BACKUP して、終わったら RESTORE する、といった方式でも、大丈夫でしょうか?

    ご回答ありがとうございます。目的はその通りです。データベースをバックアップ→レストアというのは前述の通り代替案として実施しています。

    ですが、処理速度の観点から少し難点があると考えていて、トランザクションのロールバックが利用できないものかと考えていた次第です。

    2010年10月4日 15:14