HTML5技术

玩转Asp.net MVC 的八个扩展点 - richiezhang

字号+ 作者:H5之家 来源:博客园 2016-02-05 09:45 我要评论( )

MVC模型以低耦合、可重用、可维护性高等众多优点已逐渐代替了WebForm模型。能够灵活使用MVC提供的扩展点可以达到事半功倍的效果,另一方面Asp.net MVC优秀的设计和高质量的代码也值得我们去阅读和学习。 本文将介绍Asp.net MVC中常用的八个扩展点并举例说明

MVC模型以低耦合、可重用、可维护性高等众多优点已逐渐代替了WebForm模型。能够灵活使用MVC提供的扩展点可以达到事半功倍的效果,另一方面Asp.net MVC优秀的设计和高质量的代码也值得我们去阅读和学习。

本文将介绍Asp.net MVC中常用的八个扩展点并举例说明。

一、ActionResult

ActionResult代表了每个Action的返回结果。asp.net mvc提供了众多内置的ActionResult类型,如:ContentResult,ViewResult,JsonResult等,每一种类型都代表了一种服务端的Response类型。我们什么时候需要使用这个扩展点呢?

假如客户端需要得到XML格式的数据列表:

public void GetUser() { var user = new UserViewModel() { Name = "richie", Age = 20, Email = "abc@126.com", Phone = "139********", Address = "my address" }; XmlSerializer serializer = new XmlSerializer(typeof(UserViewModel)); Response.ContentType = "text/xml"; serializer.Serialize(Response.Output, user); }

我们可以在Controller中定义一个这样的方法,但是这个方法定义在Controller中有一点别扭,在MVC中每个Action通常都需要返回ActionResult类型,其次XML序列化这段代码完全可以重用。经过分析我们可以自定义一个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); } }

这时候Action就可以返回这种类型了:

public XmlResult GetUser() { var user = new UserViewModel() { Name = "richie", Age = 20, Email = "abc@126.com", Phone = "139********", Address = "my address" }; return new XmlResult(user); }

同样的道理,你可以定义出其他的ActionResult类型,例如:CsvResult等。

二、Filter

MVC中有四种类型的Filter:IAuthorizationFilter,IActionFilter,IResultFilter,IExceptionFilter

这四个接口有点拦截器的意思,例如:当有异常出现时会被IExceptionFilter类型的Filter拦截,当Action在执行前和执行结束会被IActionFilter类型的Filter拦截。

通过实现IExceptionFilter我们可以自定义一个用来记录日志的Log4NetExceptionFilter:

public class Log4NetExceptionFilter : IExceptionFilter { private readonly ILog _logger; public Log4NetExceptionFilter() { _logger = LogManager.GetLogger(GetType()); } public void OnException(ExceptionContext context) { _logger.Error("Unhandled exception", context.Exception); } }

最后需要将自定义的Filter加入MVC的Filter列表中:

public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new Log4NetExceptionFilter()); } }

为了记录Action的执行时间,我们可以在Action执行前计时,Action执行结束后记录log:

public class StopwatchAttribute : ActionFilterAttribute { private const string StopwatchKey = "StopwatchFilter.Value"; private readonly ILog _logger= LogManager.GetLogger(typeof(StopwatchAttribute)); public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Application[StopwatchKey] = Stopwatch.StartNew(); } public override void OnActionExecuted(ActionExecutedContext filterContext) { var stopwatch = (Stopwatch)filterContext.HttpContext.Application[StopwatchKey]; stopwatch.Stop(); var log=string.Format("controller:{0},action:{1},execution time:{2}ms",filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,filterContext.ActionDescriptor.ActionName,stopwatch.ElapsedMilliseconds) _logger.Info(log); } }

ActionFilterAttribute是一个抽象类,它不但继承了IActionFilter, IResultFilter等Filter,还继承了FilterAttribute类型,这意味着我们可以将这个自定义的类型当作Attribute来标记到某个Action或者Controller上,同时它还是一个Filter,仍然可以加在MVC的Filter中起到全局拦截的作用。

三、HtmlHelper

在Razor页面中,如果需要写一段公用的用来展示html元素的逻辑,你可以选择使用@helper标记,例如:

@helper ShowProduct(List<ProductListViewModel.Product> products, string style) { <ul> @foreach (var product in products) { <li><a href="@product.Href" target="_blank">@product.Name</a></li> } </ul> }

这一段代码有点像一个方法定义,只需要传入一个list类型和字符串就会按照定义的逻辑输出html:

<h2>Product list using helper</h2> <div> <div>@ShowProduct(Model.SportProducts, "list-group-item-info")</div> <div>@ShowProduct(Model.BookProducts, "list-group-item-warning")</div> </div> <div> <div>@ShowProduct(Model.FoodProducts, "list-group-item-danger")</div> </div>

这样抽取的逻辑只对当前页面有效,如果我们想在不同的页面公用这一逻辑如何做呢?

在Razor中输入@Html即可得到HtmlHelper实例,例如我们可以这样用:@Html.TextBox("name")。由此可见我们可以将公用的逻辑扩展在HtmlHelper上:

public static class HtmlHelperExtensions { public static ListGroup ListGroup(this HtmlHelper htmlHelper) { return new ListGroup(); } } public class ListGroup { public MvcHtmlString Info<T>(List<T> data, Func<T, string> getName) { return Show(data,getName, "list-group-item-info"); } public MvcHtmlString Warning<T>(List<T> data, Func<T, string> getName) { return Show(data,getName, "list-group-item-info"); } public MvcHtmlString Danger<T>(List<T> data, Func<T, string> getName) { return Show(data,getName, "list-group-item-info"); } public MvcHtmlString Show<T>(List<T> data, Func<T, string> getName, string style) { var ulBuilder = new TagBuilder("ul"); ulBuilder.AddCssClass("list-group"); foreach (T item in data) { var liBuilder = new TagBuilder("li"); liBuilder.AddCssClass("list-group-item"); liBuilder.AddCssClass(style); liBuilder.SetInnerText(getName(item)); ulBuilder.InnerHtml += liBuilder.ToString(); } return new MvcHtmlString(ulBuilder.ToString()); } }

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 如何在 ASP.NET Core 中发送邮件 - Savorboard

    如何在 ASP.NET Core 中发送邮件 - Savorboard

    2017-05-02 08:02

  • 十二个 ASP.NET Core 例子 - Savorboard

    十二个 ASP.NET Core 例子 - Savorboard

    2017-04-27 16:01

  • ASP.NET MVC5请求管道和生命周期 - 雪飞鸿

    ASP.NET MVC5请求管道和生命周期 - 雪飞鸿

    2017-04-24 08:04

  • ASP.NET Core MVC 源码学习:详解 Action 的激活 - Savorboard

    ASP.NET Core MVC 源码学习:详解 Action 的激活 - Savorboard

    2017-04-14 13:04

网友点评
i