2015-02-23 38 views
4

我有一個類使用外部進程來創建一個文件,並作爲下載結果返回,此時我想從服務器上刪除文件。我通常喜歡避免臨時的磁盤文件,但在這種情況下是不可避免的。有沒有一種乾淨的方式來返回FilePathResult並在之後刪除磁盤上的文件?


我最初嘗試此使用Dispose方法來實現:

public class SetupFile : IDisposable 
{ 
    /// <summary>Local file path</summary> 
    public string LocalFilePath { get; set; } 
    /// <summary>Filename to present to user</summary> 
    public string DownloadFilename { get; set; } 

    public void Dispose() 
    { 
     System.IO.File.Delete(LocalFile); 
    } 
} 

控制器代碼創建並在此文件進行操作,然後返回結果作爲FilePathResult

public class DownloadController : Controller 
{ 
    public SetupFileGenerator Generator { get; set; } 
    public DigitalSignatureTool Signer { get; set; } 

    [HttpPost, Route("/download")] 
    public ActionResult Download(InstallParams params) 
    { 
     using (SetupFile file = Generator.Generate(params)) { 
     { 
      Signer.Sign(file.LocalFilePath); // note: requires a local path! 

      return new FilePathResult(file.LocalFilePath, "application/octet-stream") 
      { 
       FileDownloadName = file.DownloadFilename 
      }; 
     } 
    } 
} 

(請注意,GeneratorSigner正通過依賴注入被插入控制器,並保持c oncerns我不想要SetupFileGenerator取決於DigitalSignatureTool。重要的是,我需要Signer.Sign的磁盤上的文件運行 - 因此Generator.Generate()不能只是返回一個流)。

這裏的問題是FilePathResult只在its WriteFile() method後來在處理管道中調用時才發送文件,這意味着我的SetupFile.Dispose()方法已被調用。


我想我的下一個步驟是做兩件事情之一:

  • 實現從FilePathResult派生又是一個新的類刪除該文件它發送
  • 重構我的代碼後認爲與其SetupFile具有財產string LocalFilePath,它有MemoryStream FileContents

然而,這似乎是它將是一個相當常見的模式,所以在我重新開始研究之前,是否有最佳實踐?有什麼要特別留意的?

+0

應該將兩個過程分開,因爲文件管理可以是一個皮塔。有時文件會被鎖定,導致您不想在這裏管理的問題。你應該把這個管理放到一個簡單的服務中,只要你喜歡就可以運行。 – phillip 2015-02-23 20:49:19

+0

你可以使用從'MemoryStream'繼承的一個類來覆蓋'Dispose()'方法嗎? – 2015-02-23 20:52:45

+0

@phillip好點:可能有一些原因可能會導致失敗,這需要週期性的帶外清理操作。但是這也需要考慮到它不能刪除正在使用的文件(例如,當前正在下載的文件)。可以使用。 – gregmac 2015-02-23 21:01:59

回答

2

OnResultExecuted方法在寫入響應之後運行。你可以用ActionFilterAttribute來覆蓋它。

public class DeleteFileAttribute : ActionFilterAttribute 
{ 
    public override void OnResultExecuted(ResultExecutedContext filterContext) 
    { 
     filterContext.HttpContext.Response.Flush(); 
     string filePath = (filterContext.Result as FilePathResult).FileName; 
     System.IO.File.Delete(filePath); 
    } 
} 

只是裝點你的方法如下:

[DeleteFile] 
[HttpPost, Route("/download")] 
public ActionResult Download(InstallParams params) 
{ 
    using (SetupFile file = Generator.Generate(params)) 
    { 
     Signer.Sign(file.LocalFilePath); 

     return new FilePathResult(file.LocalFilePath, "application/octet-stream") 
     { 
      FileDownloadName = file.DownloadFilename 
     }; 
    } 
} 
相關問題