Starting with the recently released version 4.5.2 of the .NET Framework, ASP.NET now supports the
HostingEnvironment.QueueBackgroundWorkItem method found in the
System.Web.Hosting namespace. I want to quickly show you how you can use it to schedule background work items in an ASP.NET MVC application.
In the release notes, the
QueueBackgroundWorkItem method is summarized as follows:
HostingEnvironment.QueueBackgroundWorkItemmethod lets you schedule small background work items. ASP.NET tracks these items and prevents IIS from abruptly terminating the worker process until all background work items have completed.
The summary (emphasis mine) highlights the reason for using
QueueBackgroundWorkItem: You won't have to worry about processes being shut down prematurely by IIS.
QueueBackgroundWorkItem can only be called inside an ASP.NET managed app domain. It won't work if the runtime host is either Internet Explorer or some Windows shell. For more information on app domains, please refer to Using Application Domains.
Basic Usage of the
QueueBackgroundWorkItem method defines two overloads, each of which accepts a single parameter. You can pass either of the following delegate types:
Here's how you could pass a lambda expression to the first overload:
// Some long-running job
The lambda can even be
async so that you can use all the goodness
await has to offer:
HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken =>
var result = await LongRunningMethodAsync();
// Do something with result
Passing a method group to the overload accepting a
Func is possible as well:
private void QueueWorkItem()
Func<CancellationToken, Task> workItem = LongRunningMethodAsync;
private async Task LongRunningMethodAsync(CancellationToken cancellationToken)
// Some long-running job
Due to the way that the C# compiler does method group conversion, it's not possible to pass
LongRunningMethodAsync directly to
QueueBackgroundWorkItem. The issue is that the compiler utilizes overload resolution when converting the method group, and overload resolution doesn't take into account return types.
Func overloads accept a single parameter of type
CancellationToken, there's no way to distinguish the two method calls just by looking at their parameter types. The assignment to the
workItem variable provides the compiler with that missing type information. For more detail, make sure to read this great StackOverflow answer from Eric Lippert Himself™.
Posting to a Remote API from an ASP.NET MVC Controller
Here's a more complete example of how
QueueBackgroundWorkItem can be used in an ASP.NET MVC controller. After creating some
Foo model, the controller registers a background work item which makes a (potentially) long-running call to a remote API:
public class FooController : Controller
public ActionResult Create(FooInputModel input)
// Process the input somehow
Action<CancellationToken> workItem = PostToRemoteService;
private async void PostToRemoteService(CancellationToken cancellationToken)
using (var client = new HttpClient())
var response = await client.PostAsync("https://example.com/endpoint",
new StringContent("..."), cancellationToken);
// Do something with response
// More action methods
That way, the controller can return an
ActionResult (in this case, a view) after the input has been processed. It doesn't have to wait until the HTTP request to the remote API has been made and a response is returned.
Of course, you can call the
QueueBackgroundWorkItem method from other ASP.NET application types as well, it is in no way specific to MVC.
As you've seen, the new
QueueBackgroundWorkItem method is very easy to use with different delegate parameters. ASP.NET does the heavy lifting for us by preventing IIS from terminating worker processes when there are any pending background work items. Consequently,
HostingEnvironment.QueueBackgroundWorkItem is an ideal candidate for scheduling small background jobs in .NET 4.5.2.
For an overview of all the other new features that shipped with .NET 4.5.2, read the blog post from the .NET engineering team or the summary in the MSDN library: