随笔 - 80  文章 - 2 评论 - 1197 trackbacks - 37

我的小工具
.NET正则表达式库
中国游戏开发者网络
中国游戏开发者网络 | 论坛

广告


北京狼烟网络科技有限公司
北京市朝阳区曙光西里甲6号 时间国际A座1505&msg=2007101111175778000" frameBorder=0 scrolling=no>

与我联系

搜索

 

常用链接

留言簿(8)

我参与的团队

我的标签

随笔分类

随笔档案

文章档案

相册

友情链接

积分与排名

  • 积分 - 215026
  • 排名 - 156

最新评论

阅读排行榜

评论排行榜

原文地址:http://weblogs.asp.net/stephenwalther/archive/2008/06/16/asp-net-mvc-tip-2-create-a-custom-action-result-that-returns-microsoft-excel-documents.aspx 

摘要:在这个Tip中,Stephen Walther创建了一个自定义的ActionResult,可以由ASP.NET MVC控制器action返回。该ActionResult从一个LINQ to SQL查询生成了一个Excel文档。

译注:从本篇开始,为了方便,仅保留了C#代码。对VB.NET感兴趣的朋友可以参见原文。

在MVC应用程序中,控制器action可以返回一个ActionResult。特别是,他能够返回一些从ActionResult基类继承的东西——

  • - ViewResult
  • - EmptyResult
  • - RedirectResult
  • - RedirectToRouteResult
  • - JsonResult
  • - ContentResult

例如,你可以使用ViewResult向浏览器返回一个特定的视图,使用ContentResult向浏览器返回文本内容。

但是,如果你想向浏览器返回其他类型的内容——如图片、PDF文件或Excel文档呢?在这些情况下,你可以创建自己的ActionResult。在这个Tip中,我会想你展示如何创建一个能返回Excel文档的ActionResult。

清单1包含了ExcelResult的代码。 

清单1 - ExcelResult.cs

  1using System;
  2using System.Web.Mvc;
  3using System.Data.Linq;
  4using System.Collections;
  5using System.IO;
  6using System.Web.UI.WebControls;
  7using System.Linq;
  8using System.Web;
  9using System.Web.UI;
 10using System.Drawing;
 11 
 12 
 13namespace 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}

所有的ActionResult都必须直接或间接继承自ActionResult基类。清单1中的ExcelResult就是这样,实际上,它直接继承了ActionResult类。ActionResult基类中有一个方法是必须实现的——Execute()方法。调用Execute()方法会生成ActionResult的结果产生的内容。

在清单1中,Execute()方法用于从Linq to SQL查询生成Excel文档。Execute()方法会调用WriteFile()方法将生成的Excel文档以正确的MIME类型写入到浏览器中。

通常,你不会从控制器action中直接返回一个ActionResult,而是利用Controller类提供的某个方法——

  • - View()
  • - Redirect()
  • - RedirectToAction()
  • - RedirectToRoute()
  • - Json()
  • - Content()

例如,如果你想从一个控制器action中返回一个视图,不要直接返回一个ViewResult,而是调用View()方法。View()方法会实例化一个ViewResult并将这个新的ViewResult返回给浏览器。

清单2中的代码包含三个应用于Controller类的扩展方法。这些扩展方法向Controller类添加了一个名为Excel()的方法。Excel()方法会返回一个ExcelResult。

清单2 - ExcelControllerExtensions.cs (C#) 

 1using System;
 2using System.Web.Mvc;
 3using System.Data.Linq;
 4using System.Collections;
 5using System.Web.UI.WebControls;
 6using System.Linq;
 7 
 8namespace Tip2
 9{
10    public static class ExcelControllerExtensions
11    {
12 
13        public static ActionResult Excel
14        (
15            this Controller controller,
16            DataContext dataContext,
17            IQueryable rows,
18            string fileName
19        )
20        {
21            return new ExcelResult(dataContext, rows, fileName, nullnullnullnull);
22        }

23 
24        public static ActionResult Excel
25        (
26            this Controller controller,
27            DataContext dataContext,
28            IQueryable rows,
29            string fileName,
30            string[] headers
31        )
32        {
33            return new ExcelResult(dataContext, rows, fileName, headers, nullnullnull);
34        }

35 
36        public static ActionResult Excel
37        (
38            this Controller controller, 
39            DataContext dataContext,
40            IQueryable rows, 
41            string fileName, 
42            string[] headers, 
43            TableStyle tableStyle, 
44            TableItemStyle headerStyle,
45            TableItemStyle itemStyle
46        )
47        {
48            return new ExcelResult(dataContext, rows, fileName, headers, tableStyle, headerStyle, itemStyle);
49        }

50 
51    }

52}

清单3中的控制器展示了如何在控制器中使用Excel()扩展方法。该控制器包含三个方法,名字分别是GenerateExcel1()、GenerateExcel2()和GenerateExcel3()。所有这三个控制器action都返回Excel文档,这些Excel是从Movies数据表生成的。

清单3 - HomeController.cs (C#)

 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Data.Linq;
 5using System.Data.Linq.Mapping;
 6using System.Web.UI.WebControls;
 7using System.Web;
 8using System.Web.Mvc;
 9using Tip2.Models;
10using Tip2;
11 
12