我正在使用 ASP.NET MVC 并且有一个长时间运行的进程。具体来说,我正在生成一个大 PDF 供用户下载。
我理解基本概念:
- 操作方法被调用
- 新线程开始生成进程
- 返回一个 View ,告诉用户正在生成 (pdf)
- 使用AJAX调用服务器并询问进度
- 完成后,将文件提供给用户下载。
我不完全理解的部分是:
- 跨单独 AJAX 调用的线程管理。我可能需要某种方法来查找正在运行的线程并请求状态。是否有一个静态上下文可以保存对线程的引用?我知道
HttpContext.Application
中的数据缓存,这适合于此吗? - 以及如何呈现已完成的文件。我是否创建临时文件并提供下载链接?或者我可以进行最终的 AJAX 调用来返回文件吗?
最佳答案
它有效!
这是我所做的:
第 1 步和第 2 步 - 调用操作方法,启动长时间运行的线程
当我的操作方法被调用时,它会生成一个唯一的 ID。然后,我实例化 PdfGenerator
类的实例,创建一个调用 PdfGenerator.Generate
的新线程并启动它。
public class PdfGenerator
{
public string State;
public byte[] Data;
public void Generate()
{
// Generate PDF/Long running process
// Should update State as it goes
// ...
// Once finished, Data is populated with the binary byte[]
}
}
线程启动后(或启动之前),生成器实例将存储在缓存中:
HttpContext.Cache[guid] = generator;
我还将 guid 附加到 ViewData,以便可以在我的 View 脚本中引用它。
第 3 步和第 4 步 - 显示和更新状态/进度 View
现在线程正在运行并且 PDF 生成已经开始,我可以显示我的进度 View 脚本。使用 jQuery 的 $.getJSON
我能够轮询一个单独的 Action 来查找生成的状态:
[OutputCache(Duration = 0, VaryByName = "none", NoStore = true)]
public JsonResult CheckPdfGenerationStatus(string guid)
{
// Get the generator from cache
var generator = HttpContext.Cache[guid] as PdfGenerator;
if (generator == null)
return Json(null);
else
return Json(generator.State);
}
我的 View 脚本解释 Json 并显示相应的进度信息。
第 5 步 - 向用户展示文件
一旦生成完成,生成器状态就会相应设置,当 jQuery 收到此信息时,它可以提供可用链接,或者使用 JavaScript location.href
直接发送文件。
设置并返回文件的 Action 方法只是将生成器从缓存中取出并返回附加的 byte[]
public ContentResult DownloadPdf(string guid)
{
var generator = HttpContext.Cache[guid] as PdfGenerator;
if (generator == null)
return Content("Error");
if (generator.State == "Completed")
{
return Content(generator.Data);
}
else
{
return Content("Not finished yet");
}
}
我的实际工作有更详细的状态,例如已初始化、正在运行和已完成。以及进度百分比(以小数表示,1.0 表示完成)。
所以是的,希望这可以帮助其他尝试做类似事情的人。
关于asp.net-mvc - 长时间运行的进程将返回一个文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1325054/