【发布时间】:2016-12-06 16:53:14
【问题描述】:
我们有如下所示的 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);
}
}
问题
在这两种情况下,我们的日志消息都会发送到事件中心。我想知道为什么async Task 允许控制器返回预期结果,而async void 导致InvalidOperationException?
另外,有没有关于从同步方法调用异步代码的最佳实践?
我在这里发布了一个示例解决方案: https://github.com/kevinkuszyk/async-task-vs-async-void-sample
【问题讨论】:
-
为什么你必须首先从同步方法中调用它?如果底层操作是异步的,则进行调用它的操作
async。这就是async存在的原因。 -
这两个实现都被破坏了。一个告诉你它坏了,所以你可以修复它,另一个只是不工作,没有告诉你它不工作,所以你没有意识到它不工作。
-
@MichaelCoxon 返回一个你刚刚扔到地板上的任务并没有更好的。它仅在消费者实际使用它来确定操作何时完成时才有用。
-
@KevinKuszyk:
"It needs to be synchronous so that consuming code can log and move on."- 我并不完全遵循那里的推理。如果操作宣传自己是同步的,那么消费代码将期望等待它完成。试图隐藏异步操作听起来像是在尝试一种“一劳永逸”的方法。但是该方法的“忘记”部分意味着您不在乎操作是否成功。那么为什么首先要处理错误呢?
标签: c# asp.net-web-api async-await