MVC中的扩展点(五)方法选择器

    前一篇中我们介绍了过滤器,通过方法和结果过滤器我们可以在MVC执行方法及结果的前后注入自己的功能,通过授权过滤器可以执行一些权限检查,阻止无权用户调用方法,通过异常过滤器处理方法执行过程中产生的异常。那么在执行方法之前,MVC又是如何确定使用何种控制器及其方法的呢?

    我们已经知道,MVC使用DefaultControllerFactory控制器工厂来实例化控制器,其大致过程如下:

1、默认Route类的GetRouteData方法将按我们设定的Url规则解析当前请求的Url,并将Url规则中的给个参数存入RouteData.Values集合中。我们知道Mvc添加了一个默认的Route项:

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
 );
 

 

按以上规则,如果我们请求的Url为:

http://localhost/News/GetNewsList

则对应的RouteData.Values[“controller”] = "News”;  RouteData.Values[“action”] = "NewsList”

2、DefaultControllerFactory根据Route.Values[“controller”]确定实际的控制器类型,并实例化,如上例控制器工厂知道应实例化的控制器类型为NewsController。

3、通过控制器工厂返回的Controller对象的Execute方法,控制器通过一个实现了IActionInvoker接口的类(默认为ControllerActionInvoker类)使用RouteData.Values[“action”]值,确定具体运行控制器中的那一个方法。

4、执行控制器中的方法生成ActionResult

5、执行ActionResult.ExecuteActionResult生成最终应答内容。

    在4、5步骤中涉及到我们上一章中介绍的过滤器,而方法选择器是在第3步骤中使用的,ControllerActionInvoker类中使用ActionMethodSelector类来获取与路由信息匹配的方法,具体执行过程如下图所示:

SelectorActivity

    图中红色终点表示异常。ActionMethodSelector首先从控制器中非静态方法中获取方法名称等于RouteData.Values[“action”]或通过ActionName特性指定的名称等于RouteData.Values[“action”]的方法列表,其次依次调用方法列表中的每个方法上的选择器,去掉选择器返回为false的部分,如果最终由一个方法匹配则使用这个方法,如果没有方法匹配,则再检查方法列表中没有选择器的方法,如果存在一个,选中它,如果没有,则直接调用控制器的HandleUnknownAction方法,Controller中此方法默认返回一个404的HTTP错误。

    下面我们来看MVC中实现的默认选择器类型:

SelectorClass

    ActionNameAttribute用于声明方法的别名,通常情况下使用ActionName将控制器中不同的方法映射为相同的控制器方法(相同的Url访问不同的方法)。它从抽象类ActionNameSelectorAttribute继承,你也可以从此类中继承实现自己的ActionName特性(不过似乎用处不大)。

    ActionMethodSelectorAttribute抽象类是一些列选择器的基类,ActionMethodSelector选择方法时,会调用IsValidForRequest方法来检查当前方法是否有效。MVC实现了几个默认的选择器:HttpGet、HttpPost、HttpDelete、HttpPut以及AcceptVerbs用于检查当前请求的方式(匹配GET方法、POST方法等,AcceptVerbs用于匹配多个方法),事实上HttpGet等选择器是对AcceptVerbs的封装。另外一个选择器:NonAction表示当前方法不对外部请求公开(它的IsValidForRequest始终返回false)。如果我们需要实现自己的选择逻辑,则应从ActionMethodSelectorAttribute类继承。

    以下示例实现一个选择器,将根据浏览器类型将相同的Url映射到不同的控制器方法:

1、创建一个空的MVC项目

2、实现BrowseSelectorAttribute

显示行号 复制代码 BrowseSelectorAttribute
  1. public class BrowseSelectorAttribute : ActionMethodSelectorAttribute
    
  2. {
    
  3.     private string _userAgent = String.Empty;
    
  4.  
  5.     public BrowseSelectorAttribute(string userAgent)
    
  6.     {
    
  7.         _userAgent = userAgent;
    
  8.     }
    
  9.  
  10.     public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    
  11.     {
    
  12.         return controllerContext.HttpContext.Request.UserAgent.Contains(_userAgent);
    
  13.     }
    
  14. }
    
  15.  

3、创建HomeController控制器

显示行号 复制代码 HomeController
  1. public class HomeController : Controller
    
  2. {
    
  3.     [ActionName("Index")]
    
  4.     [BrowseSelector("MSIE")]
    
  5.     public ActionResult IEIndex()
    
  6.     {
    
  7.         return Content("通过IE浏览器访问");
    
  8.     }
    
  9.  
  10.     [ActionName("Index")]
    
  11.     [BrowseSelector("Chrome")]
    
  12.     public ActionResult ChromeIndex()
    
  13.     {
    
  14.         return Content("通过Chrome浏览器访问");
    
  15.     }
    
  16.  
  17.     [ActionName("Index")]
    
  18.     public ActionResult OtherIndex()
    
  19.     {
    
  20.         return Content("通过其他浏览器访问");
    
  21.     }
    
  22.  
  23. }
    
  24.  

    最后,选择器的功能似乎与授权过滤器类似:都可以"过滤"掉控制器方法,但是他们本质上是不同的:执行授权过滤器时,MVC已经确定调用哪个控制器方法,而选择器是在MVC选择控制器方法时得一组过滤条件。如果通过选择器过滤后没有匹配方法,默认下会返回404错误,如果通过授权过滤器终止执行某个方法,则返回的是你在通过授权过滤器上下文参数中指定的Result。

源代码下载

转载于:https://www.cnblogs.com/xfrog/archive/2011/01/01/1923782.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值