MVC<2:路由映射原理(写在最后)>

MVC路由机制 (原文请点击http://blog.csdn.net/xiaoyong322/article/details/7401391

 
 

MVC 学习索引(点击即可)

一个请求进入IIS后

传统ASP.NET 路由部分

1、IIS根据文件类型将请求转交给相应的处理程序,如果属于ASP.NET文件,则将请求转发给aspnet_isapi.dll。(注:在II6和IIS7上的处理方式是有区别的)

2、 HTTP处理模块UrlRoutingModule接收到请求后,循环调用其RouteCollection集合中的RouteBase对象,找出匹配的RouteBase。

3、根据匹配的RouteBase对象返回的RoueData对象,获取RouteHandler。

4、RouteHandler返回一个HTTP处理程序(IHttpHandler),最终通过此处理程序处理请求,生成应答内容。

5.、如果RouteHandler为MvcRouteHandler,并且其返回的HTTP处理程序为MvcHandler,则进入到MVC框架,MvcHandler对象负责调用适当的控制器和活动方法,生成应答内容。

 

MVC 路由部分 

关键类说明

1、UrlRoutingModule类

    此类事路由系统的核心类,其主要功能是根据请求上下文找出合适的RouteBase对象。属性RouteCollection是一个RouteBase对象集合,UrlRoutingModule接收到请求后,循环RouteCollection集合中的RouteBase对象,调用其GetRouteData方法,如果该方法返回的RouteData对象不为null,则终止循环,将RouteData对象存入RequestContext。然后根据RouteData的RouteHandler获取合适的IHttpHandler处理程序。

    UrlRoutingModule实际上是一个ASP.NET的HTTP 处理模块,所以它通过配置文件的<httpMoudles>配置节点来添加的。

2、RouteTable类

    用于存储应用程序的路由集合,静态属性Routes返回应用程序的路由集合,它实际等同于UrlRoutingModule的RouteCollection属性。通过RouteTable.Routes.Add方法可以添加自定义的RouteBase对象。

3、RouteBase类

    表示一个ASP.NET路由的基类[System.Web.Routing],所有的路由都应该继承自此类。

   GetRouteData方法检查传入的HttpContextBase信息是否符合路由规则,符合则返回一个RouteData对象,不符合则返回null,此方法由UrlRoutingModule类在循环RouteTable.Routes集合时调用。

    GetVirtualPath方法根据路由数据生成相应的Url。

4、Route类

    是RouteBase的一个实现,主要添加了几个属性:

    Constraints: 对URL的约束条件

    DataTokens:传递到路由处理程序的自定义值

    Defaults:Url不包含指定参数时得默认值

    RouteHandler:一个路由处理程序(IRouteHandler)

5、IRouteHandler接口

    路由处理程序接口,包含一个GetHttpHandler方法,用于返回一个IHttpHandler处理程序对象。

6、MvcRouteHandler类

    Mvc框架实现的一个路由处理程序,其GetHttpHandler方法返回一个MvcHandler对象

  1. #region IRouteHandler Members 
  2.       IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) { 
  3.           return GetHttpHandler(requestContext); 
  4.       } 
  5.       #endregion 
  #region IRouteHandler Members
        IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) {
            return GetHttpHandler(requestContext);
        }
        #endregion

 

