可以不等待Web API控制器

时间:2018-03-15 15:11:42

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

所以我遇到了一些让我感到不舒服的代码,但是我无法找到关于它是否真的有问题的明确答案。

我们有一个主要由消息总线使用的ASP.Net Web API。需要为多个帐户启动平衡过程。平衡服务方法是异步的并返回一个Task。代码的调用方式如下:

foreach (AccountingGroup accountingGroup in Groups)
{
    ledgerService.CreateItemsAsync(accountingGroup.GLAccountingHeaderId);
}
return StatusCode(HttpStatusCode.NoContent);

这在很多层面上让我感到错误。我明白了。 "我们希望在所有这些群组上运行此方法,但我们不需要等待它们完成。

显然,取消令人不被使用。他们依赖AWS只是为了杀死整个过程,如果它持续很长时间,并且这不是我现在可以真正进入的重构。

我已经退出C#一年半了,异步代码已经用了2。5年了,感觉我在某个时候知道这个问题,但我再也找不到了。< / p>

处理此问题的正确方法是什么?这甚至是个问题吗?

4 个答案:

答案 0 :(得分:3)

正确的方法是将API方法定义为异步,然后等待所有异步方法完成:

public Task<IHttpActionResult> DoStuff()
{
    await Task.WhenAll(groups.Select(g =>
                     ledgerService.CreateItemsAsync(g.GLAccountingHeaderId));
    return StatusCode(HttpStatusCode.NoContent);
}
帕特里克的答案解释了“为什么”。如果一个动作没有完成就假装给客户似乎是一个坏主意。

如果您想在后台运行这些内容,您可能会考虑使用像RabbitMq这样的消息队列,并开发一种确保完成这些任务的故障安全方法。事情失败时的反馈是好的。使用您当前的方法,您绝对无法确定此代码是否失败,这意味着如果它停止工作,您将无法实现,直到它影响其他内容。

答案 1 :(得分:3)

  

这甚至是个问题吗?

是的,不想等待它,实际上能够处理异常是有区别的。

例如,如果您的代码因任何原因失败,您现在返回HTTP 204,即成功状态。如果您要等待结果,但它失败了,您最有可能获得HTTP 500。

  

处理此问题的正确方法是什么?

您应该等待结果,例如汇总任务并在其上调用Task.WhenAll,这样您就不必分别等待每一项任务。

答案 2 :(得分:3)

不,不行,服务器可能会在后台运行时关闭应用程序域。处理此问题的最佳方法是使用库来进行后台工作,例如https://www.hangfire.io/

如果您认为工作将在下一分钟左右完成,您可以使用短期系统HostingEnvironment.QueueBackgroundWorkItem(Func<CancellationToken,Task>)但是我不确定这是否适用于ASP.NET Core,它的设计是与以前版本的ASP.NET一起使用。

编辑:找到一个引用,QueueBackgroundWorkItem确实在ASP.NET Core中不起作用,但有a similar way to handle these situations there

答案 3 :(得分:0)

您可以使用QueueBackgroundWorkItem

请查看Getting QueueBackgroundWorkItem to complete if the web page is closed