前面学习了这么多,那么我手也有点痒了,那么就来把路由扩展一下,看看到底能做多少事情(到底能做什么?其实我也不知道,毕竟还没在项目中使用过,能带来多大好处,也不是很清楚,虽然知道理论,但是不知道如何把学习的理论价值最大化,其实也是挺可悲的,不说了,干活吧!!!)
既然要扩展路由,那么我们肯定是需要一个路由的,那么如何弄一个路由出来了?前面也说过了,我们需要继承一下路由的基类RouteBase
我们来看看RouteBase的源码:
namespace System.Web.Routing { [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")] public abstract class RouteBase { private bool _routeExistingFiles = true; public bool RouteExistingFiles { get { return this._routeExistingFiles; } set { this._routeExistingFiles = value; } } public abstract RouteData GetRouteData(HttpContextBase httpContext); public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values); } }
我们再来看看框架是如何实现的,Route源码如下:
public override RouteData GetRouteData(HttpContextBase httpContext) { string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo; RouteValueDictionary routeValueDictionary = this._parsedRoute.Match(virtualPath, this.Defaults); if (routeValueDictionary == null) { return null; } RouteData routeData = new RouteData(this, this.RouteHandler); if (!this.ProcessConstraints(httpContext, routeValueDictionary, RouteDirection.IncomingRequest)) { return null; } foreach (KeyValuePair<string, object> current in routeValueDictionary) { routeData.Values.Add(current.Key, current.Value); } if (this.DataTokens != null) { foreach (KeyValuePair<string, object> current2 in this.DataTokens) { routeData.DataTokens[current2.Key] = current2.Value; } } return routeData; } public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { BoundUrl boundUrl = this._parsedRoute.Bind(requestContext.RouteData.Values, values, this.Defaults, this.Constraints); if (boundUrl == null) { return null; } if (!this.ProcessConstraints(requestContext.HttpContext, boundUrl.Values, RouteDirection.UrlGeneration)) { return null; } VirtualPathData virtualPathData = new VirtualPathData(this, boundUrl.Url); if (this.DataTokens != null) { foreach (KeyValuePair<string, object> current in this.DataTokens) { virtualPathData.DataTokens[current.Key] = current.Value; } } return virtualPathData; }
我们仿照框架实现方法,代码如下:
/// <summary> /// 自定义路由 /// </summary> public class MyRoute : RouteBase { /// <summary> /// 返回我们定义的路由信息 /// </summary> /// <param name="httpContext"></param> /// <returns></returns> public override RouteData GetRouteData(HttpContextBase httpContext) { //可以省略此句话(父类默认为true),为true表示应用此路由去处理所有请求(甚至包括与现有文件匹配的请求),为false,那么就不应用此路由 base.RouteExistingFiles = true; // 封装有关路由的信息。(这里我使用MVC自带的对路由请求的处理机制) RouteData routeData = new RouteData(this,new MvcRouteHandler()); //获取存储路由的字典 RouteValueDictionary dictionary = routeData.Values; //添加自定的路由到字典中 dictionary.Add("controller", "Home"); dictionary.Add("action", "Index"); return routeData; } /// <summary> /// 表示有关路由和虚拟路径的信息,该路由和虚拟路径是在使用 ASP.NET 路由框架生成 URL 时产生的。 /// </summary> /// <param name="requestContext"></param> /// <param name="values"></param> /// <returns></returns> public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { return null; } }
注意:
1.这里面有一个HttpContextBase参数,我在上面没有并没有使用,但是并不代表没用,其实用处非常大,例如:检查ip,浏览器类型,参数等等
2.因为我们还是使用MVC自带的处理机制,所以还是会走控制器中的动作,如果我们自定义处理机制,那么就不会走控制器中的动作(可以调试一下),也就不会返回视图
MVC的是使用虚拟路径来访问的,而我们自己写的其实是请求的物理文件
视图代码如下:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <div> <h1>我是Home/Index页面 </h1> </div> </body> </html>
url:http://localhost:8955/
其实我们完全可以自定义对路由的处理机制,代码如下:
RouteData routeData = new RouteData(this,new MyRouteHandle());
/// <summary> /// 处理匹配路由模式的请求的协定 /// </summary> public class MyRouteHandle : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { return new MyHandler(); } } /// <summary> /// 自定义 HTTP 处理程序同步处理 HTTP Web 请求而实现的协定。 /// </summary> public class MyHandler : IHttpHandler { /// <summary> /// 获取一个值,该值指示其他请求是否可以使用 System.Web.IHttpHandler 实例。 /// </summary> public bool IsReusable => true; /// <summary> /// 通过实现 System.Web.IHttpHandler 接口的自定义 HttpHandler 启用 HTTP Web 请求的处理。 /// </summary> public void ProcessRequest(HttpContext context) { context.Response.ContentEncoding = Encoding.UTF8; context.Response.Write("我是Home/Index页面2"); context.Response.Write(context.Request.Headers); } }
显示效果如下:
url:http://localhost:8955/