lASP.NET MVC系列文章
【02】浅谈Google Chrome浏览器(操作篇)(上)
【03】浅谈Google Chrome浏览器(操作篇)(下)
【04】浅谈ASP.NET框架
【07】浅谈ASP.NET MVC 路由
【08】浅谈ASP.NET MVC 视图
【10】浅谈jqGrid 在ASP.NET MVC中增删改查
【13】浅谈NuGet在VS中的运用
【14】浅谈ASP.NET 程序发布过程
一 引入背景
我们知道,MVC基架为我们提供了很多基础类,当需要使用时,只需调用即可,以ActionResult为例,其有很多子类,如ContentResult,EmptyResult,FileResult,HttpStatusCodeResult,JavaScriptResult,JsonResult,RedirectResult,RedirectToRouteResult,ViewResultBase,FileContentResult,FilePathResult,FileStreamResult,ViewResult,PartialResult,
然而,尽管MVC基架提供了众多类供我们调用,但却并不是包括所有功能的类,比如,我需要返回XML格式的数据,或下载CSV格式的数据,此时,MVC基架就没提供相应的类。因此,MVC类的扩展就迫在眉睫了。
在本篇文章中,主要讲解MVC比较核心的八大扩展类,一共分为两篇,即浅谈ASP.NET MVC八大类扩展(上篇)和浅谈ASP.NET MVC八大类扩展(下篇)。
其中,本篇文章主要讲解MVC基架提供的ActionResult及其子孙类,自定义扩展XMLResult和CsvResult,下篇文章将讲解剩下的七大类自定义扩展:Filter扩展,RazorViewEngine扩展,HtmlHelper扩展,Validator扩展,ModelBinder扩展,ControllerFactory注入扩展,Lambda 树扩展。
二 ASP.NET MVC扩展概述
但凡涉及到架构,我们首先都会关心安全性,稳定性,可扩展性等特征,当然,ASO.NET MVC也不例外,MVC之所以比WebForm流行,不仅仅在于其实现前后端的松耦合,而且其也支持强大的自定义扩展,在本篇文章中,我们就是运用MVC支持自定义扩展这一特性来进行自定义扩展,从而实现个性化项目需求。
三 代码实例
(一) ActionResult扩展
1 AtionResult内置扩展
ASP.NET MVC提供了如下内置扩展类.
1.1 上图简要概述
(1)ActionResult类继承Object类;
(2)ContentResult,EmptyResult,FileResult,HttpStatusCodeResult,JavaScriptResult,JsonResult,ViewResultBase,RedirectToRouteResult,RedirectResult 九大类继承类ActionResult;
(3)FileContentResult,FilePathResult,FileStreamResult 三大类继承类FileResult;
(4)ViewResult,PartialViewResult两大类继承类ViewResultBase;
1.2 ActionResult讲解
功能:封装一个操作方法的结果并用于代表该操作方法执行框架级操作。
在Mvc中,我们对如下代码再熟悉不过了。
public ActionResult Index() { return View();
}
F12查看ActionResult定义
1 namespace System.Web.Mvc 2 { 3 // 4 // 摘要: 5 // 表示操作方法的结果。 6 public abstract class ActionResult 7 { 8 // 9 // 摘要: 10 // 初始化 System.Web.Mvc.ActionResult 类的新实例。 11 protected ActionResult(); 12 13 // 14 // 摘要: 15 // 通过从 System.Web.Mvc.ActionResult 类继承的自定义类型,启用对操作方法结果的处理。 16 // 17 // 参数: 18 // context: 19 // 用于执行结果的上下文。上下文信息包括控制器、HTTP 内容、请求上下文和路由数据。 20 public abstract void ExecuteResult(ControllerContext context); 21 } 22 }
不难看出,ActionResult具有如下特征:
(1)抽象类;
(2)一个只可继承的构造函数;
(3)一个未实现的抽象方法;
1.2.1 ContentResult讲解
功能:表示用户定义的内容类型,该类型是操作方法的结果。
定义:查看定义
不难看出,ContentResult具有如下特征:
(1)继承自类ActionResult
(2)包含一个构造方法,一个重写ActionResultl类的抽象方法ExecuteResult(ControllerContext context),和三个属性;
(3)完整定义
1 public class ContentResult : ActionResult 2 { 3 // Methods 4 public override void ExecuteResult(ControllerContext context) 5 { 6 if (context == null) 7 { 8 throw new ArgumentNullException("context"); 9 } 10 HttpResponseBase response = context.HttpContext.Response; 11 if (!string.IsNullOrEmpty(this.ContentType)) 12 { 13 response.ContentType = this.ContentType; 14 } 15 if (this.ContentEncoding != null) 16 { 17 response.ContentEncoding = this.ContentEncoding; 18 } 19 if (this.Content != null) 20 { 21 response.Write(this.Content); 22 } 23 } 24 25 // Properties 26 public string Content { get; set; } 27 28 public Encoding ContentEncoding { get; set; } 29 30 public string ContentType { get; set; } 31 } 32 33
(4)我们来看看具体例子:
如我们向页面输出“Alan_beijing”,可采取如下两种方式。
方式一:
1 public ContentResult ContextResultTest() 2 { 3 return Content("Alan_beijing"); 4 }
测试结果
方式二
1 public ContentResult ContextResultTest() 2 { 3 //string str = "<html>" + "<head></head>" + "<body>" + "Alan_beijing" + "</body>" + "</html>"; 4 string str = "<html><head></head></body>Alan_beijing</body></html>"; 5 return Content(str); 6 }
测试结果
总之,大家在使用时,可以把ContentResult当作Responce.Write()使用。
1.2.2 EmptyResult
功能:表示一个不执行任何操作的结果,如不返回任何内容的控制器操作方法。
(1)查看定义
(2)完整定义
1 public class EmptyResult : ActionResult 2 { 3 // Fields 4 private static readonly EmptyResult _singleton = new EmptyResult(); 5 6 // Methods 7 public override void ExecuteResult(ControllerContext context) 8 { 9 } 10 11 // Properties 12 internal static EmptyResult Instance => 13 _singleton; 14 }
(3)总结
EmptyResult不执行任何操作,相当于如下功能。
1 public ContentResult ContextResultTest() 2 { 3 return Content(""); 4 }
1.2.3 FileResult
功能:表示一个用于将二进制文件内容发送到响应的基类。
(1)查看定义
(2)完整定义
1 public abstract class FileResult : ActionResult 2 { 3 // Fields 4 private string _fileDownloadName; 5 6 // Methods 7 protected FileResult(string contentType) 8 { 9 if (string.IsNullOrEmpty(contentType)) 10 { 11 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "contentType"); 12 } 13 this.ContentType = contentType; 14 } 15 16 public override void ExecuteResult(ControllerContext context) 17 { 18 if (context == null) 19 { 20 throw new ArgumentNullException("context"); 21 } 22 HttpResponseBase response = context.HttpContext.Response; 23 response.ContentType = this.ContentType; 24 if (!string.IsNullOrEmpty(this.FileDownloadName)) 25 { 26 string headerValue = ContentDispositionUtil.GetHeaderValue(this.FileDownloadName); 27 context.HttpContext.Response.AddHeader("Content-Disposition", headerValue); 28 } 29 this.WriteFile(response); 30 } 31 32 protected abstract void WriteFile(HttpResponseBase response); 33 34 // Properties 35 public string ContentType { get; private set; } 36 37 public string FileDownloadName 38 { 39 get => 40 (this._fileDownloadName ?? string.Empty); 41 set 42 { 43 this._fileDownloadName = value; 44 } 45 } 46 47 // Nested Types 48 internal static class ContentDispositionUtil 49 { 50 // Fields 51 private const string HexDigits = "0123456789ABCDEF"; 52 53 // Methods 54 private static void AddByteToStringBuilder(byte b, StringBuilder builder) 55 { 56 builder.Append('%'); 57 int num = b; 58 AddHexDigitToStringBuilder(num >> 4, builder); 59 AddHexDigitToStringBuilder(num % 0x10, builder); 60 } 61 62 private static void AddHexDigitToStringBuilder(int digit, StringBuilder builder) 63 { 64 builder.Append("0123456789ABCDEF"[digit]); 65 } 66 67 private static string CreateRfc2231HeaderValue(string filename) 68 { 69 StringBuilder builder = new StringBuilder("attachment; filename*=UTF-8''"); 70 foreach (byte num in Encoding.UTF8.GetBytes(filename)) 71 { 72 if (IsByteValidHeaderValueCharacter(num)) 73 { 74 builder.Append((char) num); 75 } 76 else 77 { 78 AddByteToStringBuilder(num, builder); 79 } 80 } 81 return builder.ToString(); 82 } 83 84 public static string GetHeaderValue(string fileName) 85 { 86 foreach (char ch in fileName) 87 { 88 if (ch > 'x007f') 89 { 90 return CreateRfc2231HeaderValue(fileName); 91 } 92 } 93 ContentDisposition disposition = new ContentDisposition { 94 FileName = fileName 95 }; 96 return disposition.ToString(); 97 } 98 99 private static bool IsByteValidHeaderValueCharacter(byte b) 100 { 101 if ((0x30 <= b) && (b <= 0x39)) 102 { 103 return true; 104 } 105 if ((0x61 <= b) && (b <= 0x7a)) 106 { 107 return true; 108 } 109 if ((0x41 <= b) && (b <= 90)) 110 { 111 return true; 112 } 113 switch (b) 114 { 115 case 0x3a: 116 case 0x5f: 117 case 0x7e: 118 case 0x24: 119 case 0x26: 120 case 0x21: 121 case 0x2b: 122 case 0x2d: 123 case 0x2e: 124 return true; 125 } 126 return false; 127 } 128 } 129 }
1.2.4 HttpStatusCodeResult
功能:提供一种用于返回带特定 HTTP 响应状态代码和说明的操作结果的方法。
(1)定义
(2)完整定义
1 public class HttpStatusCodeResult : ActionResult 2 { 3 // Methods 4 public HttpStatusCodeResult(int statusCode) : this(statusCode, null) 5 { 6 } 7 8 public HttpStatusCodeResult(HttpStatusCode statusCode) : this(statusCode, null) 9 { 10 } 11 12 public HttpStatusCodeResult(int statusCode, string statusDescription) 13 { 14 this.StatusCode = statusCode; 15 this.StatusDescription = statusDescription; 16 } 17 18 public HttpStatusCodeResult(HttpStatusCode statusCode, string statusDescription) : this((int) statusCode, statusDescription) 19 { 20 } 21 22 public override void ExecuteResult(ControllerContext context) 23 { 24 if (context == null) 25 { 26 throw new ArgumentNullException("context"); 27 } 28 context.HttpContext.Response.StatusCode = this.StatusCode; 29 if (this.StatusDescription != null) 30 { 31 context.HttpContext.Response.StatusDescription = this.StatusDescription; 32 } 33 } 34 35 // Properties 36 public int StatusCode { get; private set; } 37 38 public string StatusDescription { get; private set; } 39 }
1.2.5 JavaScriptResult
功能:将 JavaScript 内容发送到响应。
(1)定义
(2)完整定义
1 public class JavaScriptResult : ActionResult 2 { 3 // Methods 4 public override void ExecuteResult(ControllerContext context) 5 { 6 if (context == null) 7 { 8 throw new ArgumentNullException("context"); 9 } 10 HttpResponseBase response = context.HttpContext.Response; 11 response.ContentType = "application/x-javascript"; 12 if (this.Script != null) 13 { 14 response.Write(this.Script); 15 } 16 } 17 18 // Properties 19 public string Script { get; set; } 20 }
1.2.6 JsonResult
功能:表示一个类,该类用于将 JSON 格式的内容发送到响应。
(1)定义
(2)完整定义
1 public class JsonResult : ActionResult 2 { 3 // Methods 4 public JsonResult() 5 { 6 this.JsonRequestBehavior = JsonRequestBehavior.DenyGet; 7 } 8 9 public override void ExecuteResult(ControllerContext context) 10 { 11 if (context == null) 12 { 13 throw new ArgumentNullException("context"); 14 } 15 if ((this.JsonRequestBehavior == JsonRequestBehavior.DenyGet) && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) 16 { 17 throw new InvalidOperationException(MvcResources.JsonRequest_GetNotAllowed); 18 } 19 HttpResponseBase response = context.HttpContext.Response; 20 if (!string.IsNullOrEmpty(this.ContentType)) 21 { 22 response.ContentType = this.ContentType; 23 } 24 else 25 { 26 response.ContentType = "application/json"; 27 } 28 if (this.ContentEncoding != null) 29 { 30 response.ContentEncoding = this.ContentEncoding; 31 } 32 if (this.Data != null) 33 { 34 JavaScriptSerializer serializer = new JavaScriptSerializer(); 35 if (this.MaxJsonLength.HasValue) 36 { 37 serializer.MaxJsonLength = this.MaxJsonLength.Value; 38 } 39 if (this.RecursionLimit.HasValue) 40 { 41 serializer.RecursionLimit = this.RecursionLimit.Value; 42 } 43 response.Write(serializer.Serialize(this.Data)); 44 } 45 } 46 47 // Properties 48 public Encoding ContentEncoding { get; set; } 49 50 public string ContentType { get; set; } 51 52 public object Data { get; set; } 53 54 public JsonRequestBehavior JsonRequestBehavior { get; set; } 55 56 public int? MaxJsonLength { get; set; } 57 58 public int? RecursionLimit { get; set; } 59 }
(3)总结
JsonResult首先将指定的对象序列化为Json字符串,然后将字符串写入到HTTP输出流。
1.2.7 RedirectResult
功能:通过重定向到指定的 URI 来控制对应用程序操作的处理。
(1)定义
(2)完整定义
1 public class RedirectResult : ActionResult 2 { 3 // Methods 4 public RedirectResult(string url) : this(url, false) 5 { 6 } 7 8 public RedirectResult(string url, bool permanent) 9 { 10 if (string.IsNullOrEmpty(url)) 11 { 12 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "url"); 13 } 14 this.Permanent = permanent; 15 this.Url = url; 16 } 17 18 public override void ExecuteResult(ControllerContext context) 19 { 20 if (context == null) 21 { 22 throw new ArgumentNullException("context"); 23 } 24 if (context.IsChildAction) 25 { 26 throw new InvalidOperationException(MvcResources.RedirectAction_CannotRedirectInChildAction); 27 } 28 string url = UrlHelper.GenerateContentUrl(this.Url, context.HttpContext); 29 context.Controller.TempData.Keep(); 30 if (this.Permanent) 31 { 32 context.HttpContext.Response.RedirectPermanent(url, false); 33 } 34 else 35 { 36 context.HttpContext.Response.Redirect(url, false); 37 } 38 } 39 40 // Properties 41 public bool Permanent { get; private set; } 42 43 public string Url { get; private set; } 44 }
1.2.8 RedirectToRouteResult
功能:表示使用指定的路由值字典来执行重定向的结果。
(1)定义
(2)完整定义
1 public class RedirectToRouteResult : ActionResult 2 { 3 // Fields 4 private RouteCollection _routes; 5 6 // Methods 7 public RedirectToRouteResult(RouteValueDictionary routeValues) : this(null, routeValues) 8 { 9 } 10 11 public RedirectToRouteResult(string routeName, RouteValueDictionary routeValues) : this(routeName, routeValues, false) 12 { 13 } 14 15 public RedirectToRouteResult(string routeName, RouteValueDictionary routeValues, bool permanent) 16 { 17 this.Permanent = permanent; 18 this.RouteName = routeName ?? string.Empty; 19 this.RouteValues = routeValues ?? new RouteValueDictionary(); 20 } 21 22 public override void ExecuteResult(ControllerContext context) 23 { 24 if (context == null) 25 { 26 throw new ArgumentNullException("context"); 27 } 28 if (context.IsChildAction) 29 { 30 throw new InvalidOperationException(MvcResources.RedirectAction_CannotRedirectInChildAction); 31 } 32 string str = UrlHelper.GenerateUrl(this.RouteName, null, null, this.RouteValues, this.Routes, context.RequestContext, false); 33 if (string.IsNullOrEmpty(str)) 34 { 35 throw new InvalidOperationException(MvcResources.Common_NoRouteMatched); 36 } 37 context.Controller.TempData.Keep(); 38 if (this.Permanent) 39 { 40 context.HttpContext.Response.RedirectPermanent(str, false); 41 } 42 else 43 { 44 context.HttpContext.Response.Redirect(str, false); 45 } 46 } 47 48 // Properties 49 public bool Permanent { get; private set; } 50 51 public string RouteName { get; private set; } 52 53 internal RouteCollection Routes 54 { 55 get 56 { 57 if (this._routes == null) 58 { 59 this._routes = RouteTable.Routes; 60 } 61 return this._routes; 62 } 63 set 64 { 65 this._routes = value; 66 } 67 } 68 69 public RouteValueDictionary RouteValues { get; private set; } 70 }
1.2.9 ViewResultBase
功能:表示一个用于为视图提供模型并向响应呈现视图的基类。
(1)定义
(2)完整定义
1 public abstract class ViewResultBase : ActionResult 2 { 3 // Fields 4 private DynamicViewDataDictionary _dynamicViewData; 5 private TempDataDictionary _tempData; 6 private ViewDataDictionary _viewData; 7 private ViewEngineCollection _viewEngineCollection; 8 private string _viewName; 9 10 // Methods 11 protected ViewResultBase() 12 { 13 } 14 15 public override void ExecuteResult(ControllerContext context) 16 { 17 if (context == null) 18 { 19 throw new ArgumentNullException("context"); 20 } 21 if (string.IsNullOrEmpty(this.ViewName)) 22 { 23 this.ViewName = context.RouteData.GetRequiredString("action"); 24 } 25 ViewEngineResult result = null; 26 if (this.View == null) 27 { 28 result = this.FindView(context); 29 this.View = result.View; 30 } 31 TextWriter output = context.HttpContext.Response.Output; 32 ViewContext viewContext = new ViewContext(context, this.View, this.ViewData, this.TempData, output); 33 this.View.Render(viewContext, output); 34 if (result != null) 35 { 36 result.ViewEngine.ReleaseView(context, this.View); 37 } 38 } 39 40 protected abstract ViewEngineResult FindView(ControllerContext context); 41 42 // Properties 43 public object Model => 44 this.ViewData.Model; 45 46 public TempDataDictionary TempData 47 { 48 get 49 { 50 if (this._tempData == null) 51 { 52 this._tempData = new TempDataDictionary(); 53 } 54 return this._tempData; 55 } 56 set 57 { 58 this._tempData = value; 59 } 60 } 61 62 public IView View { get; set; } 63 64 [Dynamic] 65 public object ViewBag 66 { 67 [return: Dynamic] 68 get 69 { 70 Func<ViewDataDictionary> viewDataThunk = null; 71 if (this._dynamicViewData == null) 72 { 73 if (viewDataThunk == null) 74 { 75 viewDataThunk = () => this.ViewData; 76 } 77 this._dynamicViewData = new DynamicViewDataDictionary(viewDataThunk); 78 } 79 return this._dynamicViewData; 80 } 81 } 82 83 public ViewDataDictionary ViewData 84 { 85 get 86 { 87 if (this._viewData == null) 88 { 89 this._viewData = new ViewDataDictionary(); 90 } 91 return this._viewData; 92 } 93 set 94 { 95 this._viewData = value; 96 } 97 } 98 99 public ViewEngineCollection ViewEngineCollection 100 { 101 get => 102 (this._viewEngineCollection ?? ViewEngines.Engines); 103 set 104 { 105 this._viewEngineCollection = value; 106 } 107 } 108 109 public string ViewName 110 { 111 get => 112 (this._viewName ?? string.Empty); 113 set 114 { 115 this._viewName = value; 116 } 117 } 118 }
1.2.10 FileContentResult
功能:将二进制文件的内容发送到响应
定义:
1 public class FileContentResult : FileResult 2 { 3 // Methods 4 public FileContentResult(byte[] fileContents, string contentType) : base(contentType) 5 { 6 if (fileContents == null) 7 { 8 throw new ArgumentNullException("fileContents"); 9 } 10 this.FileContents = fileContents; 11 } 12 13 protected override void WriteFile(HttpResponseBase response) 14 { 15 response.OutputStream.Write(this.FileContents, 0, this.FileContents.Length); 16 } 17 18 // Properties 19 public byte[] FileContents { get; private set; } 20 }
1.2.11 FilePathResult
功能:将文件的内容发送到响应。
定义:
1 public class FilePathResult : FileResult 2 { 3 // Methods 4 public FilePathResult(string fileName, string contentType) : base(contentType) 5 { 6 if (string.IsNullOrEmpty(fileName)) 7 { 8 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "fileName"); 9 } 10 this.FileName = fileName; 11 } 12 13 protected override void WriteFile(HttpResponseBase response) 14 { 15 response.TransmitFile(this.FileName); 16 } 17 18 // Properties 19 public string FileName { get; private set; } 20 }
1.2.12 FilestreamResult
功能:使用Stream实例将二进制内容发送到响应。
定义:
1 public class FileStreamResult : FileResult 2 { 3 // Fields 4 private const int BufferSize = 0x1000; 5 6 // Methods 7 public FileStreamResult(Stream fileStream, string contentType) : base(contentType) 8 { 9 if (fileStream == null) 10 { 11 throw new ArgumentNullException("fileStream"); 12 } 13 this.FileStream = fileStream; 14 } 15 16 protected override void WriteFile(HttpResponseBase response) 17 { 18 Stream outputStream = response.OutputStream; 19 using (this.FileStream) 20 { 21 byte[] buffer = new byte[0x1000]; 22 while (true) 23 { 24 int count = this.FileStream.Read(buffer, 0, 0x1000); 25 if (count == 0) 26 { 27 return; 28 } 29 outputStream.Write(buffer, 0, count); 30 } 31 } 32 } 33 34 // Properties 35 public Stream FileStream { get; private set; } 36 }
1.2.13 ViewResult
功能:表示一个类,该类用于使用由IViewEngine对象返回的IView实例来呈现视图。
(1)定义:
1 public class ViewResult : ViewResultBase 2 { 3 // Fields 4 private string _masterName; 5 6 // Methods 7 protected override ViewEngineResult FindView(ControllerContext context) 8 { 9 ViewEngineResult result = base.ViewEngineCollection.FindView(context, base.ViewName, this.MasterName); 10 if (result.View != null) 11 { 12 return result; 13 } 14 StringBuilder builder = new StringBuilder(); 15 foreach (string str in result.SearchedLocations) 16 { 17 builder.AppendLine(); 18 builder.Append(str); 19 } 20 throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.Common_ViewNotFound, new object[] { base.ViewName, builder })); 21 } 22 23 // Properties 24 public string MasterName 25 { 26 get => 27 (this._masterName ?? string.Empty); 28 set 29 { 30 this._masterName = value; 31 } 32 } 33 }
1.2.14 PartialResult
功能:表示一个用于将分部视图发送到响应的基类。
(1)定义:
1 public class PartialViewResult : ViewResultBase 2 { 3 // Methods 4 protected override ViewEngineResult FindView(ControllerContext context) 5 { 6 ViewEngineResult result = base.ViewEngineCollection.FindPartialView(context, base.ViewName); 7 if (result.View != null) 8 { 9 return result; 10 } 11 StringBuilder builder = new StringBuilder(); 12 foreach (string str in result.SearchedLocations) 13 { 14 builder.AppendLine(); 15 builder.Append(str); 16 } 17 throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.Common_PartialViewNotFound, new object[] { base.ViewName, builder })); 18 } 19 }
2 ActionResult自定义扩展
关于ActionResult的自定义扩展,满足两个条件
(1)继承ActionResult
(2)重写ExecuteResult()方法
2.1 XMLResult
public class XmlResult : ActionResult { private object _data; public XmlResult(object data) { _data = data; } public override void ExecuteResult(ControllerContext context) { var serializer = new XmlSerializer(_data.GetType()); var response = context.HttpContext.Response; response.ContentType = "text/xml"; serializer.Serialize(response.Output, _data); } }
Controller
public XmlResult GetEmpInfo() { EmpInfo empInfo = new EmpInfo() { Name = "Alan_beijing", Address = "China-ShangHai", Age=40 }; return new XmlResult(empInfo); }
Test Result
2.2 CsvResult
public class CsvResult : FileResult { private IEnumerable _data; public CsvResult(IEnumerable data, string fileName) : base("text/csv") { _data = data; FileDownloadName = fileName; } protected override void WriteFile(HttpResponseBase response) { var builder = new StringBuilder(); var strWriter = new StringWriter(builder); foreach (var item in _data) { var properties = item.GetType().GetProperties(); foreach (var prop in properties) { strWriter.Write(GetValue(item, prop.Name)); strWriter.Write(", "); } strWriter.WriteLine(); } response.Write(builder); } public static string GetValue(object item, string propName) { return item.GetType().GetProperty(propName).GetValue(item, null).ToString() ?? ""; } }
Controller
public CsvResult DownCsvEmpInfo() { EmpInfo empInfo = new EmpInfo() { Name = "Alan_beijing", Address = "China-ShangHai", Age = 40 }; return new CsvResult(new List<EmpInfo>() { empInfo }, "empInfo"); }
测试结果
四 推荐网址
【01】https://msdn.microsoft.com/zh-cn/library/system.web.mvc.actionresult(v=vs.118).aspx
五 后续
敬请等待下一篇......
六 服务区
有喜欢的朋友,可以看一下,不喜欢的的朋友,勿喷,谢谢!!