首页 > Web开发 > 详细

Asp.net Mvc 请求是如何到达 MvcHandler的——UrlRoutingModule、MvcRouteHandler分析,并造个轮子

时间:2014-03-27 04:46:52      阅读:711      评论:0      收藏:0      [点我收藏+]

前言

  本文假定读者对 HttpModule 、HttpHandler和IIS的处理流程有一定的了解,如果为了解可以参考以下链接。文中大部分代码通过Reflector反编译  System.Web.dll 得到,.net 版本为4.0 

IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述

IIS 7.0 的 ASP.NET 应用程序生命周期概述

HTTP 处理程序和 HTTP 模块概述

   Asp.net MVC 程序虽然开发的模式不同,但是其本质上还是 Asp.net。其利用了HttpModule 和 HttpHandler 做了扩展,可以参考博客园里的大牛——Artech 相关系列文章。

本文主要关注UrlRoutingModule 、MvcRouteHandler 两个类的源代码,进而分析客户的请求是如何到达MvcHandler 的。

Asp.net MVc 程序启动流程 需要关注的行为

  • 1、Application启动时先通过RouteTable把URL映射到Handler
  • 2、通过UrlRouting Module 这个HttpModule 拦截用户请求。

我们知道,HttpModule 是注册在 Web.config 中的,可是当你打开Asp.net MVc 程序的Web .Config 时 却没有发现该配置节,原因是:"它已经默认的写在全局的中"。应此 你可以在 “$\Windows\Microsoft.NET\Framework\版本号\Config\Web.config“ 中找到 " <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />”

UrlRoutingModule 源码


UrlRoutingModule 位于 System.web.dll 文件中,利用Reflector 可以查看到其源码:

bubuko.com,布布扣UrlRoutingModuel

 

UrlHttpModule 实现了 IHttpModule 接口

  HTTP Module在应用程序发出请求时被调用的并进行特定的事件处理。 HTTP Module作为请求管道的一部分调用,它们能够访问请求过程中请求周期中的各种管线事件。 
Http Module必须经过注册才能从请求管道接收通知。 注册 HTTP 模块的最常用方法是在应用程序的 Web.config 文件中进行注册。 在 IIS 7.0 中,统一的请求管道使您还可以通过其他方式注册模块,其中包括通过 IIS 管理器和 Appcmd.exe 命令行工具。
  当 ASP.NET 创建表示您的应用程序的 HttpApplication 类的实例时,将创建已注册的任何模块的实例。 在创建模块时,将调用它的 Init 方法,并且模块会自行初始化。在模块的 Init 方法中,可以注册各种应用程序事件的处理程序(如 BeginRequest 或 EndRequest)。

可以看到 UrlHttpModule 在 init 方法中注册了PostResolveRequestCache 事件的处理程序。
关于Asp.net的生命周期事件可以参考:
http://msdn.microsoft.com/zh-cn/library/ms178472
http://msdn.microsoft.com/zh-cn/library/bb470252
http://msdn.microsoft.com/zh-cn/library/ms178473


PostResolveRequestCache

    该事件在完成缓存解析并投递时触发。

  在UrlRoutingModule中它主要是进行上下文的初始化,同时根据传递过来的路由信息获取指定IHttpHandler (其实就是我们的MvcHandler类)
最后通过 context.RemapHandler() 代码将HttpHandler 处理程序映射到 管线处理中。 
在 PostResolveRequestCache 之前分别触发的事件有:
引发 BeginRequest 事件。
引发 AuthenticateRequest 事件。
引发 PostAuthenticateRequest 事件。
引发 AuthorizeRequest 事件。
引发 PostAuthorizeRequest 事件。
引发 ResolveRequestCache 事件。

bubuko.com,布布扣

http://i.msdn.microsoft.com/dynimg/IC5405.png


核心逻辑代码:

bubuko.com,布布扣
bubuko.com,布布扣
 1 //获取路由信息
 2 RouteData routeData = this.RouteCollection.GetRouteData(context);
 3 IRouteHandler routeHandler = routeData.RouteHandler;
 4 //构建请求上下文
 5 RequestContext requestContext = new RequestContext(context, routeData);
 6 context.Request.RequestContext = requestContext;
 7 IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
 8 //将MvcHandler 实例 映射到管线中(通常我们是利用web.config 进行配置的,但是MvcHandler 没有默认无参构造函数,所以直接通过向其传递一个实例
 9 //进行映射)
