2016-06-16 9 views
2

私のベースリポジトリクラスを非同期にしようとしていますが、何か問題があります。私はC#アプリケーションでDapper ORMを使用しています。非同期/待機のメインスレッドをブロックします

基本法

protected async Task<List<T>> Read<T>(CommandDefinition cmd) { 
    using(SqlConnection myCon = new SqlConnection(Config.DBConnection)) { 
     await myCon.OpenAsync(); 

     IEnumerable<T> results = await myCon.QueryAsync<T>(cmd); 

     List<T> retVal = results.ToList(); 

     myCon.Close(); 

     return retVal; 
    } 
} 

呼び出す方法

public List<Category> GetAllActiveCategories(Guid siteGuid) { 
    return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid).Result; 
} 

すべてが私のために見えます。私はasyncキーワードで装飾されたメソッド宣言を持っています。私は非同期メソッドを待っています。

私が抱えている問題は、スレッドがブロックすることです。await myCon.OpenAsync();です。これはasyncとawaitを使用する私の最初の試みです。だから私は何か間違っていると確信していますが、それは明らかではありません。助けてください!

+0

@KirillShlenskiy私はあなたが何かにいると思います。使用している方法のうちの1つを表示するようにほとんど編集します。これは、それをブロックしています。 – fizch

+0

あなたは消費側を投稿したので、私は自信があります。私のコメントを答えとして返す。 –

答えて

3

投稿コードは正常です。問題はコードを消費することにあります。 Taskまたはその前件のTaskがコールチェーンで呼び出されたときにまたはResultを呼び出した場合、デッドロックはasyncとなるのが一般的です。

いつものように、一般的なアドバイスはdon't block on async codeです。 async/awaitを使用し始めると、コールチェーン全体でasync/awaitを使用する必要があります。

だから、あなたの呼び出し方法は

public Task<List<Category>> GetAllActiveCategoriesAsync(Guid siteGuid) { 
    return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid); 
} 

...または

public async Task<List<Category>> GetAllActiveCategoriesAsync(Guid siteGuid) { 
    List<Category> result = await base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid); 

    // Do something. 

    return result; 
} 
+0

私の唯一の質問は、ブロックすることなくトップレベルの結果にどうやってアクセスするのですか? – fizch

+1

@fizch、残念ながら、asyncはコードを "中毒"させる方法を持っています。*チェーン全体を '非同期である。もちろん、同期呼び出しチェーンを使用している場合、特定のケースでは常に旧式のブロッキングメソッドを使用できます。代わりに 'Read'メソッドの中で待たれている全ての' Task'sに対して 'ConfigureAwait(false)'を使って問題を解決できますが、これはベストプラクティスですが意図的に 'Task'sをブロックすることは反パターンを避けるべきである。 –

+0

しかし、私はもはや元の質問に答えたので、私は逃げ出す。 –

1

犯人は次のようになります。

return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid).Result; 

キリルは、あなたが.Wait().Resultを使用し、いつでも述べたようにタスクでは、同期してブロックしています。

public Task<List<Category>> GetAllActiveCategories(Guid siteGuid) { 
    return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid); 
} 

これはの呼び出し方法この方法にタスクを返します、のように...それが「までのすべての道」非同期である必要があります。何をする必要があると、これはあります。

このコードの最上位コンシューマがASP.NETの場合は、問題ありません。 Task<IActionResult>(またはタスクにラップされた適切な戻り値の型)を返すだけで、フレームワークはawaitを並べ替えます。

コンソールアプリケーションを書いている場合、またはそれ以外の場合は、それが「までのすべての方法非同期(async)」、あなたは.Result上のブロックのいずれかに持っているか、あなたの方法async voidを作成し、awaitを使用しますことはできません。どちらも、悲しいことに、素晴らしい解決策ではありません。 Async/awaitは、スタック全体で本当に使用しなければならないという意味ではかなり積極的です。

+0

@fizch少し説明が追加されました。キリルの答え(とリンク)も良い情報です! –

関連する問題