1. 概述

  ASP.NET MVC具有很好的扩展性,每一个核心功能都可以被扩展、重写 和 定制。

  本章内容包括:实现MVC过滤器和controller工厂、使用 action results,view engines,model binders 和route handlers 来控制程序行为。

2. 主要内容

  2.1 实现MVC过滤器和controller工厂

    2.1.1 MVC过滤器应用于controller或action,有四种主要的类型:

    ① Authorization(授权型),继承自 System.Web.Mvc.IAuthorizationFilter,用于验证调用者身份。

    ② Action,继承自 System.Web.Mvc.IActionFilter ,用于给action方法提供额外的信息,检查action传出的信息或者取消action的执行。

    ③ Result,继承自System.Web.Mvc.IResultFilter,允许开发者对action方法返回的结果做额外的处理。

    ④ Exception,继承自 System.Web.Mvc.IExceptionFilter,当有未处理的异常从action方法中抛出时会被执行到,覆盖了action的整个生命周期。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false,
Inherited = true)]

    *把过滤器添加到App_Start/FilterConfig.cs文件中的RegisterGlobalFilters方法,就可以在全局内有效。

filters.Add(new MyCustomAttribute());

    2.1.2 还可以创建自定义的controllers,或者是可以生成它的工厂。原因有二:

      ① 为了支持  Dependency Injection (DI) 和 Inversion of Control (IoC)。

      ② 为了传递 服务引用 或者 数据仓库信息。

      * 创建自定义的 ControllerFactory 类需要实现 System.Web.Mvc.IControllerFactory接口,包含三个方法:

        ① CreateController:处理实际的controller创建工作。

        ② ReleaseController:执行清理工作。

        ③ GetControllerSessionBehavior:处理与session的交互工作。

      创建完毕,可以添加到Global.asax的 Application_Start方法来注册。