10 context.RemapHandler(httpHandler);
bubuko.com,布布扣
bubuko.com,布布扣

如何获取到MvcRouteHandler?

  MvcRouteHandler 实现了 IRouteHandler接口。 上文的 IRouteHandler routeHandler=routeData.RouteHandler; 在Asp.net MVc 程序中实际上获取的是MvcRouteHandler实例。
RouteData 类中包含了 IRouteHandler实例的引用,它通过 RouteData 的构造函数:

public RouteData(RouteBase route, IRouteHandler routeHandler);

或者 属性

public IRouteHandler RouteHandler { get; set; }

进行注入。

我们再往回搜索,RouteData实例是通过 RouteCollection.GetRouteData(Context) 方法获取的。查看该方法的主要逻辑实现:

bubuko.com,布布扣
bubuko.com,布布扣
 using (this.GetReadLock())
        {
            foreach (RouteBase base2 in this)
            {
                RouteData routeData = base2.GetRouteData(httpContext);
                if (routeData != null)
                {
                    return routeData;
                }
            }
        }
bubuko.com,布布扣
bubuko.com,布布扣

可以看到通过 RouteBase 类的 GetRouteData(HttpContext)获取了 RouteData实例,并且将第一个部位Null的值返回。 我们需要深入查看RouteBase GetRouteData方法。 RouteBase 是抽象类,其方法是在 Route上具体实现的。(这里又引出一个问题,程序是何时将 Route实例绑定到了 RouteBase上)。

Route类 

深入到Route 类中 发现其和 RouteData 一样, IRouteHandler 也是通过 构造参数 或 属性对 IRouteHandler 进行了注入。

bubuko.com,布布扣
bubuko.com,布布扣
public override RouteData GetRouteData(HttpContextBase httpContext)
{
    string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
    RouteValueDictionary values = this._parsedRoute.Match(virtualPath, this.Defaults);
    if (values == null)
    {
        return null;
    }
    RouteData data = new RouteData(this, this.RouteHandler);
    if (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest))
    {
        return null;
    }
    foreach (KeyValuePair<string, object> pair in values)
    {
        data.Values.Add(pair.Key, pair.Value);
    }
    if (this.DataTokens != null)
    {
        foreach (KeyValuePair<string, object> pair2 in this.DataTokens)
        {
            data.DataTokens[pair2.Key] = pair2.Value;
        }
    }
    return data;
}
bubuko.com,布布扣
bubuko.com,布布扣

关于Asp.net Mvc 中的 MapRoute() 方法

  在Asp.net MVc 程序Global 文件的RegisterRoutes 方法里,RouteCollection 类使用的是MapRoute 方法添加的路由,该方法是一个扩展方法。它位于System.Web.Mvc 的RouteCollectionExtensions类中。

bubuko.com,布布扣
bubuko.com,布布扣
 public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
            if (routes == null) {
                throw new ArgumentNullException("routes");
            }
            if (url == null) {
                throw new ArgumentNullException("url");
            }

            Route route = new Route(url, new MvcRouteHandler()) {
                Defaults = new RouteValueDictionary(defaults),
                Constraints = new RouteValueDictionary(constraints),
                DataTokens = new RouteValueDictionary()
            };

            if ((namespaces != null) && (namespaces.Length > 0)) {
                route.DataTokens["Namespaces"] = namespaces;
            }

            routes.Add(name, route);

            return route;
        }
bubuko.com,布布扣
bubuko.com,布布扣

 

查看上面的关键行:
Route route = new Route(url, new MvcRouteHandler()) {
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
};

 

可以清楚看到,当我们在Asp.net MVc 程序里使用MapRoute()添加路由时,会生成一个 Route 类的实例,并且该实例在生成时会被注入 MvcRouteHandler 实例。 最后被添加到 RouteCollection的集合里(Route 和 MvcRouteHandler 都是以多态形式存在于 RouteCollection中的),这样就建立了一个关系映射表,只有请求的上下文通过该上下文的验证,就可以返回对应MvcRouteHandler实例。

  • MvcRouteHandler 实现了 IRouteHandler接口
  • Route 继承了 RouteBase 抽象类。
  • RouteCollection 中维护着一个 RouteBase 集合。

