是否有一种有效的方式来下载文件并将其保存在"背景"没有阻止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<HttpResponseMessage> GetResponse()
{
var client = new HttpClient();
client.BaseAddress = new Uri("http://someUrl.com");
return await client.GetAsync("someResourceEndPoint").ConfigureAwait(false);
}
我已经阅读了几个你不应该在服务器上使用Task.Run的地方(在工作线程中)所以我想知道这个例子是否可扩展(例如,如果它每秒收到10个请求)或者可靠或者是否存在有什么合适的方法可以做到这一点吗?
由于
答案 0 :(得分:3)
不阻止mvc控制器中当前执行的操作?
答案完全取决于你的意思。
如果您的意思是允许您在下载过程中构建模型,那么您可以简单地这样做:
public ActionResult Index()
{
var task = DownloadAndSaveFileAsync();
var model = GetModel();
await task;
return View(model);
}
但是,如果您想要在不等待下载的情况下将响应返回给客户端,那就更加复杂了。 I have a blog post that goes into more detail on the subject.如果您确实想在工作完成之前返回回复,那么您需要确定该工作对您的重要程度。
如果您需要进行下载,那么您需要将下载请求放在可靠的队列中(例如,Azure队列或MSMQ)并具有独立的后端(例如,Azure辅助角色或Win32服务)进行实际下载和保存。
如果完成下载并不重要 - 例如,您的系统可以处理偶尔丢失的下载 - 那么您可以使用上面我博客文章中的BackgroundTaskManager
类型:
private void InitiateDownload()
{
BackgroundTaskManager.Run(() => DownloadAndSaveFileAsync());
}
我还建议您在下载完成之前关闭AppDomain时使用BackgroundTaskManager.Shutdown
取消令牌进行适当的响应(例如,将消息写入事件日志)。
无论您选择哪种解决方案,都应更改DownloadAndSaveFileAsync
以打开文件流以进行异步访问。这是文件流的常见错误;默认情况下,它们是同步的。