简体   繁体   中英

How to call one async method from another one in ASP.NET Web API application

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, ie call an async method from an API controller and then call a second async method from the first one?

You said in your comment:

At some point up the chain, you have to have a non-async method, right?!

The answer to that is no. Everything can be async. So you can have this as your action:

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();
}

Then doing that kind of makes that method pointless. You can make your asyncMethod1 the actual action method. If you want.

That said, the exception you were getting is because there is actually an exception. But because you weren't await ing the result, it gets thrown as an AggregateException with the real exception inside the InnerExceptions collection. Once you await the task, you'll see the real exception thrown.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM