TransactionScopeにより、2番目のサービスエラーが発生しても部分的な更新が可能

StackOverflow https://stackoverflow.com/questions/1802426

質問

関連する質問と実装された提案をうまく調べましたが、.NET TransactionScopeにはまだ問題があります。

メソッドから2つのWCFサービスを呼び出していますが、2番目のサービス(この場合は意図的に)でエラーが発生しても、最初のサービスはロールバックしません。問題を実証する簡単なテストアプリケーションを作成しました。

呼び出しメソッドは次のとおりです。

private void TryATransaction()
{
    ServiceReference1.IService1 service = new ServiceReference1.Service1Client();
    ServiceReference2.IService1 service2 = new ServiceReference2.Service1Client();

    using (TransactionScope scope = new TransactionScope())
    {
        service.TestMethod("one");
        service2.UpdateSomethingElse("two");

        scope.Complete();
    }
}

最初のサービスは次のようになります(接続は匿名になります):

public bool TestMethod(string anything)
{
        using (TransactionScope scope = new TransactionScope())
        {

            // connect to a db
            using (SqlConnection connection = new SqlConnection("Data Source=DATASOURCE;Initial Catalog=DATABASE;Integrated Security=SSPI;Transaction Binding=Explicit Unbind;"))
            {

                connection.Open();
                // save something
                SqlCommand command1 = new SqlCommand("EXECUTE [DATABASE].[dbo].[uspUpdateCustomer] 3, 'test@test.com', 1, null", connection);
                command1.ExecuteNonQuery();
                connection.Close();

            }

            scope.Complete();
        }

    return true;
}

2番目のサービスは、データベースの別のフィールドを更新することを除いて、最初のサービスと同じです。

1)エラーを強制せずにこれを実行すると、すべてのフィールドが正常に更新されます。

2)これを実行して2番目のサービスでエラーを強制すると、最初のサービスからの更新がデータベースにコミットされますが、2番目のサービスはロールバックされます(エラーはExecuteNonQueryステートメントの後です)。

このサンプルコードは、基本的にここにあるサンプルに従います。 http://msdn.microsoft.com/en-us/ library / system.transactions.transactionscope.aspx

そして、明示的なバインド解除を追加しました。これは、他の関連する質問で推奨されました。

ご提案は大歓迎です-必要に応じて詳細を追加できます。

追加情報

配布された識別子は常に00000000-0000-0000-0000-000000000000のようです-これが手掛かりかどうかわかりません。

これは、分散IDとローカルIDのdubug出力です(この順序で)

  

現在のトランザクションは   00000000-0000-0000-0000-000000000000-   f6446876-496d-488c-a21c-1e4c4295d50c:8

     

現在のトランザクションは   00000000-0000-0000-0000-000000000000-   7edd5ba3-7f5a-42af-b9ca-37b3862c26a7:2

     

現在のトランザクションは   00000000-0000-0000-0000-000000000000-   6fa0e3f7-b655-40ad-8bdd-f0670de79a49:2

トランザクションは、サンプルアプリのaspxページの背後にあるコードを介して開始されています。

役に立ちましたか?

解決

編集:後方に物事がありました。

ほとんどの場合、問題はWCFとともにトランザクションを使用していることが原因です。

トランザクションサービスに関するこちらの記事をご覧ください。特に、クライアント/サービスモードトランザクションに関する部分。

基本的に必要なこと:

  • OperationContractインターフェイスメソッドで [TransactionFlow(TransactionFlowOption.Mandatory)] 属性を設定します
  • 実装に [OperationBehavior(TransactionScopeRequired = true)] 属性を設定します
  • TransactionFlowBindingElement をサービスのBindingContextに追加します
  • クライアントのTransactionScopeを使用しているため、サービスの実装から TransactionScope を削除します。

正常に完了した各サービスメソッドは、トランザクションが成功するよう投票します(デフォルトのTransactionAutoComplete = true OperationBehaviorを使用している場合)。

例外のためにサービスメソッドが失敗した場合、トランザクションが失敗したと投票します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top