2012-11-24 30 views
97

サービスバスにasync/awaitを統合しようとしています。 http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspxに基づいてSingleThreadSynchronizationContextを実装しました。TransactionScopeをasync/awaitと連携させる

そして、1つのことを除いて正常に動作します:TransactionScope。私はTransactionScopeの中のものを待っていて、TransactionScopeを壊します。

TransactionScopeasync/awaitでは、ThreadStaticAttributeを使用してスレッドに何かを格納しているので、うまくいきません。

"TransactionScopeが正しくネストされていません。"

私は、タスクをキューに入れて実行する前にデータを保存しようとしましたが、動作を変更するようには見えません。 TransactionScopeコードは混乱しているので、そこで何が起こっているのかを理解することは本当に難しいです。

これを機能させる方法はありますか? TransactionScopeの代替手段はありますか?

+0

はのTransactionScopeのエラーを再現するために非常に簡単なコードであるhttp://pastebin.com/Eh1dxG4aここで例外がトランザクション – Yann

+0

を中止されたことを除いて、あなたは、通常のSQLトランザクションを使用するだけでNITことはできますか?または、複数のリソースにまたがっていますか? –

+0

私は複数のリソースにまたがっています – Yann

答えて

6

あなたはTransaction.DependentClone()方法により作成されたDependentTransaction使用することができます:.NET Frameworkの4.5.1で

static void Main(string[] args) 
{ 
    // ... 

    for (int i = 0; i < 10; i++) 
    { 

    var dtx = Transaction.Current.DependentClone(
     DependentCloneOption.BlockCommitUntilComplete); 

    tasks[i] = TestStuff(dtx); 
    } 

    //... 
} 


static async Task TestStuff(DependentTransaction dtx) 
{ 
    using (var ts = new TransactionScope(dtx)) 
    { 
     // do transactional stuff 

     ts.Complete(); 
    } 
    dtx.Complete(); 
} 

Managing Concurrency with DependentTransaction

http://adamprescott.net/2012/10/04/transactionscope-in-multi-threaded-applications/

+1

Adam Prescottの子タスクの例が非同期とマークされていませんでした。 'do transactional stuff 'を' await Task.Delay(500) 'に置き換えると、最も外側のTransactionScope(上の例には示されていません)が子タスクの前にスコープを正しく終了するため、このパターンは' TransactionScope nested incorrectly'でも失敗します完了する。 'await'を' Task.Wait() 'に置き換えると動作しますが、' async'のメリットが失われてしまいます。 – mdisibio

+0

これは問題を解決するためのより難しい方法です。 TransactionScopeはすべての配管を隠すことです。 – Eniola

138

を、TransactionScopeAsyncFlowOptionを取るnew constructors for TransactionScopeのセットがありますパラメータ。

MSDNによれば、それはスレッド継続の間のトランザクションフローを可能にします。

// transaction scope 
using (var scope = new TransactionScope(... , 
    TransactionScopeAsyncFlowOption.Enabled)) 
{ 
    // connection 
    using (var connection = new SqlConnection(_connectionString)) 
    { 
    // open connection asynchronously 
    await connection.OpenAsync(); 

    using (var command = connection.CreateCommand()) 
    { 
     command.CommandText = ...; 

     // run command asynchronously 
     using (var dataReader = await command.ExecuteReaderAsync()) 
     { 
     while (dataReader.Read()) 
     { 
      ... 
     } 
     } 
    } 
    } 
    scope.Complete(); 
} 
9

ビット後半の答えのために私はMVC4と同じ問題を抱えていたと私は4.5から4.5に私のプロジェクトを更新:

私の理解では、あなたがこのようなコードを書くことができるように意図されていることです.1プロジェクトを右クリックしてプロパティに移動します。アプリケーションタブを選択してターゲットフレームワークを4.5.1に変更し、トランザクションを以下のように使用します。

using (AccountServiceClient client = new AccountServiceClient()) 
using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) 
{ 
} 
ここ