「正しい方法」を引用符で囲んだのは、非同期 API を使用する正しい方法は、非同期動作を呼び出しチェーン全体に伝播させることだということをすでによく理解しているからです。ここではそれは選択肢ではありません。
私はループ内で同期的にバッチ処理を実行するように特別に設計された、非常に大規模で複雑なシステムを扱っています。
突然 HttpClient を使用するようになった理由は、これまではバッチ処理のすべてのデータが SQL データベースから収集されていたのに、今は Web API 呼び出しが追加されているからです。
はい、同期実行ループで Web API を呼び出しています。わかっています。全体を非同期に書き直すのは選択肢ではありません。これが実際にやりたいことです。(API 呼び出しの数を可能な限り最小限に抑えています)
私は実はした非同期動作を呼び出しチェーンに伝播しようとしましたが、変更が 50 個のファイルまで及んでいて、解決すべきコンパイラ エラーが数百個残っていることに気づき、すべての希望を失いました。私は敗北しました。
それで、質問に戻りますが、Microsoft は新しい開発には WebRequest を使用せず、代わりに非同期 API のみを提供する HttpClient を使用することを推奨していますが、どうすればよいでしょうか?
私がやっていることの疑似コードを以下に示します。
foreach (var thingToProcess in thingsToProcess)
{
thingToProcess.ProcessStuff(); // This makes an API call
}
ProcessStuff() を実装するにはどうすればいいですか?
私の最初の実装は次のようになりました
public void ProcessStuff()
{
var apiResponse = myHttpClient // this is an instance of HttpClient
.GetAsync(someUrl)
.Result;
// do some stuff with the apiResponse
}
ただし、この方法で .Result を呼び出すと、同期コンテキストが原因で ASP.NET などから呼び出されたときにデッドロックが発生する可能性があると言われました。
なんと、このバッチ プロセスは ASP.NET コントローラーから開始されます。はい、繰り返しますが、これは馬鹿げた話だとわかっています。ASP.NET から実行すると、バッチ全体ではなく 1 つの項目だけが「バッチ処理」されますが、話がそれますが、それでも ASP.NET から呼び出されるため、デッドロックが心配です。
では、これを処理するための「正しい方法」は何でしょうか?
ベストアンサー1
次のことを試してください。
var task = Task.Run(() => myHttpClient.GetAsync(someUrl));
task.Wait();
var response = task.Result;
メソッドを使用できない場合にのみ使用してくださいasync
。
この方法は、MSDN ブログで述べられているように、完全にデッドロックフリーです。ASP.Net – メイン コンテキストで Task .Result を使用しない。