ControllerBuilder.Current.SetControllerFactory(
typeof(MyCustomControllerFactory());

  2.2 使用 action results 控制程序行为

    Action results,处理action方法请求的结果的执行。一般用来处理返回信息的格式化。

    最常用的是ViewResultBase,它是 View 和 PartialView 的基类。用于创建、生成、转化可发送到HTTP输出流的HTML信息。

    现有的Action results类型基本可以满足大部分需求,个别个性的类型,比如 PDF或eDocs, EPS格式,需要创建自定义的Action results类型。

    创建自定义的Action results类型需要实现System.Web.Mvc.ActionResult接口,重写 ExecuteResult方法。

public class CustomResult<T> : ActionResult
{
public T Data { private get; set; } public override void ExecuteResult(ControllerContext context)
{
// do work here
string resultFromWork = "work that was done";
context.HttpContext.Response.Write(resultFromWork);
}
}

  2.3 使用view engines控制程序行为

    视图引擎(View engines)是处理Views到HTML的装置。

    ASP.NET MVC 4 中有两种主要的视图引擎: Razor 和 Web Forms (ASPX),两者的主要区别就在转化和解析代码的格式。

    如果想要向已经创建的视图中添加内容,就可以实现自定义的视图引擎。

    这两个主要的视图引擎都继承自抽象基类 System.Web.Mvc.VirtualPathProviderViewEngine。

    可以通过实现System.Web.Mvc.IViewEngine接口来创建自定义的视图引擎。这个接口包含FindView, FindPartialView 和 ReleaseView 三个方法。

    可以通过重写现有的视图引擎来添加扩展功能。

    创建自定义视图引擎的另一个原因是为了支持更加灵活的路径映射功能。

public class CustomViewEngine : VirtualPathProviderViewEngine
{
public MyViewEngine()
{
this.ViewLocationFormats = new string[]
{ "~/Views/{1}/{2}.mytheme ", "~/Views/Shared/{2}.mytheme" };
this.PartialViewLocationFormats = new string[]
{ "~/Views/{1}/{2}.mytheme ", "~/Views/Shared/{2}. mytheme " };
} protected override IView CreatePartialView
(ControllerContext controllerContext, string partialPath)
{
var physicalpath =
controllerContext.HttpContext.Server.MapPath(partialPath);
return new myCustomView (physicalpath);
} protected override IView CreateView
(ControllerContext controllerContext, string viewPath, string masterPath)
{
var physicalpath = controllerContext.HttpContext.Server.MapPath(viewPath);
return new myCustomView(physicalpath);
}
}
ViewEngines.Engines.Add(new CustomViewEngine());

    创建一个视图需要实现System.Web.Mvc.IView 接口,该接口只有一个Render方法,接收一个System.IO.TextWriter类型的参数。

public class MyCustomView : IView
{
private string _viewPhysicalPath; public MyCustomView(string ViewPhysicalPath)
{
viewPhysicalPath = ViewPhysicalPath;
} public void Render(ViewContext viewContext, System.IO.TextWriter writer)
{
string rawcontents = File.ReadAllText(_viewPhysicalPath);
string parsedcontents = Parse(rawcontents, viewContext.ViewData);
writer.Write(parsedcontents);
} public string Parse(string contents, ViewDataDictionary viewdata)
{
return Regex.Replace(contents, "\\{(.+)\\}", m => GetMatch(m,viewdata));
} public virtual string GetMatch(Match m, ViewDataDictionary viewdata)
{
if (m.Success)
{
string key = m.Result("$1");
if (viewdata.ContainsKey(key))
{
return viewdata[key].ToString();
}
}
return string.Empty;
}
}

  2.4 使用model binders控制程序行为

    模型绑定(model binding)的一个最大的好处是潜在的重用性。

public class DropDownDateTimeBinder : DefaultModelBinder
{
private List<string> DateTimeTypes = new List<string>{ "BirthDate",
"StartDate", "EndDate" }; protected override void BindProperty(ControllerContext contContext,
ModelBindingContext bindContext, PropertyDescriptor propDesc)
{
if (DateTimeTypes.Contains(propDesc.Name))
{
if (!string.IsNullOrEmpty(
contContext.HttpContext.Request.Form[propDesc.Name + "Year"])
{
DateTime dt = new DateTime(int.Parse(
contContext.HttpContext.Request.Form[propDesc.Name
+ "Year"]),
int.Parse(contContext.HttpContext.Request.Form[propDesc.Name +
"Month"]),
int.Parse(contContext.HttpContext.Request.Form[propDesc.Name +
"Day"]));
propDesc.SetValue(bindContext.Model, dt);
return;
}
}
base.BindProperty(contContext, bindContext, propDesc);
}
}
ModelBinders.Binders.DefaultBinder = new DropDownDateTimeBinder();

    要创建自定义的模型绑定,需要实现System.Web.Mvc.IModelBinder接口,重写其 BindModel方法,然后注册。

ModelBinders.Binders.Add(typeof(MyNewModelBinder), new MyNewModelBinder ());

  2.5 使用route handlers控制程序行为

    route是ASP.NET MVC的一个很重要的概念,是区别于Web Forms的一个主要的可见方式。MVC是基于action的,web forms 是基于页面的。

    System.Web.Mvc.MvcRouteHandler是默认的route handler,重写MvcRouteHandler时,需要确保重写了GetHttpHandler方法,可以在这个方法中检查数据或者修改数据。

public class MyCustomRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext reqContext)
{
string importantValue = reqContext.HttpContext.Request.Headers.Get(
"User-Agent");
if (!string.IsNullOrWhiteSpace(importantValue))
{
reqContext.RouteData.Values["action"] = importantValue +
reqContext.RouteData.Values["action"];
}
return base.GetHttpHandler(reqContext);
}
}
routes.MapRoute(
"Home",
"{controller}/{action}",
new { controller = "Home", action = "Index"
).RouteHandler = new MyCustomRouteHandler ();

    如果你有更深入的定制需求,可以通过实现 System.Web.Routing.IRouteHandler 接口来实现。一般用于自定义HttpHandler的情况下。

Route watermarkRoute = new Route("images/{name}",
new WaterMarkRouteHandler("CodeClimber - 2011"));
routes.Add("image", watermarkRoute);

3. 总结

  ① ASP.NET MVC 4 为开发者提供了大量的扩展功能,几乎可以在请求的每一个阶段插入自定义的逻辑。

  ② 扩展功能中最强大的,可能也是最常用的,就是action filter。你可以重写现有的action filter,或者通过实现 IActionFilter 接口来开发自定义的filter。

    action filter 使得开发者可以在action执行前后插入定制化逻辑。

  ③ 与action filter类似的还有 result filter,可以在result逻辑被执行前后插入自定义逻辑。

  ④ 当需要传递特定信息,比如 依赖信息 或者 运行时引用时,还可以创建自定义的controller工厂。

  ⑤ 通过重载视图引擎可以在生成Html时插入自定义逻辑。还可以创建自定义的视图引擎。

  ⑥ 模型绑定是在应用程序中的视图/表单和模型间建立单向或双向交互的方式。有时候没有直接的交互方式,这时候就需要自定义模型绑定。

  ⑦ 默认的route handler 在定义映射方面给了开发者很多灵活性。默认的handler不能满足的情况,还可以实现自定义的handler。

第十七章 提升用户体验 之 使用MVC扩展功能控制程序行为的更多相关文章

  1. 第十六章 提升用户体验 之 设计实现routes

    1. 概述 ASP.NET MVC route 用来把URL映射到方法中的action,是用户和程序之间的桥梁. 本章内容包括:定义route处理URL Pattern.应用route限制.忽略URL ...

  2. 第十五章 提升用户体验 之 设计实现MVC controllers 和 actions

    1. 概述 controllers 和 actions 是 ASP.NET MVC4中非常重要的组成部分. controller管理用户和程序间的交互,使用action作为完成任务的方式. 如果是包含 ...

  3. (转)iOS Wow体验 - 第二章 - iOS用户体验解析(2)

    本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第二章译文精选的第二部分,其余章节将陆续放出.上一 ...

  4. Atitit.hybrid混合型应用 浏览器插件,控件的实现方式 浏览器运行本地程序的解决方案大的总结---提升用户体验and开发效率..

    Atitit.hybrid混合型应用 浏览器插件,控件的实现方式 浏览器运行本地程序的解决方案大的总结---提升用户体验and开发效率.. 1. hybrid App 1 1.1. Hybrid Ap ...

  5. paip.提升用户体验--radio图片选择器 easyui 实现..

    #paip.提升用户体验--radio图片选择器 easyui 实现.. =================================== ##原因... ------------------- ...

  6. paip.提升用户体验--提升java的热部署热更新能力

    paip.提升用户体验--提升java的热部署热更新能力 想让java做到php那么好的热部署能力  "fix online"/在线修复吗??直接在服务器上修改源码生效,无需重启应 ...

  7. paip.提升用户体验----gcc c++ JIT-debugging 技术

    paip.提升用户体验----gcc  c++ JIT-debugging 技术 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http ...

  8. paip.提升用户体验-----c++ gcc 命令在notepad++扩展中的配置..

    paip.提升用户体验-----c++ gcc 命令在notepad++扩展中的配置.. 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址: ...

  9. paip.提升用户体验---c++ qt 取消gcc编译的警告信息.txt

    paip.提升用户体验---c++ qt 取消gcc编译的警告信息.txt 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http:// ...

随机推荐

  1. noip2011普及组:统计单词

    题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位 置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在 ...

  2. libvirtError: 无效参数:could not find capabilities for domaintype=kvm

    libvirtError: 无效参数:could not find capabilities for domaintype=kvm 编辑/etc/nova/nova.conf 在[libvirt] 添 ...

  3. FlexPaper+SwfTools实现的在线文档功能

    最近一个项目需要实现一个在线浏览文档的功能.准备使用FlexPaper配合Pdf2Swf实现. 主要需求在于: ➔ 文档页数很多,少则几百页,多则上千页.    ➔ 相应的文档大小也在50MB以上. ...

  4. ajax方法data参数用法的总结

    源文件分析: data的传递格式有两种:一是url字符串格式:一种是Json格式,格式分别如上 区别是:当传递的参数中包含 特殊字符如:&时,服务器解析这个参数时就会出错,而必须用encode ...

  5. CodeForces 484A Bits(水题)

    A. Bits time limit per test 1 second memory limit per test 256 megabytes input standard input output ...

  6. MD5 不可逆加密,Des对称可逆加密 ,RSA非对称可逆加密 ,数字证书 SSL

    :MD5 不可逆加密2:Des对称可逆加密3:RSA非对称可逆加密4:数字证书 SSL Anker_张(博客园)http://www.cnblogs.com/AnkerZhang/ 1:MD5 不可逆 ...

  7. 萌新笔记之Nim取石子游戏

    以下笔记摘自计算机丛书组合数学,机械工业出版社. Nim取石子游戏 Nim(来自德语Nimm!,意为拿取)取石子游戏. 前言: 哇咔咔,让我们来追寻娱乐数学的组合数学起源! 游戏内容: 有两个玩家面对 ...

  8. Unite 2017 | 基于Animation Instancing的大规模人群模拟

    在Unite 2017的国内技术专场,Unity技术团队为参会者们带来了Unity引擎功能相关的技术分享.今天这篇文章,将由Unity技术支持工程师金晓宇为大家分享基于Animation Instan ...

  9. 关于unity中BindChannels的理解

    http://blog.csdn.net/wpapa/article/details/51794277 官方文档:http://docs.unity3d.com/Manual/SL-BindChann ...

  10. hdu1754(线段树单点替换&区间最值模板)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1754 题意:中文题诶- 思路:线段树单点替换&区间最大值查询模板 代码: #include & ...