Asp.net MVC天生就有着漂亮的Url.但是却有别于Asp.net的UrlRewriter.那么其的实现原理是怎样的呢?这就要说到Route了.

Asp.Net MVC生命周期

Asp.net MVC的生命周期由8个步骤组成:

1.RouteTable(路由表)的创建

2.UrlRoutingMoudle请求拦截

3.Routing engine确定route

4.RouteHandler创建相关的IHttpHandler实例

5.IHttpHandler实例确定Controller(控制器)

6.Controller执行

7.视图引擎创建

8.视图呈现

这里主要讲解前4个.

RouteTable(路由表)的创建

打开Global.asax

 1: public class MvcApplication : System.Web.HttpApplication
 2: {
 3: public static void RegisterRoutes(RouteCollection routes)
 4: {
 5: routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 6:  
 7: routes.MapRoute(
 8: "Default", // Route name
 9: "{controller}/{action}/{id}", // URL with parameters
 10: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
 11: new { controller = @"[^\.]*"}
 12: );
 13:  
 14: routes.MapRoute(
 15: "Defalut",
 16: "{controller}/Blog/{date}",
 17: new { action = "Blog" },
 18: new { date = @"^\d{4}\.\d{2}\.\d{2}" }
 19: );
 20: }
 21:  
 22: protected void Application_Start()
 23: {
 24: AreaRegistration.RegisterAllAreas();
 25:  
 26: RegisterRoutes(RouteTable.Routes);
 27:  
 28: //RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
 29: }
 30: }

在此,我们声明了两个Route.

在MVC1中.我们必须

 1: routes.Add(new Route("User/Login", new RouteValueDictionary(new { controller = "User", action = "Login" }), new MvcRouteHandler()));
 2: routes.Add(new Route("User/Logout", new RouteValueDictionary(new { controller = "User", action = "Logout" }), new MvcRouteHandler()));
 3: routes.Add(new Route("User/Signup", new RouteValueDictionary(new { controller = "User", action = "Signup" }), new MvcRouteHandler()));

 

这样添加.但在.Net3.5中.我们却可以直接利用匿名类直接New一个.这是因为.Net3.5中扩展了一个MapRoute方法.该方法利用反射.进行背后的添加

 1: public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
 2: if (routes == null) {
 3: throw new ArgumentNullException("routes");
 4: }
 5: if (url == null) {
 6: throw new ArgumentNullException("url");
 7: }
 8:  
 9: Route route = new Route(url, new MvcRouteHandler()) {
 10: Defaults = new RouteValueDictionary(defaults),
 11: Constraints = new RouteValueDictionary(constraints),
 12: DataTokens = new RouteValueDictionary()
 13: };
 14:  
 15: if ((namespaces != null) && (namespaces.Length > 0)) {
 16: route.DataTokens["Namespaces"] = namespaces;
 17: }
 18:  
 19: routes.Add(name, route);
 20:  
 21: return route;
 22: }

 

UrlRoutingMoudle请求拦截

按照MS惯例,一般会在WebConfig留下些蛛丝马迹,打开WebConfig.不出其然.我们发现HttpMoudle中有

 1: <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

利用Reflector打开UrlRoutingModule类.

 1: protected virtual void Init(HttpApplication application)
 2: {
 3: application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
 4: application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler);
 5: }
 6:  
 7: 

Routing engine确定route

可以看到.在application的events中注册了PostResolveRequestCache 和PostMapRequestHandler 事件.

PostResolveRequestCache

 1: public virtual void PostResolveRequestCache(HttpContextBase context)
 2: {
 3: RouteData routeData = this.RouteCollection.GetRouteData(context);
 4: if (routeData != null)
 5: {
 6: IRouteHandler routeHandler = routeData.RouteHandler;
 7: if (routeHandler == null)
 8: {
 9: throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoRouteHandler, new object[0]));
 10: }
 11: if (!(routeHandler is StopRoutingHandler))
 12: {
 13: RequestContext requestContext = new RequestContext(context, routeData);
 14: IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
 15: if (httpHandler == null)
 16: {
 17: throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object[] { routeHandler.GetType() }));
 18: }
 19: context.Items[_requestDataKey] = new RequestData { OriginalPath = context.Request.Path, HttpHandler = httpHandler };
 20: context.RewritePath("~/UrlRouting.axd");
 21: }
 22: }
 23: }
 24:  
 25: 

