Asp.net MVC Route初探
时间:2010-09-05 来源:空逸云
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的确定和执行了.