• MVC中的扩展点(二)路由上的扩展


    一、RouteBase

        前面我们知道,UrlRoutingModule通过遍历RouteTable.Routes中的路由对象来获取匹配的RouteData,从而将请求转发到相应的IHttpHandler处理程序。RouteTable.Routes是一个RouteBase对象集合,可向集合中添加任何RouteBase的子类。所以,我们可以通过创建一个RouteBase的子类,然后将其添加到RouteTable.Routes集合中,以此实现自定义路由规则。

        RouteBase是一个抽象类,包含两个抽象方法:GetRouteData用于检查请求上下文是否符合路由规则,如果符合返回一个RouteData对象,若不符合则返回null,UrlRoutingModule在在遍历Routes集合时,将调用此方法,如果方法返回非空,则终止遍历,并将返回的RouteData保存到请求上下文(RequestContext)中。GetVirtualPath方法用于检查指定的路由信息是否符合本路由规则,如果符合返回一个VirtualPathData对象,通过该对象可以获取响应的Url,如果不符合则返回null,通常我们通过MVC中的Html.RouteLink方法来生成Url时,此方法会遍历RoueTable.Routes中的路由对象,依次调用GetVirtualPath方法,直到方法返回非空。

        下面我们将创建一个MyRoute类,该类将阻止IE浏览器方法网站。

    1、首先,我们创建一个MVC2空应用程序项目,然后创建一个名为Home的控制器,在控制器中创建两个Action:Index表示网站首页,Limit表示一个显示限制信息的页面,如果浏览器为IE则会直接显示此页面类容。

    2、创建Index和Limit活动所对应的视图。

    显示行号 复制代码 Index.aspx
    1.     <div>
    2.     <h1>欢迎-!</h1>
    3.     </div>
    显示行号 复制代码 Limit.aspx
    1.     <div>
    2.     不允许IE浏览器访问
    3.      <%= Html.RouteLink("MyRoute", new {applay="IE" }) %>
    4.      <%= Html.RouteLink("Route", new { controller = "Home", action = "Index" })%>
    5.     </div>

    3、创建一个MyRoute类,让其继承自RouteBase,重写GetRouteData和GetVirtualPath方法:

    显示行号 复制代码 MyRoute.cs
    1. public class MyRoute : RouteBase
      
    2. {
      
    3.     public override RouteData GetRouteData(HttpContextBase httpContext)
      
    4.     {
      
    5.         if (httpContext.Request.UserAgent.IndexOf("MSIE")>=0 )
      
    6.         {
      
    7.             RouteData rd = new RouteData(this, new MvcRouteHandler());
      
    8.             rd.Values.Add("controller", "Home");
      
    9.             rd.Values.Add("action", "Limit");
      
    10.             return rd;
      
    11.         }
      
    12.         return null;
      
    13.     }
      
    14. 
      
    15.     public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
      
    16.     {
      
    17.         if (values.ContainsKey("applay") && values["applay"] == "IE")
      
    18.         {
      
    19.             return new VirtualPathData(this, "IE/Index");
      
    20.         }
      
    21.         return null;
      
    22.     }
      
    23. }
      
    24.  

    4、打开Global.asax.cs文件,找到RegisterRoutes方法,将我们的MyRoute注册到RouteTable.Routes集合中,注意添Route的顺序很重要,UrlRoutingModule在遍历时是按照添加顺序进行的,所以未保证MyRoute规则有效,必须将其放到第一个位置。注意MapRoute方法是MVC框架对RouteCollection的扩展,用于添加一个Route对象到集合中,本质上内部也是调用的Add方法。

    显示行号 复制代码 MvcApplication
    1. public static void RegisterRoutes(RouteCollection routes)
      
    2. {
      
    3.     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
      
    4.     routes.Add("myRoute",new MyRoute());
      
    5.     routes.MapRoute(
      
    6.         "Default", // Route name
      
    7.         "{controller}/{action}/{id}", // URL with parameters
      
    8.         new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
      
    9.     );
      
    10. }
      

        启动调试,如果是IE浏览器,则会显示“不允许IE浏览器访问”,另外,请注意看MyRoute与Route连接的地址,显然MyRoute的地址是通过MyRoute类产生的,而Route地址是通过Route默认路由对象产生的。

    二、IRouteHandler

        UrlRoutingModule在获取到合适的RouteData后,将通过其RouteHandler属性来获取实际的IHttpHandler对象,通过IHttpHandler来处理请求。在MVC中,已经实现了一个RouteHandler,即MvcRouteHandler,在上例中我们的GetRouteData方法使用的即是MvcRouteHandler。

        IRouteHandler接口只有一个方法:GetHttpHandler它返回一个IHttpHandler对象。也就是说最终页面的生成是在IHttpHandler对象中实现的。对应于MVC,MvcRouteHandler的GetHttpHandler方法返回一个MvcHandler对象,MvcHandler对象负责调用合适的Controller与Action方法。

        下面我们沿用上例,实现一个IERouteHandler,通过这个Handler来处理来自IE浏览器的请求。

    1、添加一个IERouteHandler类,继承自IRouteHandler,实现其GetHttpHandler方法,返回一个IEHandler对象。

    显示行号 复制代码 IERouteHandler
    1. public class IERouteHandler : IRouteHandler
      
    2. {
      
    3.     #region IRouteHandler Members
      
    4. 
      
    5.     public IHttpHandler GetHttpHandler(RequestContext requestContext)
      
    6.     {
      
    7.         return new IEHandler();
      
    8.     }
      
    9. 
      
    10.     #endregion
      
    11. 
      
    12. 
      
    13.     private class IEHandler : IHttpHandler
      
    14.     {
      
    15.         #region IHttpHandler Members
      
    16. 
      
    17.         public bool IsReusable
      
    18.         {
      
    19.             get { return true; }
      
    20.         }
      
    21. 
      
    22.         public void ProcessRequest(HttpContext context)
      
    23.         {
      
    24.             context.Response.Write("不允许IE浏览器访问");
      
    25.         }
      
    26. 
      
    27.         #endregion
      
    28.     }
      
    29. }
      

    2、修改MyRoute的GetRouteData方法,将之前的MvcRouteHandler修改为IERouteHandler

    显示行号 复制代码 MyRoute
    1. public override RouteData GetRouteData(HttpContextBase httpContext)
      
    2. {
      
    3.     if (httpContext.Request.UserAgent.IndexOf("MSIE")>=0 )
      
    4.     {
      
    5.         //RouteData rd = new RouteData(this, new MvcRouteHandler());
      
    6.         //rd.Values.Add("controller", "Home");
      
    7.         //rd.Values.Add("action", "Limit");
      
    8.         RouteData rd = new RouteData(this, new IERouteHandler());
      
    9.         return rd;
      
    10.     }
      
    11.     return null;
      
    12. }
      

    三、IRouteConstraint

        IRouteConstraint接口由Route类的Constraints属性使用,用于判断当前的Url是否符合路由的约束条件。Route已经实现了一个HttpMethodConstraint用于限制请求方法,例如:

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

        表明此项路由规则必须是POST请求才有效,即就算Url为Home/Index形式,符合Url规则,但是如果请求是通过的GET方法,那此项规则也不满足,明显,Route的GetRouteData方法中会检查所有的约束条件,如果某项约束条件不满足仍然会返回null。

        IRouteConstraint接口有一个Match方法,如果请求上下文符合约束返回true否则返回false。

        沿用上例,现在我们通过IRouteConstraint来限制IE浏览器的访问:

    1、新建类IERouteConstraint,实现其Match方法:

    显示行号 复制代码 IERouteConstraint
    1. public class IERouteConstraint : IRouteConstraint
      
    2. {
      
    3.     #region IRouteConstraint Members
      
    4. 
      
    5.     public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
      
    6.     {
      
    7.         return !(httpContext.Request.UserAgent.Contains("MSIE"));
      
    8.     }
      
    9.     #endregion
      
    10. }
      

    2、修改Global.asax.cs的RegisterRoutes方法,屏蔽掉之前加入的MyRoute规则,然后修改默认的MapRoute:

    显示行号 复制代码 MvcApplication
    1. public static void RegisterRoutes(RouteCollection routes)
      
    2. {
      
    3.     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
      
    4.     //  routes.Add("myRoute",new MyRoute());
      
    5.     routes.MapRoute(
      
    6.         "Default", // Route name
      
    7.         "{controller}/{action}/{id}", // URL with parameters
      
    8.         new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
      
    9.         new { ie = new IERouteConstraint() }
      
    10.     );
      
    11. }
      

        启动调试,如果是IE浏览器,将显示一个无法找到资源的404错误。

        源代码下载

  • 相关阅读:
    [NOI2009]管道取珠 DP + 递推
    poj3207 Ikki's Story IV
    NOIP2016Day1T2天天爱跑步(LCA+桶)
    NOIP2016Day2T3愤怒的小鸟(状压dp) O(2^n*n^2)再优化
    NOIP2016Day1T3换教室(floyd+期望dp)
    bzoj1854: [Scoi2010]游戏(匈牙利) / GDKOI Day2 T2(最大流)
    [CodeVs4927]线段树练习5
    基数排序的奇技淫巧
    bzoj2724: [Violet 6]蒲公英(离散化+分块)
    bzoj1483: [HNOI2009]梦幻布丁(链表+启发式合并)
  • 原文地址:https://www.cnblogs.com/xfrog/p/1910428.html
Copyright © 2020-2023  润新知