我們在 ASP.NET MVC (7) 中曾介紹了 ASP.NET MVC 的 View 內建了 9 種不同的 View,基本上這些 View 均足以應付大部份的資料呈現需求,但是它也不是不能擴充的,像是一些特殊的 View (例如圖表或特殊檔案或特別的資料格式),就需要由開發人員自己設計,不過 MVC 的 View 設計上也不難,只要將自己的 View 加入 HTTP 處理流程中即可。
我們在 ASP.NET MVC (7) 中曾介紹了 ASP.NET MVC 的 View 內建了 9 種不同的 View,基本上這些 View 均足以應付大部份的資料呈現需求,但是它也不是不能擴充的,像是一些特殊的 View (例如圖表或特殊檔案或特別的資料格式),就需要由開發人員自己設計,不過 MVC 的 View 設計上也不難,只要將自己的 View 加入 HTTP 處理流程中即可。
我們在 Controller 中的每一個動作,最後都會回傳一個 View,而預設的型別是 ActionResult,ActionResult 是 View 的基底類別,MVC 內建的 9 種 View 都衍生自 ActionResult,也就是說,我們可以透過繼承這個抽象類別,來取得產生自己需要的 View 的基本功能,而我們只需要覆寫 ActionResult.ExecuteResult() 方法即可。
所以我們在專案中新增一個類別,命名為 CsvResult,並設定它繼承 ActionResult 類別 (Visual Studio 會偵測是否已實作必要成員,將會以一個小的底線符號通知)。而本例是使用泛型的方式產生 CSV,因此可直接使用下列程式碼取代:
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Reflection;
5: using System.Text;
6: using System.Web;
7: using System.Web.Mvc;
8:
9: namespace MvcApplication1
10: {
11: public class CsvResult<TModel, T> : ActionResult where TModel : IEnumerable<T>
12: {
13: public string FileName { get; set; }
14: public TModel Model { get; set; }
15:
16: public override void ExecuteResult(ControllerContext context)
17: {
18: StringBuilder csvBuilder = new StringBuilder();
19:
20: context.HttpContext.Response.Clear();
21:
22: context.HttpContext.Response.Buffer = true;
23: context.HttpContext.Response.ContentType = "text/csv";
24: context.HttpContext.Response.AddHeader("content-disposition", "attachment; filename=" + this.FileName);
25:
26: PropertyInfo[] modelProperties = typeof(T).GetProperties();
27: StringBuilder itemBuilder = new StringBuilder();
28:
29: // render header.
30: foreach (PropertyInfo modelProperty in modelProperties)
31: {
32: if (modelProperty.DeclaringType == typeof(T))
33: {
34: if (itemBuilder.Length == 0)
35: itemBuilder.Append(modelProperty.Name);
36: else
37: itemBuilder.Append(",").Append(modelProperty.Name);
38: }
39: }
40:
41: csvBuilder.Append(itemBuilder);
42:
43: // render body.
44: foreach (T item in this.Model)
45: {
46: csvBuilder.Append(Environment.NewLine);
47: itemBuilder.Clear();
48:
49: foreach (PropertyInfo modelProperty in modelProperties)
50: {
51: if (modelProperty.DeclaringType == typeof(T))
52: {
53: if (itemBuilder.Length == 0)
54: itemBuilder.Append(modelProperty.GetValue(item, null).ToString());
55: else
56: itemBuilder.Append(",").Append(modelProperty.GetValue(item, null).ToString());
57: }
58: }
59:
60: csvBuilder.Append(itemBuilder);
61: }
62:
63: context.HttpContext.Response.Write(csvBuilder.ToString());
64: }
65: }
66: }
完成後,在 MyController 中,加入一個 CustomerCsv 的方法:
1: public ActionResult CustomerCsv()
2: {
3: var model = Models.CustomerDataContext.LoadCustomers();
4: return new CsvResult<IEnumerable<Models.Customer>, Models.Customer>() { FileName = "Customers.csv", Model = model };
5: }
然後啟動程式,打開瀏覽器,瀏覽 http://[root]/My/CustomerCsv,你會發現檔案已自動下載到瀏覽器的下載資料夾內:
打開來看,Northwind 的 Customers 的資料都會在裡面,不過會只有宣告在 Model.Customer 的屬性的資料才會出現。
Reference: