创建返回Excel的自定义ActionResult

该篇文章是Stephen Walther博客中的文章,个人觉得不错就翻译了一下。但由于个人英语水平有限,还望各位海量。如果想看原文,请点击ASP.NET MVC Tip #2 - Create a custom Action Result that returns Microsoft Excel Documents查看原文

在这篇条目中,我会展示给大家创建一个能够返回Asp.net MVCController Action的自定的Action Result。这个action result从一个Linq to SQL查询获取数据并创建一个Microsoft Excel的文件。

在一个MVC的应用程序中,一个Controller控制器的操作返回一个Action result。特别的这些操作返回值是来源于基础的ActionResult类就像下面这些:

· ViewResult

· EmptyResult

· RedirectResult

· RedirectToRouteResult

· JsonResult

· ContentResult

例如,你使用ViewResult向浏览器返回一个特别的View,使用一个ContentResult向浏览器返回文本内容。

但是如果你要向浏览器返回一些象image,PDF,或者Microsoft Excel的其他类型的内容该怎么办?在该种情况下,你只能创建一个自己的action result。这个条目中,我会给大家展示怎样创建一个返回Microsoft Excel文件的action result

列表一是ExcelResult的代码:

  1 using System;
  2 using System.Web.Mvc;
  3 using System.Data.Linq;
  4 using System.Collections;
  5 using System.IO;
  6 using System.Web.UI.WebControls;
  7 using System.Linq;
  8 using System.Web;
  9 using System.Web.UI;
 10 using System.Drawing;
 11 
 12 
 13 namespace Tip2
 14 {
 15     public class ExcelResult : ActionResult
 16     {
 17         private DataContext _dataContext;
 18         private string _fileName;
 19         private IQueryable _rows;
 20         private string[] _headers = null;
 21 
 22         private TableStyle _tableStyle;
 23         private TableItemStyle _headerStyle;
 24         private TableItemStyle _itemStyle;
 25 
 26         public string FileName
 27         {
 28             get { return _fileName; }
 29         }
 30 
 31         public IQueryable Rows
 32         {
 33             get { return _rows; }
 34         }
 35 
 36 
 37         public ExcelResult(DataContext dataContext, IQueryable rows, string fileName)
 38             :this(dataContext, rows, fileName, nullnullnullnull)
 39         {
 40         }
 41 
 42         public ExcelResult(DataContext dataContext, string fileName, IQueryable rows, string[] headers)
 43             : this(dataContext, rows, fileName, headers, nullnullnull)
 44         {
 45         }
 46 
 47         public ExcelResult(DataContext dataContext, IQueryable rows, string fileName, string[] headers, TableStyle tableStyle, TableItemStyle headerStyle, TableItemStyle itemStyle)
 48         {
 49             _dataContext = dataContext;
 50             _rows = rows;
 51             _fileName = fileName;
 52             _headers = headers;
 53             _tableStyle = tableStyle;
 54             _headerStyle = headerStyle;
 55             _itemStyle = itemStyle;
 56 
 57             // provide defaults
 58             if (_tableStyle == null)
 59             {
 60                 _tableStyle = new TableStyle();
 61                 _tableStyle.BorderStyle = BorderStyle.Solid;
 62                 _tableStyle.BorderColor = Color.Black;
 63                 _tableStyle.BorderWidth = Unit.Parse("2px");
 64             }
 65             if (_headerStyle == null)
 66             {
 67                 _headerStyle = new TableItemStyle();
 68                 _headerStyle.BackColor = Color.LightGray;
 69             }
 70         }
 71 
 72         public override void ExecuteResult(ControllerContext context)
 73         {
 74             // Create HtmlTextWriter
 75             StringWriter sw = new StringWriter();
 76             HtmlTextWriter tw = new HtmlTextWriter(sw);
 77 
 78             // Build HTML Table from Items
 79             if (_tableStyle != null)
 80                 _tableStyle.AddAttributesToRender(tw);
 81             tw.RenderBeginTag(HtmlTextWriterTag.Table);
 82 
 83             // Generate headers from table
 84             if (_headers == null)
 85             {
 86                 _headers = _dataContext.Mapping.GetMetaType(_rows.ElementType).PersistentDataMembers.Select(m => m.Name).ToArray();
 87             }
 88 
 89 
 90             // Create Header Row
 91             tw.RenderBeginTag(HtmlTextWriterTag.Thead);
 92             foreach (String header in _headers)
 93             {
 94                 if (_headerStyle != null)
 95                     _headerStyle.AddAttributesToRender(tw);
 96                 tw.RenderBeginTag(HtmlTextWriterTag.Th);
 97                 tw.Write(header);
 98                 tw.RenderEndTag();
 99             }
100             tw.RenderEndTag();
101 
102             
103 
104             // Create Data Rows
105             tw.RenderBeginTag(HtmlTextWriterTag.Tbody);
106             foreach (Object row in _rows)
107             {
108                 tw.RenderBeginTag(HtmlTextWriterTag.Tr);
109                 foreach (string header in _headers)
110                 {
111                     string strValue = row.GetType().GetProperty(header).GetValue(row, null).ToString();
112                     strValue = ReplaceSpecialCharacters(strValue);
113                     if (_itemStyle != null)
114                         _itemStyle.AddAttributesToRender(tw);
115                     tw.RenderBeginTag(HtmlTextWriterTag.Td);
116                     tw.Write( HttpUtility.HtmlEncode(strValue));
117                     tw.RenderEndTag();
118                 }
119                 tw.RenderEndTag();
120             }
121             tw.RenderEndTag(); // tbody
122 
123             tw.RenderEndTag(); // table
124             WriteFile(_fileName, "application/ms-excel", sw.ToString());            
125         }
126 
127 
128         private static string ReplaceSpecialCharacters(string value)
129         {
130             value = value.Replace("""'");
131             value = value.Replace("""\"");
132             value = value.Replace("""\"");
133             value = value.Replace("""-");
134             value = value.Replace("""");
135             return value;
136         }
137 
138         private static void WriteFile(string fileName, string contentType, string content)
139         {
140             HttpContext context = HttpContext.Current;
141             context.Response.Clear();
142             context.Response.AddHeader("content-disposition""attachment;filename=" + fileName);
143             context.Response.Charset = "";
144             context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
145             context.Response.ContentType = contentType;
146             context.Response.Write(content);
147             context.Response.End();
148         }
149     }
150 }
151 

每个action result必须继承基础的ActionResult类。列表一中的ExcelResult类事实上也是继承基础的ActionResult类。基础的ActionResult类的Execute()方法是你必须要重写的。Excute()方法是产生action result返回的内容。

在列表一中,Excute()方法被用来从Linq to SQL的数据产生一个Excel文件。Excute()方法调用WriteFile()方法来向浏览器写包含正确MIME类型的以完成的Excel文件。

通常的,你不会直接从控制器(controller)返回一个action result。你使用Controller类中的方法来代替:

· View()

· Redirect()

· RedirectToAction()

· RedirectToRoute()

· Json()

· Content()

例如,如果你想要从Controller的操作中返回一个view,你不用返回一个ViewResult,而是用View()方法代替。View()方法实例化一个ViewResult并想浏览器返回一个新的ViewResult

应用于Controller由三个扩展方法组成的类的代码在类表二中。这些扩展方法向Controller类中添加名叫Excel()的方法。Excel()方法返回ExcelResult

 

 1 using System;
 2 using System.Web.Mvc;
 3 using System.Data.Linq;
 4 using System.Collections;
 5 using System.Web.UI.WebControls;
 6 using System.Linq;
 7 
 8 namespace Tip2
 9 {
10     public static class ExcelControllerExtensions
11     {
12         public static ActionResult Excel
13         (
14             this Controller controller,
15             DataContext dataContext,
16             IQueryable rows,
17             string fileName
18         )
19         {
20             return new ExcelResult(dataContext, rows, fileName, nullnullnullnull);
21         }
22 
23         public static ActionResult Excel
24         (
25             this Controller controller,
26             DataContext dataContext,
27             IQueryable rows,
28             string fileName,
29             string[] headers
30         )
31         {
32             return new ExcelResult(dataContext, rows, fileName, headers, nullnullnull);
33         }
34 
35         public static ActionResult Excel
36         (
37             this Controller controller, 
38             DataContext dataContext,
39             IQueryable rows, 
40             string fileName, 
41             string[] headers, 
42             TableStyle tableStyle, 
43             TableItemStyle headerStyle,
44             TableItemStyle itemStyle
45         )
46         {
47             return new ExcelResult(dataContext, rows, fileName, headers, tableStyle, headerStyle, itemStyle);
48         }
49 
50     }
51 }

    在列表三中的Controller代码向你阐明怎样在一个Controller使用Excel()扩展方法。这个控制器Controller包含三个名为GenerateExcel1()GenerateExcel2()GenerateExcel3()方法。这个三个控制器操作方法返回一个从Movies数据表获取数据的Excel文件。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Data.Linq;
 5 using System.Data.Linq.Mapping;
 6 using System.Web.UI.WebControls;
 7 using System.Web;
 8 using System.Web.Mvc;
 9 using Tip2.Models;
10 using Tip2;
11 
12 namespace Tip2.Controllers
13 {
14     public class HomeController : Controller
15     {
16 
17         private MovieDataContext db = new MovieDataContext();
18 
19         public ActionResult Index()
20         {
21             return View();
22         }
23 
24         /// <summary>
25         /// Generates Excel document using headers grabbed from property names
26         /// </summary>
27         public ActionResult GenerateExcel1()
28         {
29             return this.Excel(db, db.Movies, "data.xls");            
30         }
31 
32         /// <summary>
33         /// Generates Excel document using supplied headers
34         /// </summary>
35         public ActionResult GenerateExcel2()
36         {
37             var rows = from m in db.Movies select new {Title=m.Title, Director=m.Director};
38             return this.Excel(db, rows, "data.xls"new[] { "Title""Director" });
39         }
40 
41         /// <summary>
42         /// Generates Excel document using supplied headers and using supplied styles
43         /// </summary>
44         public ActionResult GenerateExcel3()
45         {
46             var rows = from m in db.Movies select new { Title = m.Title, Director = m.Director };
47             var headerStyle = new TableItemStyle();
48             headerStyle.BackColor = System.Drawing.Color.Orange;
49             return this.Excel(db, rows, "data.xls"new[] { "Title""Director" }, null, headerStyle, null);
50         }
51     }
52 }
53 

    最后,在Index.aspx View展示怎样调用GenerateExcel()控制器操作并创建Excel文件。注意三个连接指向三个不同的GenerateExcel版本。

 

 1     <h1>Generate Microsoft Excel Document</h1>
 2     
 3     
 4     <ul>
 5         <li>
 6         <href="/Home/GenerateExcel1">Generate</a> - Generates an Excel document by using the entity property names for column headings and the default
 7         formatting.        
 8         </li>
 9         <li>
10         <href="/Home/GenerateExcel2">Generate</a> - Generates an Excel document by using supplied header names and default formatting.        
11         </li>
12         <li>
13         <href="/Home/GenerateExcel3">Generate</a> - Generates an Excel document by using supplied header names and supplied formatting.        
14         </li>
15 
16     </ul>

posted @ 2010-06-27 12:12  Jones.Zhao  阅读(645)  评论(0编辑  收藏  举报