Web API中的async void vs async任务:异步操作仍处于待处理状态

时间:2016-12-06 16:53:15

标签: c# asp.net-web-api async-await

我们的Web API控制器如下所示:

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

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

        return Ok();
    }
}

在内部,我们的记录器使用HttpClientPOST数据到Azure事件中心。这意味着记录器具有一个内部调用异步方法的同步方法。

破坏的实施

当我们的记录器具有带async void签名的私有方法时,如下所示:

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

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

我们看到以下错误:

Yellow screen of death

工作实施

如果我们更改记录器以使用这样的async Task签名,则可以正常工作:

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

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

问题

在这两种情况下,我们的日志消息都会发送到Event Hub。我想知道为什么async Task允许控制器返回预期结果,而async void会产生InvalidOperationException

此外,有关从同步方法调用异步代码的最佳做法吗?

我在这里发布了一个示例解决方案: https://github.com/kevinkuszyk/async-task-vs-async-void-sample

2 个答案:

答案 0 :(得分:1)

对这种方法的优点进行判断,对实际问题的回答是this question的答案。

在保持使用模式的同时,有多种方法可以修复它:

  • await
  • 中不要LogAsync()
  • 使用Task.Run(() => LogAsync());

答案 1 :(得分:-1)

如果同时调用async方法,请按以下方式调用:

async Task MyMethod()
{
   ...
}

public void WaitOnTask()
{
  var resultTask = MyMethod();
  resultTask.GetAwaiter().GetResult();
}
应该避免使用

async void,因为没有什么能阻止方法立即返回,并且当调用程序不期望在没有异步进程完成的情况下返回该方法时,这会导致问题,如ASP.NET运行时中的情况。