12/08/2018, 15:04

ASP.NET MVC Tip #2 - Tạo custom Action Result trả về Microsoft Excel Documents

Trong thủ thuật này, tôi chỉ cho bạn cách để tạo ra một custom action result mà bạn có thể trả lại từ một ASP.NET MVC controller action. action result này tạo ra một tài liệu Excel của Microsoft từ một LINQ to SQL query. Trong một ứng dụng MVC, một controller action trả về một kết quả hành động. ...

Trong thủ thuật này, tôi chỉ cho bạn cách để tạo ra một custom action result mà bạn có thể trả lại từ một ASP.NET MVC controller action. action result này tạo ra một tài liệu Excel của Microsoft từ một LINQ to SQL query.

Trong một ứng dụng MVC, một controller action trả về một kết quả hành động. Đặc biệt, nó sẽ trả về một cái gì đó mà xuất phát từ lớp cơ sở ActionResult như:

· ViewResult

· EmptyResult

· RedirectResult

· RedirectToRouteResult

· JsonResult

· ContentResult

Ví dụ, bạn sử dụng một ViewResult để trả lại một view cụ thể vào trình duyệt và một ContentResult trả về nội dung văn bản cho trình duyệt.

Nhưng nếu bạn muốn trả về một số loại khác của nội dung để trình duyệt như một hình ảnh, một tập tin PDF, hoặc một tài liệu Microsoft Excel? Trong những trường hợp này, bạn có thể tạo ra kết quả hành động của riêng bạn. Trong thủ thuật này, tôi chỉ cho bạn cách để tạo ra một kết quả hành động trả về một tài liệu Microsoft Excel.

Mã cho ExcelResult được chứa trong Liệt kê 1.

1 - ExcelResult.vb (VB)

1: Imports System
  2: Imports System.Web.Mvc
  3: Imports System.Data.Linq
  4: Imports System.Collections
  5: Imports System.IO
  6: Imports System.Web.UI.WebControls
  7: Imports System.Linq
  8: Imports System.Web
  9: Imports System.Web.UI
 10: Imports System.Drawing
 11:  
 12:  
 13: Namespace Tip2
 14:  
 15:     Public Class ExcelResult
 16:         Inherits ActionResult
 17:  
 18:         Private _dataContext As DataContext
 19:         Private _fileName As String
 20:         Private _rows As IQueryable
 21:         Private _headers() As String = Nothing
 22:  
 23:         Private _tableStyle As TableStyle
 24:         Private _headerStyle As TableItemStyle
 25:         Private _itemStyle As TableItemStyle
 26:  
 27:         Public ReadOnly Property FileName() As String
 28:             Get
 29:                 Return _fileName
 30:             End Get
 31:         End Property
 32:  
 33:         Public ReadOnly Property Rows() As IQueryable
 34:             Get
 35:                 Return _rows
 36:             End Get
 37:         End Property
 38:  
 39:  
 40:         Public Sub New(ByVal dataContext As DataContext, ByVal rows As IQueryable, ByVal fileName As String)
 41:             Me.New(dataContext, rows, fileName, Nothing, Nothing, Nothing, Nothing)
 42:         End Sub
 43:  
 44:         Public Sub New(ByVal dataContext As DataContext, ByVal fileName As String, ByVal rows As IQueryable, ByVal headers() As String)
 45:             Me.New(dataContext, rows, fileName, headers, Nothing, Nothing, Nothing)
 46:         End Sub
 47:  
 48:         Public Sub New(ByVal dataContext As DataContext, ByVal rows As IQueryable, ByVal fileName As String, ByVal headers() As String, ByVal tableStyle As TableStyle, ByVal headerStyle As TableItemStyle, ByVal itemStyle As TableItemStyle)
 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 Is Nothing Then
 59:                 _tableStyle = New TableStyle()
 60:                 _tableStyle.BorderStyle = BorderStyle.Solid
 61:                 _tableStyle.BorderColor = Color.Black
 62:                 _tableStyle.BorderWidth = Unit.Parse("2px")
 63:             End If
 64:             If _headerStyle Is Nothing Then
 65:                 _headerStyle = New TableItemStyle()
 66:                 _headerStyle.BackColor = Color.LightGray
 67:             End If
 68:         End Sub
 69:  
 70:         Public Overrides Sub ExecuteResult(ByVal context As ControllerContext)
 71:             ' Create HtmlTextWriter
 72:             Dim sw As StringWriter = New StringWriter()
 73:             Dim tw As HtmlTextWriter = New HtmlTextWriter(sw)
 74:  
 75:             ' Build HTML Table from Items
 76:             If Not _tableStyle Is Nothing Then
 77:                 _tableStyle.AddAttributesToRender(tw)
 78:             End If
 79:             tw.RenderBeginTag(HtmlTextWriterTag.Table)
 80:  
 81:             ' Generate headers from table
 82:             If _headers Is Nothing Then
 83:                 _headers = _dataContext.Mapping.GetMetaType(_rows.ElementType).PersistentDataMembers.Select(Function(m) m.Name).ToArray()
 84:             End If
 85:  
 86:  
 87:             ' Create Header Row
 88:             tw.RenderBeginTag(HtmlTextWriterTag.Thead)
 89:             For Each header As String In _headers
 90:                 If Not _headerStyle Is Nothing Then
 91:                     _headerStyle.AddAttributesToRender(tw)
 92:                 End If
 93:                 tw.RenderBeginTag(HtmlTextWriterTag.Th)
 94:                 tw.Write(header)
 95:                 tw.RenderEndTag()
 96:             Next
 97:             tw.RenderEndTag()
 98:  
 99:  
100:  
101:             ' Create Data Rows
102:             tw.RenderBeginTag(HtmlTextWriterTag.Tbody)
103:             For Each row As Object In _rows
104:                 tw.RenderBeginTag(HtmlTextWriterTag.Tr)
105:                 Dim header As String
106:                 For Each header In _headers
107:                     Dim strValue As String = row.GetType().GetProperty(header).GetValue(row, Nothing).ToString()
108:                     If Not _itemStyle Is Nothing Then
109:                         _itemStyle.AddAttributesToRender(tw)
110:                     End If
111:                     tw.RenderBeginTag(HtmlTextWriterTag.Td)
112:                     tw.Write(HttpUtility.HtmlEncode(strValue))
113:                     tw.RenderEndTag()
114:                 Next
115:                 tw.RenderEndTag()
116:             Next
117:             tw.RenderEndTag() ' tbody
118:  
119:             tw.RenderEndTag() ' table
120:             WriteFile(_fileName, "application/ms-excel", sw.ToString())
121:         End Sub
122:  
123:  
124:       
125:  
126:         Private Shared Sub WriteFile(ByVal fileName As String, ByVal contentType As String, ByVal content As String)
127:             Dim context As HttpContext = HttpContext.Current
128:             context.Response.Clear()
129:             context.Response.AddHeader("content-disposition", "attachment;filename=" + fileName)
130:             context.Response.Charset = ""
131:             context.Response.Cache.SetCacheability(HttpCacheability.NoCache)
132:             context.Response.ContentType = contentType
133:             context.Response.Write(content)
134:             context.Response.End()
135:         End Sub
136:     End Class
137: End Namespace
138:  

ExcelResult.cs (C#)

 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: }

Mỗi kết quả hành động phải kế thừa từ lớp cơ sở ActionResult. Lớp ExcelResult trên thực tế, kế thừa từ lớp cơ sở ActionResult. Các lớp cơ sở ActionResult có một method mà bạn phải thực hiện: hàm Execute (). Các method Execute () được gọi để tạo ra các nội dung được tạo ra bởi action result.

Hàm trên, Execute () được sử dụng để tạo ra các tài liệu Excel từ một truy vấn LINQ to SQL. Cáchàm Execute () gọi phương thức WriteFile () để viết các tài liệu Excel hoàn chỉnh tới trình duyệt với kiểu MIME đúng.

Thông thường, bạn không trả về action result từ 1 controller actionn trực tiếp. Thay vào đó, bạn tận dụng lợi thế của một trong những phương thức của lớp điều khiển:

View()

· Redirect()

· RedirectToAction()

· RedirectToRoute()

· Json()

· Content()

Ví dụ, nếu bạn muốn quay trở lại một view từ một controller action, bạn không trả về một ViewResult. Thay vào đó, bạn gọi phương thức View (). Phương thức View () khởi tạo một ViewResult mới và trả về ViewResult mới cho trình duyệt.

Mã trong List 2 bao gồm ba phương thức mở rộng được áp dụng cho các lớp điều khiển. Những phương pháp mở rộng thêm một phương thức mới có tên là Excel () đến các lớp điều khiển. Các phương thức Excel () trả về một ExcelResult ().

Listing 2 –ExcelControllerExtensions.vb (VB)

1: Imports System
 2: Imports System.Web.Mvc
 3: Imports System.Data.Linq
 4: Imports System.Collections
 5: Imports System.Web.UI.WebControls
 6: Imports System.Linq
 7: Imports System.Runtime.CompilerServices
 8:  
 9: Namespace Tip2
10:     Public Module ExcelControllerExtensions
11:  
12:         <Extension()> _
13:         Function Excel(ByVal controller As Controller, ByVal dataContext As DataContext, ByVal rows As IQueryable, ByVal fileName As String) As ActionResult
14:             Return New ExcelResult(DataContext, rows, fileName, Nothing, Nothing, Nothing, Nothing)
15:         End Function
16:  
17:         <Extension()> _
18:         Function Excel(ByVal controller As Controller, ByVal dataContext As DataContext, ByVal rows As IQueryable, ByVal fileName As String, ByVal headers As String()) As ActionResult
19:             Return New ExcelResult(dataContext, rows, fileName, headers, Nothing, Nothing, Nothing)
20:         End Function
21:  
22:         <Extension()> _
23:         Function Excel(ByVal controller As Controller, ByVal dataContext As DataContext, ByVal rows As IQueryable, ByVal fileName As String, ByVal headers As String(), ByVal tableStyle As TableStyle, ByVal headerStyle As TableItemStyle, ByVal itemStyle As TableItemStyle) As ActionResult
24:             Return New ExcelResult(dataContext, rows, fileName, headers, tableStyle, headerStyle, itemStyle)
25:         End Function
26:  
27:     End Module
28: End Namespace

Listing 2 –ExcelControllerExtensions.cs (C#)

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:  
 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, null, null, null, null);
 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, null, null, null);
 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: }

Các bộ điều khiển trong Liệt kê 3 cho thấy làm thế nào bạn có thể sử dụng phương thức mở rộng Excel () trong một bộ điều khiển. Bộ điều khiển này bao gồm ba phương thức đặt tên là GenerateExcel1 (), GenerateExcel2 (), và GenerateExcel3 (). Cả ba phương thứccủa controller action trả về một tài liệu Excel bằng cách tạo ra các tài liệu từ các bảng cơ sở dữ liệu phim.

Listing 3 – HomeController.vb (VB)

   1: Imports System
   2: Imports System.Collections.Generic
   3: Imports System.Linq
   4: Imports System.Data.Linq
   5: Imports System.Data.Linq.Mapping
   6: Imports System.Web.UI.WebControls
   7: Imports System.Web
   8: Imports System.Web.Mvc
   9: Imports Tip2
  10:  
  11: Namespace Tip2.Controllers
  12:     Public Class HomeController
  13:         Inherits Controller
  14:  
  15:         Private db As New MovieDataContext()
  16:  
  17:         Public Function Index() As ActionResult
  18:             Return View()
  19:         End Function
  20:  
  21:         ' <summary>
  22:         ' Generates Excel document using headers grabbed from property names
  23:         ' </summary>
  24:         Public Function GenerateExcel1() As ActionResult
  25:             Return Me.Excel(db, db.Movies, "data.xls")
  26:         End Function
  27:  
  28:         ' <summary>
  29:         ' Generates Excel document using supplied headers
  30:         ' </summary>
  31:         Public Function GenerateExcel2() As ActionResult
  32:             Dim rows = From m In db.Movies Select New With {.Title = m.Title, .Director = m.Director}
  33:  
  34:             Return Me.Excel(db, rows, "data.xls", New String() {"Title", "Director"})
  35:         End Function
  36:  
  37:  
  38:         ' <summary>
  39:         ' Generates Excel document using supplied headers and using supplied styles
  40:         ' </summary>
  41:         Public Function GenerateExcel3() As ActionResult
  42:             Dim rows = From m In db.Movies Select New With {.Title = m.Title, .Director = m.Director}
  43:  
  44:             Dim headerStyle As New TableItemStyle()
  45:             headerStyle.BackColor = System.Drawing.Color.Orange
  46:             Return Me.Excel(db, rows, "data.xls", New String() {"Title", "Director"}, Nothing, headerStyle, Nothing)
  47:         End Function
  48:  
  49:  
  50:     End Class
  51: End Namespace

Listing 3 – HomeController.cs (C#)

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:     }
54: }

Cuối cùng, view index.aspx trong List 4 cho thấy làm thế nào bạn có thể gọi GenerateExcel () để tạo ra các tài liệu Excel. Chú ý ba liên kết với ba phiên bản khác nhau của GenerateExcel.

Listing 4 – Index.aspx

1: <%@ Page Language="VB" AutoEventWireup="false" CodeBehind="Index.aspx.vb" Inherits="Tip2.Index" %>
2: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3:  
4: <html xmlns="http://www.w3.org/1999/xhtml" >
5: <head id="Head1" runat="server">
6:     <title>Index Page</title>
7:     <style type="text/css">
8:     
9:     li
10:     {
11:         margin-bottom: 5px;
12:     }
13:     
14:     </style>
15: </head>
16: <body>
17:     <div>
18:     
19:     <h1>Generate Microsoft Excel Document</h1>
20:     
21:     
22:     <ul>
23:         <li>
24:         <a href="/Home/GenerateExcel1">Generate</a> - Generates an Excel document by using the entity property names for column headings and the default
25:         formatting.        
26:         </li>
27:         <li>
28:         <a href="/Home/GenerateExcel2">Generate</a> - Generates an Excel document by using supplied header names and default formatting.        
29:         </li>
30:         <li>
31:         <a href="/Home/GenerateExcel3">Generate</a> - Generates an Excel document by using supplied header names and supplied formatting.        
32:         </li>
33:  
34:     </ul>
35:     
36:     
37:     
38:     
39:     </div>
40: </body>
41: </html>

Khi bạn mở giao diện Index, bạn sẽ thấy các trang trong hình 1. Figure 1 – The Index.aspx View alt

Khi bạn nhấp vào một trong các liên kết Generate Excel, bạn sẽ có được các tài liệu Excel khác nhau. Ví dụ, sau khi bạn nhấp vào liên kết đầu tiên, bạn sẽ có được các tài liệu Excel trong hình 2.

Figure 2 – Data.xls alt

Một lưu ý : Khi bạn bấm vào một liên kết để tạo ra các tài liệu Excel, bạn nhận được cảnh báo trong hình 3. Thật không may, không có cách nào xung quanh hiển thị cảnh báo này (để tìm hiểu thêm về cảnh báo này, xem http://blogs.msdn.com/vsofficedeveloper/ trang / Excel-2007-Gia-Warning.aspx ).

Hình 3 - Cảnh báo từ Microsoft Internet Explorer alt

Bạn có thể làm theo phương pháp tương tự được thảo luận trong các tip này để tạo ra các loại khác của các action result. Ví dụ, bạn có thể tạo ra action result hình ảnh, action result Microsoft Word, hoặc action result PDF. Download Code

Nguồn: https://weblogs.asp.net/stephenwalther/asp-net-mvc-tip-2-create-a-custom-action-result-that-returns-microsoft-excel-documents

0