该篇文章是Stephen Walther博客中的文章,个人觉得不错就翻译了一下。但由于个人英语水平有限,还望各位海量。如果想看原文,请点击ASP.NET MVC Tip #2 - Create a custom Action Result that returns Microsoft Excel Documents查看原文
在这篇条目中,我会展示给大家创建一个能够返回Asp.net MVC的Controller 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,
null
,
null
,
null
,
null
)
39
{
40
}
41
42
public
ExcelResult(DataContext dataContext,
string
fileName, IQueryable rows,
string
[] headers)
43
:
this
(dataContext, rows, fileName, headers,
null
,
null
,
null
)
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,
null
,
null
,
null
,
null
);
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,
null
,
null
,
null
);
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
<
a
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
<
a
href
="/Home/GenerateExcel2"
>
Generate
</
a
>
- Generates an Excel document by using supplied header names and default formatting.
11
</
li
>
12
<
li
>
13
<
a
href
="/Home/GenerateExcel3"
>
Generate
</
a
>
- Generates an Excel document by using supplied header names and supplied formatting.
14
</
li
>
15
16
</
ul
>
下载源代码