这是我的问题:我需要在ApiController内调用多个第三方方法。这些方法的签名为Task DoSomethingAsync(SomeClass someData, SomeOtherClass moreData)
。我希望这些调用在ApiController将数据发送回客户端后继续在后台运行。当DoSomethingAsync
完成时,我想进行一些日志记录,可能还要保存一些数据到文件系统中。我该如何做?我更喜欢使用异步/等待语法。
这是我的问题:我需要在ApiController内调用多个第三方方法。这些方法的签名为Task DoSomethingAsync(SomeClass someData, SomeOtherClass moreData)
。我希望这些调用在ApiController将数据发送回客户端后继续在后台运行。当DoSomethingAsync
完成时,我想进行一些日志记录,可能还要保存一些数据到文件系统中。我该如何做?我更喜欢使用异步/等待语法。
好消息,.NET 4.5.2 中有一个被称为 QueueBackgroundWorkItem API 的新解决方案。它非常简单易用:
HostingEnvironment.QueueBackgroundWorkItem(ct => DoSomething(a, b, c));
这里有一篇详细描述的文章。
另外,这里还有另一篇文章提到了几种在此主题未提及的方法。 http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
QueueBackgroundWorkItem
在 .NET Core (.NET 5+) 中已经不存在。 - Sedat Kapanoglu你几乎从不想这样做。这几乎总是一个大错误。
ASP.NET(以及大多数其他服务器)的工作原理是,一旦所有请求完成,关闭服务是安全的。因此,您无法保证日志记录已完成,或者数据已写入磁盘。特别是对于磁盘写入,您的写入完全可能会损坏。
话虽如此,如果你绝对确定要实现这个极度危险的设计,可以使用BackgroundTaskManager
(来自我的博客)。
更新: 我已经写了一个博客系列,详细介绍了一个适合请求外代码的正确解决方案。简而言之,您真正想做的是将请求外代码移出 ASP.NET。引入可持久化队列和独立处理器;ASP.NET 控制器动作将一个请求放置到队列中,独立处理器将读取请求并执行它们。该“处理器”可以是 Azure Function/WebJob、Win32 Service 等。
Stephen解释了为什么在ApiController中启动基本上是长时间运行的fire-and-forget任务是一个坏主意。
也许你应该创建一个独立的服务来执行那些fire-and-forget任务。这个服务可以是不同的ApiController,一个队列后面的工作程序,任何可以单独托管并具有独立生命周期的东西。
这将使得管理不同任务生命周期更加容易,并且将长时间运行的任务的责任与ApiController的核心责任分离开来。
虽然这个问题已经几年了,但现在最好的解决方案是在这种情况下使用Signal R。
.ContinueWith
的东西,这是你可以进行日志记录的地方。 - T.S.