2017-12-12 12 views
2

ASP.NET 웹 API 응용 프로그램에서 비동기 메서드로 다음과 같은 프로그램 흐름이 있습니다. API 컨트롤러에서 비동기 메서드를 호출합니다 (이라고 부름). asyncMethod1), 두 번째 비동기 메소드 (무언가를 asyncMethod2)로 가져와야합니다. API 컨트롤러는 asyncMethod1이 끝나는 시점을 알 필요가 없지만 사용자 피드백을 제공하는 것이 좋습니다. asyncMethod1은 asyncMethod2가 끝나는 시점을 알아야합니다. 방법 DoAsyncWork1DoAsyncWork2 모두 비동기 것을 특징으로ASP.NET 웹 API 응용 프로그램에서 하나의 비동기 메서드를 호출하는 방법

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의 클래스입니다 :

여기에 관련 코드입니다.

는 실행 위의 코드는, 나는 방법 에서 다음과 같은 예외가 WorkMethod받을 때, 라인 Task.Run(async() => await this.asyncMethod1(testObject)).Wait(); :

"메시지": "오류가 발생했습니다.", "ExceptionMessage": "하나 이상의 오류가 발생했습니다. ","ExceptionType ":"System.AggregateException ","StackTrace ":"
System.Threading.Tasks.Task.Wait에서 System.Threading.Tasks.Task.ThrowIfExceptional (부울 includeTaskCanceledExceptions)
(Int32 millisecondsTimeout , 취소 토큰 취소 토큰)
at System.Threading.Tasks.Task.Wait()
at MyCont roller.WorkMethod (Test testObject) in MyController.cs : lambda_method (Closure, Object, Object [])의 행 9

at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor. <> c__DisplayClass10.b__9 (Object instance, Object [] methodParameters)
, System.Web.Http.Controllers.ReflectedHttpActionDescriptor에서 System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute (Object 인스턴스, Object [] 인수)의
에 있습니다. 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에서 반환되었습니다.- asyncMethod1
asyncMethod1를 호출하기 전에 - DoAsyncWork2
WorkMethod를 호출하기 전에 - - asyncMethod2
asyncMethod2를 호출하기 전에

문제가 여기에 무엇 asyncMethod1

를 호출 한 후

WorkMethod : 또한, 출력은 다음과 같다? 달성하려고하는 올바른 방법은 무엇입니까? 즉 API 컨트롤러에서 비동기 메서드를 호출 한 다음 첫 번째 비동기 메서드를 두 번째 호출합니다.

+0

'Wait()'또는'.Result'로 비동기 호출을 차단해서는 안됩니다. 왜'WorkMethod' 비동기가 아닌가? 'Task.Run()'에서 어떤 작업이 완료 될까요? 작업이 IO 바인딩 인 경우 스레드를 낭비하고 있습니다. – Crowcoder

+0

@Crowcoder 비동기 메서드가 비동기 메서드를 호출하는 곳에서 찾은 예제를 제외하고는 특히 좋은 답변이 없습니다. 비동기 메서드를 호출하는 메서드가 반드시 비동기가되어야합니까? 어떤 점에서 체인을 따라 비동기 방식이 필요합니다. 맞습니까? 모두 비동기적일 수는 없습니다. 두 번째 질문에 대해서는 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이 아니기 때문에, InnerExceptions 컬렉션 안에 실제 예외가있는 AggregateException으로 던졌습니다. await 작업을 완료하면 실제 예외가 표시됩니다.

+0

정확합니다. 실제 예외가 표시되면 클래스에 CustomClass 클래스가있는 사용자 정의 API에 문제가 있음을 알았습니다. 일단 그것이 고쳐지면 모든 것이 잘 작동하기 시작합니다. – lukegf