简体   繁体   中英

async void vs async task in Web API: an asynchronous operation was still pending

We have Web API controllers that look like this:

public class HomeController : ApiController
{
    Logger logger = new Logger();

    [HttpGet, Route("")]
    public IHttpActionResult Index()
    {
        logger.Info("Some info logging");

        return Ok();
    }
}

Internally, our loggers use the HttpClient to POST data to an Azure Event Hub. This means that the logger has a synchronous method which internally calls an asynchronous method.

The broken implementation

When our logger has a private method with an async void signature like this:

public class Logger
{
    public void Info(string message)
    {
        LogAsync(message);
    }

    private async void LogAsync(string message)
    {
        await PostAsync(message);
    }
}

We see the following error:

死亡黄屏

The working implementation

If we change our logger to use an async Task signature like this it works:

public class Logger
{
    public void Info(string message)
    {
        LogAsync(message);
    }

    private async Task LogAsync(string message)
    {
        await PostAsync(message);
    }
}

The question

In both cases our logging messages are sent to the Event Hub. I'd like to know why async Task allows the controller to return the expected result, and async void results in an InvalidOperationException ?

Also, is there any best practice regarding calling into asynchronous code from a synchronous method?

I've posted a sample solution here: https://github.com/kevinkuszyk/async-task-vs-async-void-sample

Avoiding judgement on the merits of this approach, the answer to your actual question is in the answer to this question .

There are various ways you could fix it while maintaining that usage pattern:

  • Don't await in LogAsync()
  • Use Task.Run(() => LogAsync());

If you call an async method synchronously call it as follows:

async Task MyMethod()
{
   ...
}

public void WaitOnTask()
{
  var resultTask = MyMethod();
  resultTask.GetAwaiter().GetResult();
}

async void should be avoided because there is nothing stopping the method returning immediately and this causes problems when the caller is not expecting the method to return without the asynchronous process completing as is the case in the ASP.NET runtime.

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