2017-12-12 22 views
2

ASP.NET Web APIアプリケーションで非同期メソッドを使用すると、次のようなプログラムフローが発生します.APIコントローラが非同期メソッドを呼び出します(asyncMethod1)、これは2番目の非同期メソッドから何かを必要とします(asyncMethod2と呼ぶ)。 APIコントローラは、asyncMethod1がいつ終了するかを実際に知る必要はありませんが、ユーザーにフィードバックを与えるのはうれしいでしょう。 asyncMethod1は、asyncMethod2がいつ終了するかを知る必要があります。方法DoAsyncWork1DoAsyncWork2は両方とも非同期である、ASP.NET Web APIアプリケーション内の別のASP.NETメソッドから1つの非同期メソッドを呼び出す方法

public class MyController : ApiController 
{ 
    private CustomClass customClass; 

    public IHttpActionResult WorkMethod(TestObject testObject) 
    { 
     Debug.WriteLine("WorkMethod - before calling asyncMethod1"); 

     Task.Run(async() => await this.asyncMethod1(testObject)).Wait(); // ERROR HERE 

     Debug.WriteLine("WorkMethod - after calling asyncMethod1"); 

     return Ok(); 
    } 

    private async Task asyncMethod1(TestObject testObject) 
    { 
     Debug.WriteLine("asyncMethod1 - before calling asyncMethod2"); 

     Dictionary<string, string> x = await this.asyncMethod2(testObject); 

     Debug.WriteLine("asyncMethod1 - after calling asyncMethod2"); 

     try 
     { 
      using (Task<IList<TestResponse>> testTask = customClass.DoAsyncWork1(x)) 
      { 
       IList<TestResponse> response = await testTask; 

       // Do something with response 
       Debug.WriteLine("Transform 'response'"); 
      } 
     } 
     catch (Exception ex) 
     { 
      throw new Exception(" Exception ", ex); 
     } 
    } 

    private async Task<Dictionary<string, string>> asyncMethod2(TestObject testObject) 
    { 
     try 
     { 
      Debug.WriteLine("asyncMethod2 - before calling DoAsyncWork2"); 

      using (Task<IList<SomeData>> workTask = customClass.DoAsyncWork2(testObject.x)) 
      { 
       IList<SomeData> data = await workTask ; 

       var output = new Dictionary<string, string>(); 
       output = data.values; 

       Debug.WriteLine("asyncMethod2 - returning data to caller"); 

       return output; 
      } 
     } 
     catch (Exception ex) 
     { 
      throw new Exception(" Exception ", ex); 
     } 
    } 
} 

CustomClassは、私が使用していたカスタムAPIのクラスです:

は、ここで関連するコードです。

実行上記のコードは、私はラインTask.Run(async() => await this.asyncMethod1(testObject)).Wait();、WorkMethod方法で、次の例外を取得:

"メッセージ": "エラーが発生しました。"、 "ExceptionMessage": "一つ以上をエラーが発生しました。 "、" ExceptionType ":" System.AggregateException "、" StackTrace ":"
System.Threading.Tasks.Task.WaitでSystem.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
(Int32 millisecondsTimeout 、CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at MyCont MyController.cs内のroller.WorkMethod(Test testObject):9行目
、lambda_method(Closure、Object、Object [])
、System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutorにあります。 <> c__DisplayClass10.b__9(Object instance、Object [] methodParameters)
(System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance、Object [] arguments)
(System.Web.Http.Controlers.ReflectedHttpActionDescriptor) ExecuteAsync(HttpControllerContext controllerContext、IDictionary`2引数、CancellationToken cancellationToken)

、出力は以下の通りです:asyncMethod2
asyncMethod2を呼び出す前に - - asyncMethod1 asyncMethod1
を呼び出す前に

WorkMethod -

Task.Run(async() => await this.asyncMethod1(asyncMethod1)).Wait(); 

これまで:

var task = this.asyncMethod1(asyncMethod1); 

Debug.WriteLine("WorkMethod - after calling asyncMethod1"); 

task.wait(); 

Iドン -
asyncMethod1を呼び出し元にデータを返す - DoAsyncWork2
asyncMethod2を呼び出す前にこの方法では、asyncMethod2

の場合を呼び出した後、私はこの変更WorkMethod例外は発生しますが、プログラムの流れは決してasyncMethod1になりません。応答の返信はasyncMethod2から返されました。また、出力は以下の通りです:

WorkMethod - asyncMethod1
asyncMethod1を呼び出す前に - DoAsyncWork2
WorkMethodを呼び出す前に - - 問題はここに何が

asyncMethod1

を呼び出した後asyncMethod2
asyncMethod2を呼び出す前に?私が達成しようとしている、つまりAPIコントローラから非同期メソッドを呼び出して、最初のメソッドから2番目の非同期メソッドを呼び出す正しい方法は何ですか?あなたはあなたのコメントで言っ

+0

'Wait()'や '.Result'を使って非同期呼び出しをブロックしてはいけません。なぜ 'WorkMethod'は非同期ではありませんか? 'Task.Run()'ではどのような作業が行われますか?作業が特にIOバインドの場合、スレッドを無駄にしています。 – Crowcoder

+0

@Crowcoder非同期メソッドが非同期メソッドを呼び出す場所で見つかった例を除いて、私はそれに特に良い答えはありません。非同期メソッドを呼び出すメソッドも非同期であることは必須ですか?チェーン上のある点では、非同期メソッドが必要です。それらはすべて非同期であることはできません。あなたの2番目の質問については、Task.Run()はasyncMethod1を呼び出すことです。 – lukegf

+0

ウェブAPIでは、それを呼び出すクライアントに影響を与えないので、すべてを非同期にするのは簡単です。すべてを非同期にすることができない場合は、両方を混合するとリソースの非効率的な使用とデッドロックのリスクが発生するため、すべてを非同期にする方が良いです。私はそれが 'asyncMethod1'を呼び出していることを見ていますが、明らかにそれは偽造されていないので、私はあなたが実際にその方法でやっていることを知らない。 – Crowcoder

答えて

4

かの時点でアップチェーンを、あなたは は右、非非同期メソッドを持っている必要があります!

その答えはいいえです。すべてが非同期である可能性があります。あなたの行動としてこれを使うことができます:

public async Tack<IHttpActionResult> WorkMethod(TestObject testObject) 
{ 
    Debug.WriteLine("WorkMethod - before calling asyncMethod1"); 

    await this.asyncMethod1(testObject); 

    Debug.WriteLine("WorkMethod - after calling asyncMethod1"); 

    return Ok(); 
} 

このようにすると、その方法は無意味になります。実際の行動方法をasyncMethod1にすることができます。お望みならば。

実際に例外があるため、例外が表示されています。しかし、結果がawaitではなかったので、コレクション内で実際の例外を持つAggregateExceptionとしてスローされます。 awaitタスクを実行すると、実際の例外がスローされます。

+0

あなたは正しいです。実際の例外がスローされたことを確認できたら、問題は自分のコードではなく、CustomClassクラスが存在するカスタムAPIにあるとわかりました。それが修正されたら、物事はうまく始まりました。 – lukegf

関連する問題