URL Routing组件是如何与ASP.NET MVC框架组合起来的

最近有一段时间都在看ASP.NET MVC框架的源代码。原来的想法是,如果有相应ASP.NET MVC的文档,就直接看文档,学学怎么使用这个框架。可惜都是视频教程,而又感觉看那本电子书有点无趣,索性就直接看源代码了。这样一来反而收获了很多的东西。

在ASP.NET MVC框架里面,用到了URL Routing组件。URL Routing组件干什么用呢?根据你配置的URL 模式来提取数据或者生成相应的URL 。但我有一个疑问:URL Routing组件是如何同ASP.NET MVC框架关联起来的?

由于这个组件没有开放源代码,所以我们查看代码的方式也就只有反编译了。我们可以看到Route类型。这个类表示一条路由,包括URL模式,路由数据,HTTP处理程序等。我们可以看到它的构造器如下:

 


 
public Route(string url, IRouteHandler routeHandler);
public Route(string url, RouteValueDictionary defaults, IRouteHandler routeHandler);
public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler);
public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler);

 

 

Route的初始化时需要一个实现IRouteHandler接口的类的实例的。IRouteHandler的定义如下:
 

 
public interface IRouteHandler{
    IHttpHandler GetHttpHandler(RequestContext requestContext);
}

 

 

IRouteHandler只定义了一个方法——GetHttpHandler,返回一个IHttpHandler。IHttpHandler其实就是ASP.NET管线事件的终点,所有的HTTP请求最后都是由IHttpHandler的实现来处理的。

沿着这个思路,我们继续往下找,看能不能找到一个实现这个接口的类型。一开始看到一个UrlRoutingHandler,以为找到要找的类型了,不过仔细一开类型的定义,是抽象类型,表示Routing的终点,因为这个抽象类实现了IHttpHandler接口。查看它的ProcessRequest方法的代码,如下:

 


 
protected virtual void ProcessRequest(HttpContextBase httpContext)
{
    RouteData routeData = this.RouteCollection.GetRouteData(httpContext);
    if (routeData == null)
    {
        throw new HttpException(0x194, SR.GetString("UrlRoutingHandler_NoRouteMatches"));
    }
    IRouteHandler routeHandler = routeData.RouteHandler;
    if (routeHandler == null)
    {
        throw new InvalidOperationException(SR.GetString("UrlRoutingModule_NoRouteHandler"));
    }
    RequestContext requestContext = new RequestContext(httpContext, routeData);
    IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
    if (httpHandler == null)
    {
        throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() }));
    }
    this.VerifyAndProcessRequest(httpHandler, httpContext);
}

 

 

可以看到, 实际上这个方法首先使用Route的实例返回一个IRouteHandler接口实现类的实例对象,调用IRouteHandler.GetHttpHandler()方法返回一个IHttpHandler实现类的实例对象,最后调用了this.VerifyAndProcessRequest(httpHandler, httpContext)方法进行处理。VerifyAndProcessRequest(httpHandler, httpContext)定义如下:
 
protected abstract void VerifyAndProcessRequest(
  IHttpHandler httpHandler, 
  HttpContextBase httpContext);

 

这是一个抽象方法。URL Routing组件最后一定映射到一个处理程序来相应HTTP请求,显然,必定有一个实现类继承并且实现了这个VerifyAndProcessRequest方法。我们在这个组件里面接着找,还是没有找到相应的实现类型,但是我们发现了一个UrlRoutingModule类。这个类实现了IHttpModule,是一个ASP.NET模块。那么这个模块做了什么?我们可以查看这个模块的Init(HttpApplication application)方法,定义如下:
 

 
protected virtual void Init(HttpApplication application)
{
    if (application.Context.Items[_contextKey] == null)
    {
        application.Context.Items[_contextKey] = _contextKey;
        application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
    }
}
 
