將返回文件的長時間執行的程序
我正在使用 ASP.NET MVC 並且有一個長時間執行的過程。具體來說,我正在生成一個大的 PDF 供使用者下載。
我了解基本概念:
- 動作方法被呼叫
- 新執行緒開始生成程序
- 返回一個告訴使用者正在生成(pdf)的視圖
- 使用AJAX呼叫伺服器並詢問進度
- 完成後,將文件呈現給使用者以供下載。
我不完全理解的部分是:
- 跨單獨 AJAX 呼叫的執行緒管理。我可能需要某種方法來查找正在執行的執行緒並請求狀態。是否有一個靜態上下文我可以保留對執行緒的引用?我知道中的數據記憶體
HttpContext.Application,這適合這個嗎?- 以及如何呈現完成的文件。我是否創建一個臨時文件並提供下載連結?或者我可以進行最終的 AJAX 呼叫來返回文件嗎?
Cashe 非常適合這種情況。只有一件事是確保在程序執行時永遠不會刪除記憶體的項目(您可以使用 ItemPriority.NotRemovable )。
您可以將文件保存在磁碟上的臨時文件夾中,也可以將其保存在記憶體中一段時間(視情況而定)。
我個人不喜歡用文件污染硬碟,所以我會將文件保存在記憶體中(使用 MediumPriority 幾分鐘)。但是如果文件很大並且可以生成,通常考慮使用文件系統的數據庫。
在客戶端,當最後一個 Ajax 請求返回 result( 可能看起來像*{progress: “100%”, resultUrl: “http://your.url/Where/ToGet/TheFile.aspx?file=GUID-OR-CACHE- KEY”}* ) 您可以將瀏覽器重定向到提供的 URL。
反過來,它將將該文件呈現為二進制結果。
客戶端重定向可以使用 Javascript 來完成,如下所示:
location.href = response.resultUrl;順便說一句,你如何生成 PDF?非政府組織?
有用!
這是我所做的:
第 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,我可以輪詢一個單獨的操作來查找生成的狀態:[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"); } }在我的實際工作中,我得到了更詳細的狀態,例如 Initialized、Running 和 Completed。以及進度百分比(以小數表示,1.0 表示完整)。
所以,是的,希望能幫助其他嘗試做類似事情的人。