• 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。

    源代码下载

  • 相关阅读:
    Visual Studio.Net 已检测到指定的Web服务器运行的不是ASP.NET1.1版。您将无法运行ASP.NET Web应用程序或服务。
    ActiveX 部件不能创建对象
    XML Schema帮你建模
    XBRL CHINA - XBRL入门
    Xml文档验证—编程篇
    怎样用XML技术对数据库进行操作
    Vclskin 问答
    Altova XMLSpy Ent 2006 汉化特别版 破解版
    一个通过DataSet操作XML的类
    XML Schema教程
  • 原文地址:https://www.cnblogs.com/xfrog/p/1923782.html
Copyright © 2020-2023  润新知