Asp.net mvc asp.net mvc 4.5:使HostingEnvironment.QueueBackgroundWorkItem正常工作

Asp.net mvc asp.net mvc 4.5:使HostingEnvironment.QueueBackgroundWorkItem正常工作,asp.net-mvc,asp.net-mvc-4,task-parallel-library,Asp.net Mvc,Asp.net Mvc 4,Task Parallel Library,我正在尝试在控制器完成工作后完成一些轻量级任务,为此我使用HostingEnvironment.QueueBackgroundWorkItem() 我看到一个奇怪的行为,所以我为此制作了一个人工概念验证应用程序 在我的global.asax.cs中,我有一个很好的函数: public class MvcApplication : HttpApplication { private static NLog.Logger logger = NLog.LogManager.GetCurrent

我正在尝试在控制器完成工作后完成一些轻量级任务,为此我使用
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”,但从未看到“let's fail”,也没有关于错误的消息

我还做了
HostingEnvironment.QueueBackgroundWorkItem((Func)(=>workItem))
以确保调用不含糊


如何解决此问题?

您的问题是,
TestWorkItem
正在捕获当前请求上下文,并试图在请求上下文的
等待后恢复该请求上下文。(我在博客上解释)。由于请求已完成,请求上下文在尝试恢复时不再存在

最好的解决方法是允许
QueueBackgroundWorkItem
在请求上下文之外执行代码。因此,首先将助手方法更改为使用
Func
而不是
任务

public static void ContinueWorkOnBackground(Func<Task> workItem)
{
  HostingEnvironment.QueueBackgroundWorkItem(async _ =>
  {
    try
    {
      await workItem();
    }
    catch (Exception ex)
    {
      logger.Error(ex);
    }
  });
}

NLog生存期是否以任何方式与请求相关联?另一方面,当
wait
可用时,最好不要使用
ContinueWith
。NLog在那里。我可以打开主页,看到它附加到日志中。在阅读了有关捕获上下文的内容后,我立即理解了它(但在几个小时之前,我在玩代码时未能理解)。谢谢
public ActionResult About()
{
  logger.Info("About");
  ViewBag.Message = "Your application description page.";
  MvcApplication.ContinueWorkOnBackground(() => TestWorkItem());
  return View();
}