2009-06-13 31 views
18

Tôi cần tạo một ActionResult trong một ứng dụng ASP.NET MVC có một tệp .csv.Cách được khuyến nghị để tạo một ActionResult với phần mở rộng tập tin

Tôi sẽ cung cấp danh sách email 'không gọi' cho các đối tác tiếp thị của mình và tôi muốn nó có đuôi .csv trong loại tệp. Sau đó, nó sẽ tự động mở trong Excel.

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

Tôi đã thực hiện thành công việc này như sau, nhưng tôi muốn đảm bảo đây là cách tốt nhất và được khuyến nghị tuyệt đối để thực hiện việc này.

[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" 
      }; 
    } 

Hành động này sẽ phản hồi lại liên kết trên.

Tôi chỉ băn khoăn liệu có bất kỳ xung đột không mong muốn nào về việc mở rộng tệp như thế này với bất kỳ phiên bản IIS nào khác, bất kỳ loại bộ lọc ISAPI nào hay không.

Tôi cần chắc chắn 100% vì tôi sẽ cung cấp điều này cho các đối tác bên ngoài và không muốn thay đổi ý định sau này. Tôi thực sự không thể nhìn thấy bất kỳ vấn đề, nhưng có lẽ theres một cái gì đó tối nghĩa - hoặc một "MVC" nhiều hơn như cách làm điều này.

Trả lời

19

Tôi nghĩ câu trả lời của bạn PHẢI chứa tiêu đề "Nội dung-Bố trí" trong trường hợp này. Tạo tùy chỉnh ActionResult như thế này:

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); 
     } 
    } 
} 

Và sử dụng nó trong hành động của bạn thay vì ContentResult:

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

cảm ơn! nhưng bạn có thể làm rõ những gì bạn có nghĩa là phải không? những gì tôi đã làm dường như làm việc - mặc dù cách này là thích hợp hơn nhiều –

+0

Nếu hành động của bạn trả về ".csv" tập tin sau đó khách hàng của bạn muốn "mở" hoặc "lưu" nó - vì vậy bạn phải cung cấp tiêu đề "Content-Disposition" (mặc dù nó là tùy chọn, xem http://www.ietf.org/rfc/rfc2183.txt). Không có tiêu đề này, quá trình mở tệp của bạn có thể khác nhau ở các trình duyệt/hệ điều hành/máy khác nhau –

+1

Có lỗi trong mã không? Tên không nên là một chuỗi thay vì mã hóa? Ngoài ra trình biên dịch nói với tôi rằng ActionResult không có thuộc tính Response – ADB

6

Đây là cách tôi đang làm điều tương tự. Tôi coi đó là bản tải xuống:

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

Điều này sẽ hiển thị trong trình duyệt dưới dạng tệp tải xuống với tên tệp đã cho.

Tôi không thể nghĩ ra lý do tại sao máy của bạn không hoạt động.

28

tôi đã sử dụng hành động FileContentResult cũng phải làm một cái gì đó tương tự.

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") 
} 

Nó sẽ thêm tiêu đề bố trí nội dung cho bạn.

+1

Làm cho ý nghĩa hơn nhiều so với việc viết một lớp để làm điều gì đó đã được tích hợp sẵn! Chúc mừng! – Shawson

+0

Đây thực sự là cách để đi –

+0

Cảm ơn câu trả lời đơn giản, dễ thực hiện trong một tình huống khác –

0

Câu trả lời bạn chấp nhận là đủ tốt, nhưng nó giữ nội dung của đầu ra trong bộ nhớ khi nó xuất ra. Điều gì xảy ra nếu tệp nó tạo ra là khá lớn? Ví dụ, khi bạn đổ một nội dung của bảng SQL. Ứng dụng của bạn có thể hết bộ nhớ. Những gì bạn muốn trong trường hợp này là sử dụng FileStreamResult. Một cách để truyền dữ liệu vào luồng có thể đang sử dụng đường ống, as I described here

Các vấn đề liên quan