Using Task.Run in a syncronous asp.net controller

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-23 05:13:21

问题


Is there an efficient way to download a file and save it on disk in a "background" way without blocking the current execution of an action in a mvc controller?

Currently I have the following example code working:

    public ActionResult Index()
    {
        InitiateDownload();

        var model = GetModel();
        return View(model);
    }

    private void InitiateDownload()
    {
        Task.Run(() => DownloadAndSaveFileAsync()).ConfigureAwait(false);
    }
    private async Task DownloadAndSaveFileAsync()
    {
        var response = await GetResponse();

        using (var fileStream = new FileStream("c:\\file.zip", FileMode.Create, FileAccess.Write, FileShare.None))
        {
            await response.Content.CopyToAsync(fileStream).ConfigureAwait(false);
        }
    }
    public async Task<HttpResponseMessage> GetResponse()
    {
        var client = new HttpClient();
        client.BaseAddress = new Uri("http://someUrl.com");

        return await client.GetAsync("someResourceEndPoint").ConfigureAwait(false);
    }

I have read several places that you should not use Task.Run on the server (in the worker thread) so I was wondering if this example is scaleable (eg. if it receives 10 requests every second) or reliable or if there are any appropriate way to make it so?

Thanks


回答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 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.



来源:https://stackoverflow.com/questions/22709855/using-task-run-in-a-syncronous-asp-net-controller

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!