如何根据路由信息获取MvcHandler

  在Asp.net Mvc 程序 启动时,会触发 Appliction_start 方法,该方法调用了 RouteTable,生成一个全局RouteCollection(单件模式),并将其作为参数传递到RegisterRoutes 方法中。

registerRoutes 方法里通过MapRoute 向 RouteCollection添加路由。 添加的路由是包含MvcRouteHandler实例的Route。

bubuko.com,布布扣


当用户的请求到达IIS后,由于Asp.net MVC 注册了一个HttpModule(UrlRoutingModule) ,应此会触发对应的管线事件处理方法。


1、根据上下文获取RouteData方法, 其内部 实现是:从RouteCollection中遍历RouteBase(实际为Route)实例,并调用RouteBase的GetRouteData() 方法,如果上下文与路由匹配
该方法就会构造一个 RouteData实例,并将 this.IRouteHandler的实例 注入(在Application映射路由时,每个Route实例都包含一个MvcRouteHandler实例的引用)。


2、从 RouteData中 获取IRouteHandler 实例,即 MvcRouteHandler


3、构建上下文,创建RequestContext 该类仅包含 HttpContextBase 和 RouteData 。调用MvcHandler的构造函数需要传递该参数(可以知道请求的Controller、action名等信息),MvcHandler 实现了 IHttpHandler,注意它与MvcHttpHandler 是不相同的:

MvcHandler . 此处理程序负责启动用于 MVC 应用程序的 ASP.NET 管道。 它从 MVC 控制器工厂接收 Controller 实例;此控制器处理请求的进一步处理。 注意,即使 MvcHandler 实现 IHttpHandler,也不能将其映射为处理程序(例如,.mvc 文件扩展名),因为该类不支持无参数构造函数。 (它唯一的构造函数需要一个 RequestContext 对象。)

因此 在 UrlRoutenModule 中 是 通过 HttpContext.RemapHttp(HttpHandler) 。 直接将 一个实例 映射到处理程序上 。(不需要通过系统对其实例化)。

MvcHttpHandler . 此处理程序用于在不通过路由模块的情况下帮助直接处理程序映射。 如果您希望一个文件的扩展名(如 .mvc)直接映射到一个 MVC 处理程序,这很有用。 在内部,MvcHttpHandler 执行 ASP.NET 路由通常执行的相同任务(通过 MvcRouteHandler 和 MvcHandler)。 但是,它将这些任务作为处理程序而不是模块来执行。 UrlRoutingModule 为所有请求启用时,通常不使用此处理程序。



4、调用IRouteHandler的 GetHttpHandler 方法 获取 IHttpHandler实例。(即调用了MvcRouteHandler实例的GetHttpHandler 方法,生成了一个 MvcHandler 实例)


5、向当前上下文注册 IHttpHandler 实例,进入 Controller 处理。

 

 经过以上步骤,我们就大致了解到了Asp.net Mvc程序启动后,用户的请求是如何到达HttpHandler的。


RouteTable 类

这个类很简单只包含一个静态的RouteCollection 属性,是一个单件类。

bubuko.com,布布扣RouteTable

在Asp.net MVc 中application_start 方法里 调用了RouteTable来获取唯一的RouteCollection实例,

所以在UrlRouteModuel中可以通过RouteTable.Routes获取所配置的路由集合。

RouteCollection类

  是一个集合类,内部维护着一个RouteBase 以路由名作为Key的字典集合, 所以我们可以给路由命名。主要的属性和方法有:

RouteData GetRouteData(HttpContextBase httpContext)

  该方法遍历集合内部的RouteBase实体,并返回第一个非Null的RouteData ,具体的RouteData实例,是由所遍历的RouteBase 通过调用 RouteBase.GetRouteData(HttpContext)方法获取的 。

返回的RouteData 中包含一个 IRouteHandler 对象,该接口的只有一个方法,GetHttpHandler,用于获取IHttpHandler 对象。

VirtualPathData GetVirtualPath(...)

  该方法具有多个重载,当您使用 ASP.NET 路由框架生成 URL 时,GetVirtualPath 方法将返回 VirtualPathData 类的一个实例。 VirtualPathData 类包含与所提供的上下文匹配路由的相关信息。

