2009-06-13 115 views
18

我需要在具有.csv文件類型的ASP.NET MVC應用程序中創建ActionResult。建議使用文件擴展名創建ActionResult的方法

我會爲我的營銷合作伙伴提供一個'別打電話'的電子郵件列表,我希望它在文件類型中有一個.csv擴展名。然後它會自動在Excel中打開。

http://www.example.com/mailinglist/donotemaillist.csv?password=12334 

我已經成功地做到了這一點如下,但我要確保這是這樣做的絕對是最好的和推薦的方式。

[ActionName("DoNotEmailList.csv")] 
    public ContentResult DoNotEmailList(string username, string password) 
    { 
      return new ContentResult() 
      { 
       Content = Emails.Aggregate((a,b)=>a+Environment.NewLine + b), 
       ContentType = "text/csv" 
      }; 
    } 

這個Actionmethod會響應上面的鏈接就好了。

我只是想知道是否有任何意外的衝突,像任何不同版本的IIS,任何類型的ISAPI過濾器或任何其他我不能想到現在這樣的文件擴展名的衝突。

我需要100%確定,因爲我會提供給外部合作伙伴,不希望稍後改變主意。我真的不能看到任何問題,但也許有些晦澀 - 或另一個更像「MVC」這樣做的方式。

回答

19

我認爲你的迴應在這種情況下必須包含「Content-Disposition」標題。創建自定義的ActionResult是這樣的:

public class MyCsvResult : ActionResult { 

    public string Content { 
     get; 
     set; 
    } 

    public Encoding ContentEncoding { 
     get; 
     set; 
    } 

    public string Name { 
     get; 
     set; 
    } 

    public override void ExecuteResult(ControllerContext context) { 
     if (context == null) { 
      throw new ArgumentNullException("context"); 
     } 

     HttpResponseBase response = context.HttpContext.Response; 

     response.ContentType = "text/csv"; 

     if (ContentEncoding != null) { 
      response.ContentEncoding = ContentEncoding; 
     } 

     var fileName = "file.csv"; 

     if(!String.IsNullOrEmpty(Name)) { 
      fileName = Name.Contains('.') ? Name : Name + ".csv"; 
     } 

     response.AddHeader("Content-Disposition", 
      String.Format("attachment; filename={0}", fileName)); 

     if (Content != null) { 
      response.Write(Content); 
     } 
    } 
} 

而在你的行動用它來代替ContentResult類型的:

return new MyCsvResult { 
    Content = Emails.Aggregate((a,b) => a + Environment.NewLine + b) 
    /* Optional 
    * , ContentEncoding = "" 
    * , Name = "DoNotEmailList.csv" 
    */ 
}; 
+0

謝謝!但你能澄清你的意思嗎?我所做的似乎有效 - 儘管這種方式更可取 – 2009-06-13 17:41:29

+0

如果您的操作返回「.csv」文件,那麼您的客戶需要「打開」或「保存」它 - 因此您必須提供「Content-Disposition」標題(儘管它是可選的,請參閱http://www.ietf.org/rfc/rfc2183.txt)。沒有這個頭文件,在不同的瀏覽器/操作系統/機器上打開文件的過程可能會有所不同 – 2009-06-13 18:06:16

6

這就是我如何做類似的事情。我將它視爲下載內容:

var disposition = String.Format(
    "attachment;filename=\"{0}.csv\"", this.Model.Name); 
Response.AddHeader("content-disposition", disposition); 

這應該在瀏覽器中顯示爲具有給定文件名的文件下載。

但我想不出爲什麼你不工作的原因。

28

我用FileContentResult動作也做同樣的事情。

public FileContentResult DoNotEmailList(string username, string password) 
{ 
     string csv = Emails.Aggregate((a,b)=>a+Environment.NewLine + b); 
     byte[] csvBytes = ASCIIEncoding.ASCII.GetBytes(csv); 
     return File(csvBytes, "text/csv", "DoNotEmailList.csv") 
} 

它會爲您添加content-disposition標頭。

0

您接受的答案已足夠好,但輸出內容時會將輸出內容保留在內存中。如果它生成的文件相當大,該怎麼辦?例如,當您轉儲SQL表的內容時。您的應用程序可能會耗盡內存。在這種情況下你想要的是使用FileStreamResult。將數據輸入流中的一種方法是使用管道,as I described here