ASP.NET MVC(以下简称MVC)中的窗体路由在目前的版本中(RC1)实际上使用的是System.Web.Routing(.NET SP1)。
关于System.Web.Routing的单独详解可以参看:http://msdn.microsoft.com/zh-cn/magazine/2009.01.extremeaspnet.aspx 的“使用 ASP.NET Web 窗体路由”。这里主要是配合ASP.NET MVC再来分析分析。

MVC路由和以前我们在ASP.NET中进行URL重写(http://msdn.microsoft.com/zh-cn/library/ms972974.aspx)类似的是都是通过HTTP模块来实现的。至于两者的区别可以参看:使用 ASP.NET Web 窗体路由(http://msdn.microsoft.com/zh-cn/magazine/2009.01.extremeaspnet.aspx)。

核心代码:System.Web.Routing命名空间的UrlRoutingModule以及相关的类。

        protected virtual void Init(HttpApplication application)
        {
            //BeginReques、AuthenticateRequest、AuthorizeRequestCache、ResolveRequestCache事件发生之后
            //PostResolveRequestCache事件正好是在未给HttpContent设置Http处理程序的前一个事件
            application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
            //PostMapRequestHandler事件发生时,会为HttpContent设置Http处理程序,所以在该事件中设置自定义Http处理程序最合适不过了
            application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler);
        }

        private void OnApplicationPostMapRequestHandler(object sender, EventArgs e)
        {
            //将当前HttpContent封装成HttpContextWrapper对象并赋给HttpContextWrapper的父类HttpContextBase
            HttpContextBase context = new System.Web.HttpContextWrapper(((HttpApplication) sender).Context);
            this.PostMapRequestHandler(context);
        }

        private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
        {
            HttpContextBase context = new System.Web.HttpContextWrapper(((HttpApplication) sender).Context);
            this.PostResolveRequestCache(context);
        }

        public virtual void PostMapRequestHandler(HttpContextBase context)
        {
            //如果PostResolveRequestCache事件处理方法中设置了路由信息,则根据路由中的配置重写URL,并将HTTP处理程序设置为路由中的配置中的HTTP处理程序。
            //在MVC中,HTTP处理程序设置为MvcHandler对象(注:MvcHandler对象的RequestContext属性已经被赋值为System.Web.Routing.RequestContext对象)
            RequestData data = (RequestData) context.Items[_requestDataKey];
            if (data != null)
            {
                context.RewritePath(data.OriginalPath);
                context.Handler = data.HttpHandler;
            }
        }

        public virtual void PostResolveRequestCache(HttpContextBase context)
        {
            //this.RouteCollection 是 UrlRoutingModule的公共属性,其返回类型就是System.Web.Routing.RouteCollection
            //this.RouteCollection 属性的get方法中,通过RouteTable类的静态属性Routes返回一个单件的RouteCollection(虽然表面上看RouteTable不象使用单件模式,由于路由表是全局的,所以还是单件。)
            //调用RouteCollection对象的GetRouteData(HttpContextBase httpContext)方法。该方法遍历自身,搜索时候与URL匹配的RouteData,如果不匹配返回null
            //如果要了解具体的搜索步骤,可以查看RouteCollection类的GetRouteData方法以及Route类的GetRouteData方法
            RouteData routeData = this.RouteCollection.GetRouteData(context);
            //如果搜索到匹配的路由配置
            if (routeData != null)
            {
                //首先检查路由配置中是否设置了路由处理程序(注:路由处理程序中包含HTTP处理程序),在MVC中RouteData的RouteHandler属性返回的是MvcRouteHandler对象
                IRouteHandler routeHandler = routeData.RouteHandler;
                if (routeHandler == null)
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoRouteHandler, new object[0]));
                }
                //StopRoutingHandler类阻止路由处理特定请求
                if (!(routeHandler is StopRoutingHandler))
                {
                    //RequestContext类其实就是将一个HttpContextBase对象和一个RouteData封装在一起
                    RequestContext requestContext = new RequestContext(context, routeData);
                    //这里通过路由处理程序的GetHttpHandler方法获取HTTP处理程序,在MVC中IRouteHandler的GetHttpHandler方法返回的是MvcHandler对象,并将requestContext作为参数传给了该对象
                    IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
                    if (httpHandler == null)
                    {
                        throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object[] { routeHandler.GetType() }));
                    }
                    //实例化一个RequestData对象来保存请求路径和HTTP处理程序,并将之存入当前HttpContent的Item集合中
                    context.Items[_requestDataKey] = new RequestData { OriginalPath = context.Request.Path, HttpHandler = httpHandler };
                    //MVC 在 web.config 为 IIS 7.0 加了如下配置:
                    //<add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
                    //转:这是为了使路由引擎能够在 IIS 7.0 中进行路由所采用的一种简单解决方法。实际上 UrlRouting 模块会将传入 URL 重写为 ~/UrlRouting.axd,而它会将 URL 重写回原始的传入 URL。
                    context.RewritePath("~/UrlRouting.axd");
                }
            }
        }
        public RouteCollection RouteCollection
        {
            get
            {
                if (this._routeCollection == null)
                {
                    this._routeCollection = RouteTable.Routes;
                }
                return this._routeCollection;
            }
            set
            {
                this._routeCollection = value;
            }
        }
        private class RequestData
        {
            [CompilerGenerated]
            private IHttpHandler _HttpHandler;
            [CompilerGenerated]
            private string _OriginalPath;

            public IHttpHandler HttpHandler
            {
                [CompilerGenerated]
                get
                {
                    return this._HttpHandler;
                }
                [CompilerGenerated]
                set
                {
                    this._HttpHandler = value;
                }
            }

            public string OriginalPath
            {
                [CompilerGenerated]
                get
                {
                    return this._OriginalPath;
                }
                [CompilerGenerated]
                set
                {
                    this._OriginalPath = value;
                }
            }
        }



posted on 2009-11-26 00:26  shawnliu  阅读(465)  评论(0编辑  收藏  举报