2009-06-13 79 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