2016-04-06 16 views
2

は考える:非同期メソッドでこの同期ラッパーが機能するのはなぜですか?

  • ASP.NET/WCF Webサービス上のレガシー非非同期APIメソッドが
  • 新しい非同期内部ライブラリ
  • 使用する必要があります
  • 新しい非同期のWeb APIコントローラーは
  • 前進します非同期インターフェイスのみを持つ「ストレージプロバイダ」オブジェクト。そのテストは非同期に実行され、要求コンテキスト外で同期して実行されるときに渡されます。

「go async all way」オプションは、下位互換性を損なう可能性があるため、テーブルにはありません。

public class Impl { 
    // This works fine when used asynchronously 
    public Task<Guid> SaveThingAsync(Thing thingToSave) { 
     return await _storageProvider.saveAsync(thingToSave); 
    } 

    public Guid SaveThing(Thing thingToSave) { 
     // "Obviously", this code creates a deadlock when called 
     // from within the request context 
     // return SaveThingAsync(thingToSave).Result 

     // Not so obviously, this also creates a deadlock 
     // return SaveThingAsync(thingToSave) 
     //   .ConfigureAwait(false) 
     //   .GetAwaiter() 
     //   .GetResult() 

     // This was deadlocking, but magically stopped 
     // return Task.Run(
     //  async() => await SaveThingAsync(thingToSave) 
     //      .ConfigureAwait(false) 
     //    ).Result; 

     // This one works 
     var saveTask = Task.Run(async() => 
          await SaveThingAsync(thingToSave))); 
     var result = saveTask.ConfigureAwait(false).GetAwaiter().GetResult(); 
     return result; 
    } 

なぜですか?

答えて

1

Task.Run要求コンテキストの外側にあるステップ - スレッドプールコンテキストでのみ実行されます。したがって、SaveThingAsyncは要求コンテキストで再開しないため、デッドロックは発生しません。

awaitが設定されていないため、ここではConfigureAwait(false)は意味がありません。

もう一つの注意点として、「async all way」は引き続きオプションになるはずです。 WebAPIとWCFクライアントは、実装している実装が同期か非同期かを気にしません。非同期に実装されたWCFメソッドに同期して実装されたWCFメソッドを変更することは、クライアントコードには見えません。

+0

これは迷惑です。昨日、最初の 'Task.Run'の例を実行するときにTaskCancelled例外が発生しました。クライアントは直接サービス参照だけでなく、インタフェースから生成されたクライアントライブラリを使用するので、SOAPインタフェースを変更するとすべてが損なわれます。 – Eris

+0

@ErisクライアントはStephenとして言及できません。これは互換性の問題ではありません。これはここで説明されています:http://stackoverflow.com/a/22591516/122718 – usr

+0

@Eris:最初の(コメントアウトされた) 'Task.Run'の例は本当に、本当に奇妙です。それは私の脳を曲げて、それが何をするのか理解しようとしています。 'ConfiguredTaskAwaitable'構造を渡すことは慣習的ではありません。クライアントが消費する同期インタフェースではなく、独自の(非同期の)インタフェースをサーバで使用できるはずです。残念ながら、これは(論理的に)インタフェース記述を複製します。 –

関連する問題