在同步的asp.net控制器中使用Task.Run

是否有一种有效的方法来下载文件并以“后台”方式将其保存在磁盘上,而不会阻止mvc控制器中当前执行的操作?

目前我有以下示例代码工作:

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 GetResponse() { var client = new HttpClient(); client.BaseAddress = new Uri("http://someUrl.com"); return await client.GetAsync("someResourceEndPoint").ConfigureAwait(false); } 

我已经阅读了几个你不应该在服务器上使用Task.Run的地方(在工作线程中)所以我想知道这个例子是否可扩展(例如,如果它每秒接收10个请求)或可靠或者是否有任何适当的这样做的方法呢?

谢谢

不阻止mvc控制器中当前执行的操作?

答案完全取决于你的意思。

如果您的意思是允许您在下载过程中构建模型,那么您可以简单地这样做:

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

但是,如果您想要在不等待下载的情况下将响应返回给客户端,那么这就复杂得多。 我有一篇博文,详细介绍了这个主题。 如果您确实想在工作完成之前返回响应,那么您需要确定该工作对您的重要程度。

如果您需要进行下载,那么您需要将下载请求放在可靠的队列中(例如,Azure队列或MSMQ)并且具有执行实际下载的独立后端(例如,Azure工作者角色或Win32服务)。保存。

如果下载完成并不重要 – 即,您的系统可以处理偶尔丢失的下载 – 那么您可以使用我上面的博客文章中的BackgroundTaskManager类型:

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

我还建议您在下载完成之前关闭AppDomain时使用BackgroundTaskManager.Shutdown取消令牌进行适当的响应(例如,将消息写入事件日志)。


无论您选择哪种解决方案,都应更改DownloadAndSaveFileAsync以打开文件流以进行异步访问。 这是文件流的常见错误; 默认情况下它们是同步的。