在控制器完成工作后,我试图完成一些轻量级任务,我使用HostingEnvironment.QueueBackgroundWorkItem()
。
我看到了一个奇怪的行为,所以我为此制作了一个人工的概念验证应用程序。
在我的global.asax.cs
我有这个很好的功能:
public class MvcApplication : HttpApplication
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
public static void ContinueWorkOnBackground(Task workItem)
{
workItem.ContinueWith(t =>
{
if (t.IsFaulted)
{
var ex = t.Exception;
logger.Error(ex);
}
});
HostingEnvironment.QueueBackgroundWorkItem(_ => workItem);
}
在我的控制器中,我创建了一个工作项并扔到那里:
public ActionResult About()
{
logger.Info("About");
ViewBag.Message = "Your application description page.";
MvcApplication.ContinueWorkOnBackground(TestWorkItem());
return View();
}
private async Task TestWorkItem()
{
logger.Trace("TestWorkItem");
await Task.Delay(500);
logger.Trace("let's fail");
throw new NotImplementedException();
}
我看到了消息" TestWorkItem"在日志中,但从来没有"让我们失败"并且没有错误消息。
我也HostingEnvironment.QueueBackgroundWorkItem((Func<CancellationToken,Task>)(_ => workItem));
确保通话不明确。
我该如何解决这个问题?
答案 0 :(得分:3)
您的问题是TestWorkItem
正在捕获当前请求上下文,并尝试在await
后的请求上下文中继续。 (我在我的博客上解释how this capture/resume works)。由于请求已完成,因此请求上下文在尝试恢复时不再存在。
最好的解决方法是允许QueueBackgroundWorkItem
在请求上下文之外执行代码。因此,首先更改您的帮助方法,以取Func<Task>
而不是Task
:
public static void ContinueWorkOnBackground(Func<Task> workItem)
{
HostingEnvironment.QueueBackgroundWorkItem(async _ =>
{
try
{
await workItem();
}
catch (Exception ex)
{
logger.Error(ex);
}
});
}
然后你可以这样称呼它:
public ActionResult About()
{
logger.Info("About");
ViewBag.Message = "Your application description page.";
MvcApplication.ContinueWorkOnBackground(() => TestWorkItem());
return View();
}