它订阅了ASP.NET的PostResolveRequestCache管线事件,并且这个方法重新映射了HTTP 处理程序,其实这个类型在.NET 3.5以及.NET 4.0中还是有所不同的。(this.OnApplicationPostResolveRequestCache方法代码如下:

 
public virtual void PostResolveRequestCache(HttpContextBase context)

 
{

 
    RouteData routeData = this.RouteCollection.GetRouteData(context);

 
    if (routeData != null)

 
    {

 
        IRouteHandler routeHandler = routeData.RouteHandler;

 
        if (routeHandler == null)

 
        {

 
            throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));

 
        }

 
        if (!(routeHandler is StopRoutingHandler))

 
        {

 
            RequestContext requestContext = new RequestContext(context, routeData);

 
            context.Request.RequestContext = requestContext;

 
            IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

 
            if (httpHandler == null)

 
            {

 
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() }));

 
            }

 
            if (httpHandler is UrlAuthFailureHandler)

 
            {

 
                if (!FormsAuthenticationModule.FormsAuthRequired)

 
                {

 
                    throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3"));

 
                }

 
                UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);

 
            }

 
            else

 
            {

 
                context.RemapHandler(httpHandler);

 
            }

 
        }

 
    }

 
}
 

这个方法从Route实例取得RouteData,并且从RouteData获得相应的IHttpHandler处理程序来处理请求,这样,URL Routing最终把HTTP请求映射到一个处理程序处理。但是这里有个问题,就是这个处理程序的实例是什么时候初始化,又是如何初始化的?并且,URL Routing是怎么和ASP.NET MVC框架关联起来的?

 
带着这个问题去看ASP.NET MVC框架的源代码,我们找到两个引人注意的类型:MvcHttpHandler以及MvcRouteHandler。MvcHttpHandler继承了UrlRoutingHandler, IHttpAsyncHandler, IRequiresSessionState,是一个HttpHandler。看来这个类型并不是我们要寻找的答案。于是,我想到是不是利用配置文件来把这两个组件关联起来的?于是我去看了Oxite的配置文件,注意到有这么一段配置:

 
<httpHandlers>
  <remove verb="*" path="*.asmx"/>
  <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
  <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
  <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
  <add verb="*" path="*.mvc" validate="false" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</httpHandlers>
<httpModules>
  <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
  <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</httpModules>
这段配置还是没有解决我们的疑问。因为我们知道ASP.NET MVC框架必定在某一个地方创建了一个MvcHttpHandler的实例并且将这个实例传递给URL Routing组件,URL Routing最终将请求映射到这个处理程序,然后相应请求。联想到我们每一个路由都是有一个Route类型表示的,那么我们如何实例化这个类型?一般都是在Application_Start事件里初始化并且添加到路由表里面的吧?OK,也许问题的答案就在这个地方。我们添加路由的时候,记得都是用MapRoute这个拓展方法吧,这个方法非常方便,但是这个方法被定义在哪里?在找遍了URL Routing组件,我并没有发现有这样的这样的拓展方法。于是我想到可能又是放在了ASP.NET MVC框架里了。于是我在框架里发现了RouteCollectionExtensions这个类型,这个类型为RouteCollection定义了非常多的拓展方法,其中就包括MapRoute方法。在编写实现的时候,框架使用了串联的方式,也就是很多的重载方法,其实都是调用一个实现方法。这个实现方法如下:

 
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;
}
 
在兜了一圈,终于回来了。我们非常清楚的看到,是在这里,把MvcHttpHandler注入,也就将URL Routing和ASP.NET MVC关联起来了。

 

总结

 
这里只是整理我在看ASP.NET MVC框架源代码中,忽然想到的框架是如可和URL Routing组件关联起来这个问题的解题思路,绕了一圈才忽然明白,因此我将我的思路记录了下来。其实一句话,在初始化Route类型的时候就将IHttpHandler实例注入,这样就完成了关联了。

转载于:https://www.cnblogs.com/knightuniverse/archive/2010/07/11/1775065.html

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值