asp.net mvc 4.5:让HostingEnvironment.QueueBackgroundWorkItem工作

时间:2015-12-22 14:31:37

标签: 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.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));确保通话不明确。

我该如何解决这个问题?

1 个答案:

答案 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();
}