Route MapPageRoute(...)

  该方法用于向路由集合中添加路由,提供此方法是为了方便编码, 它等效于调用 Add 方法。其内部实现的主要代码为:

Route item = new Route(routeUrl, defaults, constraints, dataTokens, new PageRouteHandler(physicalFile, checkPhysicalUrlAccess));

注册使用 PageRouteHandler 类创建的 Route 对象。

  在Asp.net Mvc 方法中,并没有利用该方法向集合中添加路由而是通过了了 MapRoute()方法 这是一个扩展方法,定义在了 RouteCollectionExtensions 类中。

static Route MapRoute(this RouteCollection routes, ......)

  这是一个扩展方法,并且具有多个重载,目的是方便编码,用于向RouteCollection中 添加路由。其内部主要是 生成了一个 以 MvcRouteHandler 为 路由处理的Route 并将其加入到集合中。

Route route = new Route(url, new MvcRouteHandler()) {
                Defaults = new RouteValueDictionary(defaults),
                Constraints = new RouteValueDictionary(constraints),
                DataTokens = new RouteValueDictionary()
            };

IRouteHandler 接口

  接口的定义很简单,只有一个 GetHttpHandler 方法用于返回 一个 IHttpHandler 对象。在 Route 对象,及 RouteData对象中 都包含该对象的引用。该接口定义了一种协议, 指定了 Route 即路由应该有哪一个处理对象进行处理。 它是 Route 到 Handler的 重要桥梁。

RouteBase 类

   这是一个抽象类,RouteBase 类用于定义应用程序中的路由。 在定义路由时,通常使用 Route 类,Route 类是从 RouteBase 类派生的。 但是,如果要提供与 Route 类所提供的功能不同的功能,则可以创建一个从 RouteBase 派生的类,并实现所需的属性和方法。

主要方法有:GetRouteData 在派生类中重写时,会返回有关请求的路由信息。
GetVirtualPath 在派生类中重写时,会检查路由是否与指定值匹配,如果匹配,则生成一个 URL,然后检索有关该路由的信息。

Route 类

  可以通过 Route 类指定 ASP.NET 应用程序中路由的处理方式。 可以为要映射的每个 URL 模式创建一个 Route 对象,该类可处理与该模式相对应的请求。 当应用程序收到请求时,ASP.NET 路由会循环访问 Routes 集合中的路由,以查找与该 URL 模式匹配的第一个路由。

  可将 Url 属性设置为 URL 模式。 该 URL 模式包含某些分段,这些分段位于 HTTP 请求中应用程序名称之后。 例如,在 URL http://www.contoso.com/products/show/beverages 中,该模式应用于 products/show/beverages。 包含三个分段的模式(如 {controller}/{action}/{id})与 URL http://www.contoso.com/products/show/beverages 匹配。 每个分段由 / 字符分隔。 如果分段位于大括号({ 和 })内,则表明该分段是一个 URL 参数。 ASP.NET 路由会检索请求中的值并将其分配给 URL 参数。 在上面的示例中,URL 参数 action 被赋予值 show。 如果该分段不在大括号内,则该值被视为文本值。将 Defaults 属性设置为 RouteValueDictionary 对象,该对象包含当 URL 中缺少某个参数时所使用的值,或者包含用于设置 URL 中未参数化的其他值的值。 将 Constraints 属性设置为 RouteValueDictionary 对象,该对象包含的值为正则表达式或 IRouteConstraint 对象。 这些值用于确定参数值是否有效。

  

bubuko.com,布布扣
bubuko.com,布布扣
public override RouteData GetRouteData(HttpContextBase httpContext)
{
    string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
    RouteValueDictionary values = this._parsedRoute.Match(virtualPath, this.Defaults);
    if (values == null)
    {
        return null;
    }
    RouteData data = new RouteData(this, this.RouteHandler);
    if (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest))
    {
        return null;
    }
    foreach (KeyValuePair<string, object> pair in values)
    {
        data.Values.Add(pair.Key, pair.Value);
    }
    if (this.DataTokens != null)
    {
        foreach (KeyValuePair<string, object> pair2 in this.DataTokens)
        {
            data.DataTokens[pair2.Key] = pair2.Value;
        }
    }
    return data;
}
bubuko.com,布布扣
bubuko.com,布布扣

