长时间运行的进程将返回一个文件

时间:2009-08-24 22:09:43

标签: asp.net-mvc

我正在使用ASP.NET MVC并且运行时间很长。具体来说,我正在生成一个大PDF供用户下载。

我理解基本概念:

  1. 调用操作方法
  2. 新线程开始生成进程
  3. 返回一个告诉用户正在生成(pdf)的视图
  4. 使用AJAX调用服务器并要求进度
  5. 完成后,将文件提供给用户下载。
  6. 我不完全理解的部分是:

    • 跨越单独的AJAX调用管理线程。我可能需要一些方法来查找正在运行的线程并请求状态。是否有静态上下文我可以保持对该线程的引用?我知道HttpContext.Application中的数据缓存,是否适用于此?
    • 以及如何呈现已完成的文件。我是否创建临时文件并提供下载链接?或者我可以进行最终返回文件的AJAX调用吗?

2 个答案:

答案 0 :(得分:7)

有效!

这就是我所做的:

第1步& 2 - 调用Action Method,启动长时间运行的线程

当调用我的action方法时,它会生成一个唯一的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,以便它可以在我的视图脚本中引用。

第3步& 4 - 显示和更新状态/进度视图

现在线程正在运行并且PDF生成已经开始,我可以显示我的进度视图脚本。使用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);
}

我的视图脚本解释Json并显示相应的进度信息。

第5步 - 向用户显示文件

生成完成后,将相应地设置生成器状态,当jQuery收到此信息时,它可以提供链接,也可以使用javascripts 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");
    }
}

我的实际工作我有更详细的状态,例如Initialised,Running和Completed。除了进度百分比(以小数表示,1.0表示完整)。

所以是的,希望能帮助其他人尝试做类似的事情。

答案 1 :(得分:6)

Cashe非常适合这种情况。只有一件事是确保在进程运行时永远不会删除缓存的项目(您可以使用ItemPriority.NotRemovable)。

您可以将文件保存在临时文件夹中的磁盘上,也可以将其保存在缓存中一段时间​​(取决于) 我个人不喜欢用文件污染硬盘,所以我会将文件保存在缓存中(在几分钟内使用MediumPriority)。但是文件很大并且可以生成,经常考虑使用文件系统数据库。

在客户端上,当最后一个Ajax请求返回结果时(可能看起来像 {progress:“100%”,resultUrl:“http://your.url/Where/ToGet/TheFile.aspx?file=GUID-OR-CACHE-KEY”} ),您可以将浏览器重定向到提供的网址 反过来,它将该文件呈现为二进制结果。

客户端重定向可以使用以下Javascript完成:

location.href = response.resultUrl;
顺便说一句,你如何生成PDF? NFOP?