代码之家  ›  专栏  ›  技术社区  ›  jeef3

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

  •  8
  • jeef3  · 技术社区  · 16 年前

    我正在使用ASP。NET MVC,运行过程长。具体来说,我正在生成一个大的PDF供用户下载。

    1. Action方法被调用
    2. 新线程已开始生成进程
    3. 返回一个视图,该视图告诉用户正在生成(pdf)

    我不完全理解的部分是:

    • 跨单独AJAX调用的线程管理。我可能需要一些方法来查找正在运行的线程并请求状态。是否有一个静态上下文可以保留对线程的引用?我知道中的数据缓存 HttpContext.Application ,这样合适吗?
    • 以及如何展示已完成的文件。我是否要创建一个临时文件并提供下载链接?或者,我可以进行最后一次AJAX调用来返回文件吗?
    2 回复  |  直到 16 年前
        1
  •  6
  •   Dmytrii Nagirniak    16 年前

    它奏效了!

    以下是我所做的:

    步骤1&2-调用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方法只是将生成器从缓存中取出,并返回附加的字节[]

    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表示完成)。

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

        2
  •  7
  •   jeef3    16 年前

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

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

    在客户端,当最后一个Ajax请求返回结果时(可能看起来像 {进度:“100%”,结果URL:http://your.url/Where/ToGet/TheFile.aspx?file=GUID-或缓存密钥“}

    客户端重定向可以使用Javascript完成,如下所示:

    location.href = response.resultUrl;
    

    顺便问一下,你是如何生成PDF的?非营利组织?