I'm trying to finish some lightweight tasks after a controller has finished his work and I use HostingEnvironment.QueueBackgroundWorkItem()
for this.
I'm seeing a strange behavior, so I make an artificial proof-of-concept app for this.
in my global.asax.cs
I have this nice function:
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);
}
And in my controller I create a workitem and throw there:
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();
}
I see the message "TestWorkItem" in logs, but never "let's fail" and no message on error.
I also did HostingEnvironment.QueueBackgroundWorkItem((Func<CancellationToken,Task>)(_ => workItem));
to make sure the call is not ambiguous.
How do I fix this?
Your problem is that
TestWorkItem
is capturing the current request context, and attempting to resume on that request context after itsawait
. (I explain how this capture/resume works on my blog). Since the request has completed, the request context no longer exists by the time it attempts to resume.The best fix for this is to allow
QueueBackgroundWorkItem
to execute the code outside of a request context. So, first change your helper method to take aFunc<Task>
instead of aTask
:Then you can call it as such: