六.MVC路由扩展
路由扩展的三个层面
1.在MapRoute层面扩展:
Routes.MapRoute("TestStatic","Test/{action}",new {controller="Second"})
只是添加url规则,HttpHandler根本就没有替换到。
2.在Route层面扩展:
先建立一个自己的route,MyRoute,这里要继承RouteBase:
/// <summary> /// 直接扩展route,拒绝浏览器 /// </summary> public class MyRoute : RouteBase { /// <summary> /// 解析路由信息 /// </summary> /// <param name="httpContext"></param> /// <returns></returns> public override RouteData GetRouteData(HttpContextBase httpContext) { //如果是 Chrome浏览器 62.0.3202.94版本 ,则访问 Pipe/Refuse,此页面上只有一句话“<h2>拒绝chrome浏览器访问</h2>”,而其他浏览器不作限制 if (httpContext.Request.UserAgent.IndexOf("Chrome/62.0.3202.94") >= 0) { RouteData rd = new RouteData(this, new MvcRouteHandler()); rd.Values.Add("controller", "Pipe"); rd.Values.Add("action", "Refuse"); return rd; } return null; } /// <summary> /// 指定处理的虚拟路径 /// </summary> /// <param name="requestContext"></param> /// <param name="values"></param> /// <returns></returns> public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { return null; } }
然后add到RouteCollection中去。
public class RouteConfig { public static void RegisterMyRoutes(RouteCollection routes) { routes.Add(new MyRoute()); } public static void RegisterMyMVCHandler(RouteCollection routes) { routes.Add(new Route("Eleven/{*Info}", new ElevenRouteHandler() )); } public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}");//忽略路由 //routes.IgnoreRoute("test/{*pathInfo}"); //mvc路由规则下的扩展 routes.IgnoreRoute("Handler/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, namespaces: new string[] { "Ruanmou.MVC5.Controllers" } ); } }
注意,这里没有用routes.MapRoute方法,直接用add,为什么可以这样用,还是看MapRoute方法:
自定义的路由也要在global注册
protected void Application_Start() { AreaRegistration.RegisterAllAreas();//注册区域路由 GlobalConfiguration.Configure(WebApiConfig.Register);//注册webapi路由 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);// RouteConfig.RegisterMyMVCHandler(RouteTable.Routes); RouteConfig.RegisterMyRoutes(RouteTable.Routes); RouteConfig.RegisterRoutes(RouteTable.Routes);//注册路由 BundleConfig.RegisterBundles(BundleTable.Bundles); ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory());//替换默认的控制器工厂 }
好了,运行一下吧
从图上可以看到,因为在route上扩展了新的路由规则,遇到chrome浏览器就跳到refuse页面,达到了拒绝chrome浏览器的效果,但对于其他浏览器还正常显示。
针对移动端、PC端用哪个控制器,中文、英文环境用哪个控制器,用户登录了跳到哪里去,没登录跳到哪里去,就可以在route层面上扩展,可以随意定义规则,因为能拿到context,有了上下文就有了全世界。
3.扩展Handler,不一定是MvcHandler
/// <summary> /// 扩展IRouteHandler, /// 扩展IHttpHandler /// </summary> public class ElevenRouteHandler : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { return new ElevenHttpHandler(requestContext); } } /// <summary> /// 还是我们熟悉的handler /// </summary> public class ElevenHttpHandler : IHttpHandler { public ElevenHttpHandler(RequestContext requestContext) { Console.WriteLine("构造ElevenHandler"); } public void ProcessRequest(HttpContext context) { string url = context.Request.Url.AbsoluteUri; context.Response.Write(string.Format("这里是Eleven定制:{0}", this.GetType().Name)); context.Response.Write((string.Format("当前地址为:{0}", url))); context.Response.End(); } public virtual bool IsReusable { get { return false; } } }
RouteConfig.cs:
/// <summary> /// 路由配置 /// </summary> public class RouteConfig { public static void RegisterMyRoutes(RouteCollection routes) { routes.Add(new MyRoute()); } public static void RegisterMyMVCHandler(RouteCollection routes) { routes.Add(new Route("Eleven/{*Info}", new ElevenRouteHandler())); } public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}");//忽略路由 //routes.IgnoreRoute("test/{*pathInfo}"); //mvc路由规则下的扩展 routes.IgnoreRoute("Handler/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, namespaces: new string[] { "Ruanmou.MVC5.Controllers" } ); } }
然后在global中注册:
protected void Application_Start() { AreaRegistration.RegisterAllAreas();//注册区域路由 GlobalConfiguration.Configure(WebApiConfig.Register);//注册webapi路由 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);// RouteConfig.RegisterMyMVCHandler(RouteTable.Routes); RouteConfig.RegisterMyRoutes(RouteTable.Routes); RouteConfig.RegisterRoutes(RouteTable.Routes);//注册路由 BundleConfig.RegisterBundles(BundleTable.Bundles); ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory());//替换默认的控制器工厂 }
运行一下,
为什么可以做到呢?
所以上面的流程就是,先建立一个RegisterMyMVCHandler的路由规则,指定它的RouteHandler为ElevenRouteHandler,然后通过ElevenRouteHandler又找到了ElevenHttpHandler,而ElevenHttpHandler里面的功能就是打印了两句话。
到了这个层面后,在例子中我们只是打印了两句话,但是可以做的扩展就多了,可以在ProcessRequest方法中版权申明,或者做一些留后门的事情,获取dll文件,获取webconfig信息,甚至得到数据库数据,想干嘛就干嘛。(好恐怖)