该方法重写了父类的方法,返回一个RouteData 作。方法一开始 首先通过 ParsedRoute 类的 Match 方法进行路由匹配,匹配成功后则生成一个RouteData对象实例。

ParsedRoute 类
该类是一个内部类,用于匹配、绑定URL,大家可以参考:

 

bubuko.com,布布扣
bubuko.com,布布扣
 public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
    BoundUrl url = this._parsedRoute.Bind(requestContext.RouteData.Values, values, this.Defaults, this.Constraints);
    if (url == null)
    {
        return null;
    }
    if (!this.ProcessConstraints(requestContext.HttpContext, url.Values, RouteDirection.UrlGeneration))
    {
        return null;
    }
    VirtualPathData data = new VirtualPathData(this, url.Url);
    if (this.DataTokens != null)
    {
        foreach (KeyValuePair<string, object> pair in this.DataTokens)
        {
            data.DataTokens[pair.Key] = pair.Value;
        }
    }
    return data;
}
bubuko.com,布布扣
bubuko.com,布布扣

  该方法返回与路由相关联的URL信息。其内部是通过ParsedRoute 类的Bind 把RouteData 绑定到一个BoundUrl 对象中。 如果有约束在则进行验证,最后返回一个 VirtualPathData 对象。

 

bubuko.com,布布扣
bubuko.com,布布扣
protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
    object obj2;
    IRouteConstraint constraint2 = constraint as IRouteConstraint;
    if (constraint2 != null)
    {
        return constraint2.Match(httpContext, this, parameterName, values, routeDirection);
    }
    string str = constraint as string;
    if (str == null)
    {
        throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_ValidationMustBeStringOrCustomConstraint"), new object[] { parameterName, this.Url }));
    }
    values.TryGetValue(parameterName, out obj2);
    string input = Convert.ToString(obj2, CultureInfo.InvariantCulture);
    string pattern = "^(" + str + ")$";
    return Regex.IsMatch(input, pattern, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase);
}
bubuko.com,布布扣
bubuko.com,布布扣

  这是一个路由约束的处理方法,可以看到如果传递的 object constraint 是一个 IRouteConstraint 类型 则直接调用 其Match 方法。

如果正则表达式字符串,利用正则表达式进行验证,否则抛出异常。 


 

造一个简陋的轮子

  不要再造轮子是软件设计的一个准则,但是在学习研究时,造一个简单的轮子能更好的帮我们了解其原理。

创建一个HttpHandler 类,让Asp.net程序通过路由,运行我们指定的HttpHandler,同时在Handler中能够获取路由信息。

1、创建一个类库项目,在项目里创建一个WheelHandler类并实现IHttpHandler接口,这个类只有一个构造函数构造函数需要传递一个 RequestContext

bubuko.com,布布扣
bubuko.com,布布扣
 public class WheelHandler : IHttpHandler
    {
        public WheelHandler(RequestContext requestContext)
        {

            this.RequestContext = requestContext;
        }

        #region IHttpHandler Members

        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            context.Response.Write(String.Format("this is a Wheel for {0}Controller and {1}action "
                , this.RequestContext.RouteData.Values["Controller"]
                , this.RequestContext.RouteData.Values["Action"]));
            context.Response.End();
        }

        #endregion

        public RequestContext RequestContext { get; private set; }
    }
bubuko.com,布布扣
bubuko.com,布布扣

 WheelHandler没有默认的无参构造函数,所以不能直接在Web.config 中注册。ProcessRequest对象很简单,就是输出传入的路由信息。

我们需要定义一个IRouteHandler对象,当路由被捕获时,返回一个WheelHandler,然后将其映射到Http处理中。

2.定义WheelRouteHandler

bubuko.com,布布扣
bubuko.com,布布扣
 public class WheelRouteHandler : IRouteHandler
    {


        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new WheelHandler(requestContext);
        }

        IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
        {
            return this.GetHttpHandler(requestContext);
        }
    }
bubuko.com,布布扣
bubuko.com,布布扣

3、映射路由和WheelRouteHandler。

  我们可以自定义一个派生自RouteBase 的类,进行特定的路由处理,但是本例是一个简单的"轮子",因此继续使用Route类,只需要在生成Route时 向其注入 WheelRouteHandler即可。