这里.首先通过RouteCollection.GetRouteData得到当前的RouteData,

UrlRoutingModule.RouteCollection

 1: public RouteCollection RouteCollection
 2: {
 3: get
 4: {
 5: if (this._routeCollection == null)
 6: {
 7: this._routeCollection = RouteTable.Routes;
 8: }
 9: return this._routeCollection;
 10: }
 11: set
 12: {
 13: this._routeCollection = value;
 14: }
 15: }
 16: 

module中的RouteCollection只是很简单的引用了RouteTable中的静态实例Routes而已.

RouteTable

 1: public class RouteTable
 2: {
 3: // Fields
 4: private static RouteCollection _instance = new RouteCollection();
 5:  
 6: // Properties
 7: public static RouteCollection Routes
 8: {
 9: get
 10: {
 11: return _instance;
 12: }
 13: }
 14: }

RouteCollection.GetRouteData

这是获取RouteDate的核心实现.

 1: public RouteData GetRouteData(HttpContextBase httpContext)
 2: {
 3: if (httpContext == null)
 4: {
 5: throw new ArgumentNullException("httpContext");
 6: }
 7: if (httpContext.Request == null)
 8: {
 9: throw new ArgumentException(RoutingResources.RouteTable_ContextMissingRequest, "httpContext");
 10: }
 11: if (!this.RouteExistingFiles)
 12: {
 13: string appRelativeCurrentExecutionFilePath = httpContext.Request.AppRelativeCurrentExecutionFilePath;
 14: if (((appRelativeCurrentExecutionFilePath != "~/") && (this._vpp != null)) && (this._vpp.FileExists(appRelativeCurrentExecutionFilePath) || this._vpp.DirectoryExists(appRelativeCurrentExecutionFilePath)))
 15: {
 16: return null;
 17: }
 18: }
 19: using (this.GetReadLock())//线程锁
 20: {
 21: foreach (RouteBase base2 in this)//遍历当前集合中的所有RouteBase
 22: {
 23: RouteData routeData = base2.GetRouteData(httpContext); //调用RouteBase的RouteData.此处传入的Class是Route.
 24: if (routeData != null)
 25: {
 26: return routeData;
 27: }
 28: }
 29: }
 30: return null;
 31: }
 32:  

Route

Route继承至RouteBase.Route中提供了MVC的Route信息.

可以看到最后承载Route数据的容器是RouteVallueDictionary.Route中包含了该Dictionary

RouteData

RouteData的实现很简单.就提供了几个基本的字段而已.主要用于描述当前Route数据的信息.如此一来.我们可以得到当前Url所匹配的Route.

 1: public class RouteData
 2: {
 3: // Fields
 4: private RouteValueDictionary _dataTokens;
 5: private IRouteHandler _routeHandler;
 6: private RouteValueDictionary _values;
 7:  
 8: // Methods
 9: public RouteData();
 10: public RouteData(RouteBase route, IRouteHandler routeHandler);
 11: public string GetRequiredString(string valueName);
 12:  
 13: // Properties
 14: public RouteValueDictionary DataTokens { get; }
 15: public RouteBase Route { get; set; }
 16: public IRouteHandler RouteHandler { get; set; }
 17: public RouteValueDictionary Values { get; }
 18: }

RouteHandler创建相关的IHttpHandler实例

RouteHandler

得到RouteData之后.获取RouteData之中的RouteHandler.根据RouteHandler获取相关的IHttpHandler.这样.MVC的Route隐射阶段就已经完成

 1: RequestContext requestContext = new RequestContext(context, routeData);
 2: IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

 

 

 

 

 

 

 

 

 

 

 

后面就是Controller的确定和执行了.

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"