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;
}
}
}
关于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;
}
}
}