我们的Web API控制器如下所示:
public class HomeController : ApiController
{
Logger logger = new Logger();
[HttpGet, Route("")]
public IHttpActionResult Index()
{
logger.Info("Some info logging");
return Ok();
}
}
在内部,我们的记录器使用HttpClient
到POST
数据到Azure事件中心。这意味着记录器具有一个内部调用异步方法的同步方法。
当我们的记录器具有带async void
签名的私有方法时,如下所示:
public class Logger
{
public void Info(string message)
{
LogAsync(message);
}
private async void LogAsync(string message)
{
await PostAsync(message);
}
}
我们看到以下错误:
如果我们更改记录器以使用这样的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
答案 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运行时中的情况。