2010-04-15 48 views
6

我有一個操作,需要從安全位置讀取文件,所以我必須使用模擬來讀取文件。模仿在ASP.NET MVC

此代碼:

[AcceptVerbs(HttpVerbs.Get)] 
public ActionResult DirectDownload(Guid id) 
{ 
    if (Impersonator.ImpersonateValidUser()) 
    { 
     try 
     { 
      var path = "path to file"; 
      if (!System.IO.File.Exists(path)) 
      { 
       return View("filenotfound"); 
      } 

      var bytes = System.IO.File.ReadAllBytes(path); 
      return File(bytes, "application/octet-stream", "FileName"); 
     } 
     catch (Exception e) 
     { 
      Log.Exception(e); 
     }finally 
     { 
      Impersonator.UndoImpersonation(); 
     } 
    } 
    return View("filenotfound"); 
} 

與上面的代碼唯一的問題是,我要讀整個文件到內存中,我將要處理非常大的文件,所以這不是一個好的解決方案但是,如果我取代這兩條線:

var bytes = System.IO.File.ReadAllBytes(path); 
return File(bytes, "application/octet-stream", "FileName"); 

與此:

return File(path, "application/octet-stream", "FileName"); 

它不工作,我得到的錯誤信息:

訪問路徑 「C: \ projects \ uploads \ 1 \ aa2bcbe7-ea99-499d-add8-c1fdac561b0e \ Untitled 2.csv'被拒絕。

我想用一個路徑的文件結果嘗試在請求管道中稍後打開文件,當我已經「取消」模擬。

請記住,模擬代碼的工作原理是因爲我可以讀取bytes數組中的文件。我想要做的是將文件流式傳輸到客戶端。

任何想法如何解決這個問題?

在此先感謝。

回答

4

您可以嘗試編寫自定義FilePathResult

public class ImpersonatingFileResult : FilePathResult 
{ 
    public ImpersonatingFileResult(string fileName, string contentType) 
     : base(fileName, contentType) 
    { } 

    protected override void WriteFile(HttpResponseBase response) 
    { 
     // TODO : Start impersonation 
     response.TransmitFile(FileName); 
     // TODO : Rollback impersonation 
    } 
} 

,並在你的控制器:

return new ImpersonatingFileResult(path, "application/octet-stream"); 
+0

這很好。我改變了一點,因爲我得到一個異常... Impersonator.ImpersonateValidUser(); response.WriteFile(文件名); response.Flush(); response.End(); Impersonator.UndoImpersonation(); – Emad 2010-04-16 18:44:29

+0

是的,這是一個好的開始。但是,它會在特定版本的IIS中引發「無效句柄」錯誤,這些版本是基於提供文件(而不是基於模仿)而建立的。 – Greg 2015-05-21 13:52:52

1

我喜歡Darin的答案,但它跳過模擬邏輯,它拋出一個錯誤在IIS 7 ...

因此,我添加了模擬代碼,你可以通過利用N uget包SimpleImpersonation

另外,爲了防止無效的句柄錯誤,IIS 7中引入了一些更改。

public class ImpersonatingFileResult : FilePathResult 
{ 
    public ImpersonatingFileResult(string fileName, string contentType) 
     : base(fileName, contentType) 
    { } 

    protected override void WriteFile(HttpResponseBase response) 
    { 
     using (SimpleImpersonation.Impersonation.LogonUser(domain: "SomeDomain", username: "SomeUser", password: "SomePassword", logonType: SimpleImpersonation.LogonType.NewCredentials)) 
     { 
      response.Clear(); 
      response.ContentType = base.ContentType; 
      response.AddHeader("Content-Disposition", "attachment; filename=" + System.IO.Path.GetFileName(base.FileName)); 
      response.TransmitFile(FileName); 
      response.Flush(); 
     } 
    } 

,然後用它從控制器:

 return new ImpersonatingFileResult(someFilePath, "Application/pdf"); 

以上是下載文件,但如果你想顯示它,那麼你需要指定「內聯」。

  response.Clear(); 
      response.ContentType = base.ContentType; 
      response.AddHeader("Content-Disposition", "inline; filename=\"" + System.IO.Path.GetFileName(base.FileName) + "\""); 
      response.TransmitFile(FileName); 
      response.Flush(); 
+0

這是一個很好的答案,謝謝! – 2015-09-15 16:55:01