因此我们需要修改添加路由的方式,这里模仿MVc 利用扩展方法。当然你也可以不用扩展方法,在添加路由是直接使用Add方法,记得注入WheelRouteHandler便行。

bubuko.com,布布扣
bubuko.com,布布扣
public static Route MapWheelRoute(this RouteCollection routes, string name, string url, object defaults)
        {
            return MapWheelRoute(routes, name, url, defaults, null, null);
        }

        public static Route MapWheelRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
        {
            if (routes == null)
            {
                throw new ArgumentNullException("routes");
            }
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }
            // 在这里注册 Route 与 WheelRouteHandler的映射关系
            Route route = new Route(url, new WheelRouteHandler())
            {
                Defaults = new RouteValueDictionary(defaults),
                Constraints = new RouteValueDictionary(constraints),
                DataTokens = new RouteValueDictionary()
            };

            if ((namespaces != null) && (namespaces.Length > 0))
            {
                route.DataTokens["Namespaces"] = namespaces;
            }

            routes.Add(name, route);

            return route;
        }
bubuko.com,布布扣
bubuko.com,布布扣

 

MapWheelRoute 方法里 调用了Route构造函数,并传入一个WheelRouteHandler对象。

4、创建HttpModule 对象

  自定义的HttpModule的责任是,构建上下文,创建HttpHandler对象并将它映射到Http处理程序里去。

bubuko.com,布布扣
bubuko.com,布布扣
 public void Init(HttpApplication context)
        {
            context.PostResolveRequestCache += new EventHandler(context_PostResolveRequestCache);
        }

        void context_PostResolveRequestCache(object sender, EventArgs e)
        {
            HttpContextBase context = new HttpContextWrapper(((HttpApplication)sender).Context);
            this.PostResolveRequestCache(context);

        }

        private void PostResolveRequestCache(HttpContextBase context)
        {
            RouteData routeData = RouteTable.Routes.GetRouteData(context);

            if (routeData == null)
            {
                throw new InvalidOperationException();
            }

            IRouteHandler routeHandler = routeData.RouteHandler;
            if (routeHandler == null)
            {
                throw new InvalidOperationException();
            }

            RequestContext requestContext = new RequestContext(context, routeData);
            IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
            if (httpHandler == null)
            {
                throw new InvalidOperationException("无法创建对应的HttpHandler对象");
            }
            context.RemapHandler(httpHandler);

        }
bubuko.com,布布扣
bubuko.com,布布扣

  这里我们也是模仿Mvc 捕获的是PostResolveRequestCache事件进行处理,处理时首先将 包装HttpContext对象为 HttpContextBase对象。然后通过GetRouteData 获取RouteData对象,它包含有IRouteHandler对象。获取到IRouteHandler对象后,需要构造 一个RequestContext 对象(该对象很简单就是包含上下文和路由信息)因为 创建WheelHandler 需要该对象。

创建好IHttpHandler对象后,利用RemapHandler方法将其映射为处理程序。

5、注册路由 和Module

  新建一个空的Asp.net 项目,移除里面所有的Aspx文件,事实上只要保留Global和 Web.Config文件即可。在Global 里注册路由:

bubuko.com,布布扣路由注册

  完成最后我们还需要组成自定义的HttpModule

在Web.Config 中添加如下配置:

 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="WheelRouting" type="WheelRouting.WheelRoutingModule,WheelRouting"/>
    </modules>

  </system.webServer>

关于 HttpModule的介绍 可以参考:演练:创建和注册自定义 HTTP 模块

下面是运行结果:

bubuko.com,布布扣

Controller默认值为 Home  Action 默认值为 index

bubuko.com,布布扣

 

源码:点击下载

Asp.net Mvc 请求是如何到达 MvcHandler的——UrlRoutingModule、MvcRouteHandler分析,并造个轮子,布布扣,bubuko.com

Asp.net Mvc 请求是如何到达 MvcHandler的——UrlRoutingModule、MvcRouteHandler分析,并造个轮子

原文:http://www.cnblogs.com/wucaifang/p/3627178.html

(0)
(0)
   
举报
评论 一句话评论(0
分享档案
最新文章
教程昨日排行
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!