So I have the following program flow with async methods in an ASP.NET Web API application: an API controller calls an async method (let's call it asyncMethod1), which needs something from a second async method (let's call it asyncMethod2). The API controller doesn't really need to know when asyncMethod1 finishes, though it would be nice to in order to give the user feedback. asyncMethod1, on the hand, does need to know when asyncMethod2 finishes.
Here is the relevant code:
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 is a class in a custom API I am using, wherein methods DoAsyncWork1 and DoAsyncWork2 are both async.
When the code above runs, I get the following exception in method WorkMethod, line Task.Run(async () => await this.asyncMethod1(testObject)).Wait();:
"Message":"An error has occurred.","ExceptionMessage":"One or more errors occurred.","ExceptionType":"System.AggregateException","StackTrace":" at
System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at MyController.WorkMethod(Test testObject) in MyController.cs:line 9
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.b__9(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
And the output is the following:
WorkMethod - before calling asyncMethod1
asyncMethod1 - before calling asyncMethod2
asyncMethod2 - before calling DoAsyncWork2
asyncMethod2 - returning data to caller
asyncMethod1 - after calling asyncMethod2
If, in method WorkMethod I change this:
Task.Run(async () => await this.asyncMethod1(asyncMethod1)).Wait();
to this:
var task = this.asyncMethod1(asyncMethod1);
Debug.WriteLine("WorkMethod - after calling asyncMethod1");
task.wait();
I don't get an exception, but the program flow never gets to the point in asyncMethod1 where it does some work over the response returned from asyncMethod2. In addition, the output is the following:
WorkMethod - before calling asyncMethod1
asyncMethod1 - before calling asyncMethod2
asyncMethod2 - before calling DoAsyncWork2
WorkMethod - after calling asyncMethod1
What is the problem here? What is the correct way to do what I am trying to achieve, i.e. call an async method from an API controller and then call a second async method from the first one?
Wait()or.Result. Why isn'tWorkMethodasync? What work will be done inTask.Run()? You are wasting a thread if the work is IO bound especially.asyncMethod1but clearly it is not fleshed out so I don't know what you are going to actually do in that method.