7、MvcHandler

    由MvcRouteHandler返回,根据请求信息,调用合适的控制器和方法,生成应答内容。

  1. publicclass MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState { 
  2.       privatestaticreadonlyobject _processRequestTag = newobject(); 
  3.       private ControllerBuilder _controllerBuilder; 
  4.  
  5.       internalstaticreadonlystring MvcVersion = GetMvcVersionString(); 
  6.       publicstaticreadonlystring MvcVersionHeaderName = "X-AspNetMvc-Version"
  7.  
  8.       public MvcHandler(RequestContext requestContext) { 
  9.           if (requestContext == null) { 
  10.               thrownew ArgumentNullException("requestContext"); 
  11.           } 
  12.  
  13.           RequestContext = requestContext; 
  14.       } 
  15.  
  16.       internal ControllerBuilder ControllerBuilder { 
  17.           get
  18.               if (_controllerBuilder == null) { 
  19.                   _controllerBuilder = ControllerBuilder.Current; 
  20.               } 
  21.               return _controllerBuilder; 
  22.           } 
  23.           set
  24.               _controllerBuilder = value; 
  25.           } 
  26.       } 
  27.  
  28.       publicstaticbool DisableMvcResponseHeader { 
  29.           get
  30.           set
  31.       } 
  32.  
  33.       protectedvirtualbool IsReusable { 
  34.           get
  35.               returnfalse
  36.           } 
  37.       } 
  38.  
  39.       public RequestContext RequestContext { 
  40.           get
  41.           privateset
  42.       } 
  43.  
  44.       protectedinternalvirtualvoid AddVersionHeader(HttpContextBase httpContext) { 
  45.           if (!DisableMvcResponseHeader) { 
  46.               httpContext.Response.AppendHeader(MvcVersionHeaderName, MvcVersion); 
  47.           } 
  48.       } 
  49.  
  50.       protectedvirtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state) { 
  51.           HttpContextBase iHttpContext = new HttpContextWrapper(httpContext); 
  52.           return BeginProcessRequest(iHttpContext, callback, state); 
  53.       } 
  54.  
  55.       protectedinternalvirtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) { 
  56.           return SecurityUtil.ProcessInApplicationTrust(() => { 
  57.               IController controller; 
  58.               IControllerFactory factory; 
  59.               ProcessRequestInit(httpContext, out controller, out factory); 
  60.  
  61.               IAsyncController asyncController = controller as IAsyncController; 
  62.               if (asyncController != null) { 
  63.                   // asynchronous controller 
  64.                   BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState) { 
  65.                       try
  66.                           return asyncController.BeginExecute(RequestContext, asyncCallback, asyncState); 
  67.                       } 
  68.                       catch
  69.                           factory.ReleaseController(asyncController); 
  70.                           throw
  71.                       } 
  72.                   }; 
  73.  
  74.                   EndInvokeDelegate endDelegate = delegate(IAsyncResult asyncResult) { 
  75.                       try
  76.                           asyncController.EndExecute(asyncResult); 
  77.                       } 
  78.                       finally
  79.                           factory.ReleaseController(asyncController); 
  80.                       } 
  81.                   }; 
  82.  
  83.                   SynchronizationContext syncContext = SynchronizationContextUtil.GetSynchronizationContext(); 
  84.                   AsyncCallback newCallback = AsyncUtil.WrapCallbackForSynchronizedExecution(callback, syncContext); 
  85.                   return AsyncResultWrapper.Begin(newCallback, state, beginDelegate, endDelegate, _processRequestTag); 
  86.               } 
  87.               else
  88.                   // synchronous controller 
  89.                   Action action = delegate
  90.                       try
  91.                           controller.Execute(RequestContext); 
  92.                       } 
  93.                       finally
  94.                           factory.ReleaseController(controller); 
  95.                       } 
  96.                   }; 
  97.  
  98.                   return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag); 
  99.               } 
  100.           }); 
  101.       } 
  102.  
  103.       protectedinternalvirtualvoid EndProcessRequest(IAsyncResult asyncResult) { 
  104.           SecurityUtil.ProcessInApplicationTrust(() => { 
  105.               AsyncResultWrapper.End(asyncResult, _processRequestTag); 
  106.           }); 
  107.       } 
  108.  
  109.       privatestaticstring GetMvcVersionString() { 
  110.           // DevDiv 216459: 
  111.           // This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in 
  112.           // medium trust. However, Assembly.FullName *is* accessible in medium trust. 
  113.           returnnew AssemblyName(typeof(MvcHandler).Assembly.FullName).Version.ToString(2); 
  114.       } 
  115.  
  116.       protectedvirtualvoid ProcessRequest(HttpContext httpContext) { 
  117.           HttpContextBase iHttpContext = new HttpContextWrapper(httpContext); 
  118.           ProcessRequest(iHttpContext); 
  119.       } 
  120.  
  121.       protectedinternalvirtualvoid ProcessRequest(HttpContextBase httpContext) { 
  122.           SecurityUtil.ProcessInApplicationTrust(() => { 
  123.               IController controller; 
  124.               IControllerFactory factory; 
  125.               ProcessRequestInit(httpContext, out controller, out factory); 
  126.  
  127.               try
  128.                   controller.Execute(RequestContext); 
  129.               } 
  130.               finally
  131.                   factory.ReleaseController(controller); 
  132.               } 
  133.           }); 
  134.       } 
  135.  
  136.       privatevoid ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) { 
  137.           // If request validation has already been enabled, make it lazy. This allows attributes like [HttpPost] (which looks 
  138.           // at Request.Form) to work correctly without triggering full validation. 
  139.           bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(HttpContext.Current); 
  140.           if (isRequestValidationEnabled == true) { 
  141.               ValidationUtility.EnableDynamicValidation(HttpContext.Current); 
  142.           } 
  143.  
  144.           AddVersionHeader(httpContext); 
  145.           RemoveOptionalRoutingParameters(); 
  146.  
  147.           // Get the controller type 
  148.           string controllerName = RequestContext.RouteData.GetRequiredString("controller"); 
  149.  
  150.           // Instantiate the controller and call Execute 
  151.           factory = ControllerBuilder.GetControllerFactory(); 
  152.           controller = factory.CreateController(RequestContext, controllerName); 
  153.           if (controller == null) { 
  154.               thrownew InvalidOperationException( 
  155.                   String.Format( 
  156.                       CultureInfo.CurrentCulture, 
  157.                       MvcResources.ControllerBuilder_FactoryReturnedNull, 
  158.                       factory.GetType(), 
  159.                       controllerName)); 
  160.           } 
  161.       } 
  162.  
  163.       privatevoid RemoveOptionalRoutingParameters() { 
  164.           RouteValueDictionary rvd = RequestContext.RouteData.Values; 
  165.  
  166.           // Get all keys for which the corresponding value is 'Optional'. 
  167.           // ToArray() necessary so that we don't manipulate the dictionary while enumerating. 
  168.           string[] matchingKeys = (from entry in rvd 
  169.                                    where entry.Value == UrlParameter.Optional 
  170.                                    select entry.Key).ToArray(); 
  171.  
  172.           foreach (string key in matchingKeys) { 
  173.               rvd.Remove(key); 
  174.           } 
  175.       } 
  176.       #region IHttpHandler Members 
  177.       bool IHttpHandler.IsReusable { 
  178.           get
  179.               return IsReusable; 
  180.           } 
  181.       } 
  182.  
  183.       void IHttpHandler.ProcessRequest(HttpContext httpContext) { 
  184.           ProcessRequest(httpContext); 
  185.       } 
  186.       #endregion 
  187.       #region IHttpAsyncHandler Members 
  188.       IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { 
  189.           return BeginProcessRequest(context, cb, extraData); 
  190.       } 
  191.  
  192.       void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) { 
  193.           EndProcessRequest(result); 
  194.       } 
  195.       #endregion 
  196.   } 
  public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState {
        private static readonly object _processRequestTag = new object();
        private ControllerBuilder _controllerBuilder;

        internal static readonly string MvcVersion = GetMvcVersionString();
        public static readonly string MvcVersionHeaderName = "X-AspNetMvc-Version";

        public MvcHandler(RequestContext requestContext) {
            if (requestContext == null) {
                throw new ArgumentNullException("requestContext");
            }

            RequestContext = requestContext;
        }

        internal ControllerBuilder ControllerBuilder {
            get {
                if (_controllerBuilder == null) {
                    _controllerBuilder = ControllerBuilder.Current;
                }
                return _controllerBuilder;
            }
            set {
                _controllerBuilder = value;
            }
        }

        public static bool DisableMvcResponseHeader {
            get;
            set;
        }

        protected virtual bool IsReusable {
            get {
                return false;
            }
        }

        public RequestContext RequestContext {
            get;
            private set;
        }

        protected internal virtual void AddVersionHeader(HttpContextBase httpContext) {
            if (!DisableMvcResponseHeader) {
                httpContext.Response.AppendHeader(MvcVersionHeaderName, MvcVersion);
            }
        }

        protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state) {
            HttpContextBase iHttpContext = new HttpContextWrapper(httpContext);
            return BeginProcessRequest(iHttpContext, callback, state);
        }

        protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) {
            return SecurityUtil.ProcessInApplicationTrust(() => {
                IController controller;
                IControllerFactory factory;
                ProcessRequestInit(httpContext, out controller, out factory);

                IAsyncController asyncController = controller as IAsyncController;
                if (asyncController != null) {
                    // asynchronous controller
                    BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState) {
                        try {
                            return asyncController.BeginExecute(RequestContext, asyncCallback, asyncState);
                        }
                        catch {
                            factory.ReleaseController(asyncController);
                            throw;
                        }
                    };

                    EndInvokeDelegate endDelegate = delegate(IAsyncResult asyncResult) {
                        try {
                            asyncController.EndExecute(asyncResult);
                        }
                        finally {
                            factory.ReleaseController(asyncController);
                        }
                    };

                    SynchronizationContext syncContext = SynchronizationContextUtil.GetSynchronizationContext();
                    AsyncCallback newCallback = AsyncUtil.WrapCallbackForSynchronizedExecution(callback, syncContext);
                    return AsyncResultWrapper.Begin(newCallback, state, beginDelegate, endDelegate, _processRequestTag);
                }
                else {
                    // synchronous controller
                    Action action = delegate {
                        try {
                            controller.Execute(RequestContext);
                        }
                        finally {
                            factory.ReleaseController(controller);
                        }
                    };

                    return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag);
                }
            });
        }

        protected internal virtual void EndProcessRequest(IAsyncResult asyncResult) {
            SecurityUtil.ProcessInApplicationTrust(() => {
                AsyncResultWrapper.End(asyncResult, _processRequestTag);
            });
        }

        private static string GetMvcVersionString() {
            // DevDiv 216459:
            // This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in
            // medium trust. However, Assembly.FullName *is* accessible in medium trust.
            return new AssemblyName(typeof(MvcHandler).Assembly.FullName).Version.ToString(2);
        }

        protected virtual void ProcessRequest(HttpContext httpContext) {
            HttpContextBase iHttpContext = new HttpContextWrapper(httpContext);
            ProcessRequest(iHttpContext);
        }

        protected internal virtual void ProcessRequest(HttpContextBase httpContext) {
            SecurityUtil.ProcessInApplicationTrust(() => {
                IController controller;
                IControllerFactory factory;
                ProcessRequestInit(httpContext, out controller, out factory);

                try {
                    controller.Execute(RequestContext);
                }
                finally {
                    factory.ReleaseController(controller);
                }
            });
        }

        private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) {
            // If request validation has already been enabled, make it lazy. This allows attributes like [HttpPost] (which looks
            // at Request.Form) to work correctly without triggering full validation.
            bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(HttpContext.Current);
            if (isRequestValidationEnabled == true) {
                ValidationUtility.EnableDynamicValidation(HttpContext.Current);
            }

            AddVersionHeader(httpContext);
            RemoveOptionalRoutingParameters();

            // Get the controller type
            string controllerName = RequestContext.RouteData.GetRequiredString("controller");

            // Instantiate the controller and call Execute
            factory = ControllerBuilder.GetControllerFactory();
            controller = factory.CreateController(RequestContext, controllerName);
            if (controller == null) {
                throw new InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentCulture,
                        MvcResources.ControllerBuilder_FactoryReturnedNull,
                        factory.GetType(),
                        controllerName));
            }
        }

        private void RemoveOptionalRoutingParameters() {
            RouteValueDictionary rvd = RequestContext.RouteData.Values;

            // Get all keys for which the corresponding value is 'Optional'.
            // ToArray() necessary so that we don't manipulate the dictionary while enumerating.
            string[] matchingKeys = (from entry in rvd
                                     where entry.Value == UrlParameter.Optional
                                     select entry.Key).ToArray();

            foreach (string key in matchingKeys) {
                rvd.Remove(key);
            }
        }

        #region IHttpHandler Members
        bool IHttpHandler.IsReusable {
            get {
                return IsReusable;
            }
        }

        void IHttpHandler.ProcessRequest(HttpContext httpContext) {
            ProcessRequest(httpContext);
        }
        #endregion

        #region IHttpAsyncHandler Members
        IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
            return BeginProcessRequest(context, cb, extraData);
        }

        void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) {
            EndProcessRequest(result);
        }
        #endregion
    }

值得一提的是,在MVC3中已经实现异步处理(IHttpAsyncHandler)

8、StopRoutingHandler类

    表示一个“不处理URL的路由处理类”,  比如MVC在RouteCollection类型上扩展了一个IgnoreRoute方法,用于指示路由系统忽略处理指定的url。其实现方式是生成一个Route对象,指定其RouteHandler属性为一个StopRoutingHandler对象。

9、IRouteConstraint接口

    用于构建Route.Constraints属性,表示一个约束条件。Match方法用于检查url是否符合路由规则,符合返回true,否则false。

posted @ 2013-01-22 10:18  Jackvin  阅读(338)  评论(0编辑  收藏  举报