Using Task.Run in a syncronous asp.net controller

Solution 1:

without blocking the current execution of an action in a mvc controller?

The answer depends on exactly what you mean by this.

If you mean allowing you to build the model while the download is in progress, then you can do it rather simply as such:

public async Task<ActionResult> Index()
{
    var task = DownloadAndSaveFileAsync();
    var model = GetModel();
    await task;
    return View(model);
}

However, if you mean that you want to return a response to the client without waiting for the download, then that's much more complicated. I have a blog post that goes into more detail on the subject. If you do want to return a response before the work is done, then you need to decide how important that work is to you.

If you need the download to happen, then you'll need to put the download request in a reliable queue (e.g., Azure queue or MSMQ) and have an independent backend (e.g., Azure worker role or Win32 service) doing the actual downloading and saving.

If it's not as important to have the downloads complete - i.e., your system can handle the occasional missing download - then you can use the BackgroundTaskManager type from my blog post above:

private void InitiateDownload()
{
  BackgroundTaskManager.Run(() => DownloadAndSaveFileAsync());
}

I also recommend you use the BackgroundTaskManager.Shutdown cancellation token to respond appropriately when the AppDomain is being shut down before the download completes (e.g., write a message to the event log).


Whichever solution you choose, you should change DownloadAndSaveFileAsync to open the file stream for asynchronous access. This is a common mistake with file streams; by default they are synchronous.