|
|
Posted on 2008-03-22 13:14 自由、创新、研究、探索…… 阅读(3140) 评论(120) 编辑 收藏 所属分类: MVC Framework
做ASP.NET WebForm开发都知道,ASP.NET有复杂的生命周期,学习ASP.NET MVC就要深入理解它的生命周期。今天从CodePlex上下载了ASP.NET Preview 2 的源代码,还有两个程序集Routing与Abstractions并未发布,不过这两个程序集的类并不多,可以用NET反编译工具 Reflector解开来看看,可惜这两个程序集用的是VS2008使用.net 3.5开发的,用了c# 3.0的很多特性,Reflector反编译不完全。
ASP.NET MVC通过HttpModule(UrlRoutingModule)开始他的执行流程
<httpModules>
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing" />
</httpModules>
代码如下:
namespace System.Web.Routing
  {
using System;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Security.Permissions;
using System.Web;
using System.Web.Resources;

[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
public class UrlRoutingModule : IHttpModule
 {
private static readonly object _requestDataKey = new object();
private System.Web.Routing.RouteCollection _routeCollection;

protected virtual void Dispose()
 {
}

protected virtual void Init(HttpApplication application)
 {
application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler);
}

private void OnApplicationPostMapRequestHandler(object sender, EventArgs e)
 {
HttpContextBase context = new HttpContextWrapper2(((HttpApplication) sender).Context);
this.PostMapRequestHandler(context);
}

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

public virtual void PostMapRequestHandler(HttpContextBase context)
 {
RequestData data = (RequestData) context.Items[_requestDataKey];
if (data != null)
 {
context.RewritePath(data.OriginalPath);
context.Handler = data.HttpHandler;
}
}

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, RoutingResources.UrlRoutingModule_NoRouteHandler, new object[0]));
}
RequestContext requestContext = new RequestContext(context, routeData);
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
if (httpHandler == null)
 {
 throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object[] { routeHandler.GetType() }));
}
RequestData data2 = new RequestData();
data2.OriginalPath = context.Request.Path;
data2.HttpHandler = httpHandler;
context.Items[_requestDataKey] = data2;
context.RewritePath("~/UrlRouting.axd");
}
}

void IHttpModule.Dispose()
 {
this.Dispose();
}

void IHttpModule.Init(HttpApplication application)
 {
this.Init(application);
}

public System.Web.Routing.RouteCollection RouteCollection
 {
get
 {
if (this._routeCollection == null)
 {
this._routeCollection = RouteTable.Routes;
}
return this._routeCollection;
}
set
 {
this._routeCollection = value;
}
}


}

里面还定义了一个RequestData,主要就是当前处理的HttpHandler和URL原始路径。来看看ASP.NET 的HttpApplication 管线会依次处理下面的请求:
-
对请求进行验证,将检查浏览器发送的信息,并确定其是否包含潜在恶意标记。
-
如果已在 Web.config 文件的 UrlMappingsSection 节中配置了任何 URL,则执行 URL 映射。
-
引发 BeginRequest 事件。
-
引发 AuthenticateRequest 事件。
-
引发 PostAuthenticateRequest 事件。
-
引发 AuthorizeRequest 事件。
-
引发 PostAuthorizeRequest 事件。
-
引发 ResolveRequestCache 事件。
-
引发 PostResolveRequestCache 事件。
-
根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理。如果该请求针对从 Page 类派生的对象(页),并且需要对该页进行编译,则 ASP.NET 会在创建该页的实例之前对其进行编译。
-
引发 PostMapRequestHandler 事件。
-
引发 AcquireRequestState 事件。
-
引发 PostAcquireRequestState 事件。
-
引发 PreRequestHandlerExecute 事件。
-
为该请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步版 BeginProcessRequest)。例如,如果该请求针对某页,则当前的页实例将处理该请求。
-
引发 PostRequestHandlerExecute 事件。
-
引发 ReleaseRequestState 事件。
-
引发 PostReleaseRequestState 事件。
-
如果定义了 Filter 属性,则执行响应筛选。
-
引发 UpdateRequestCache 事件。
-
引发 PostUpdateRequestCache 事件。
-
引发 EndRequest 事件。
上述UrlRoutingModule订阅了两个 HttpApplication 事件,PostResolveRequestCache 要比 PostMapRequestHandler 更早执行,先看PostResolveRequestCache 事件,他首先从首先从 RouteCollection 中获取一个 RouteData 对象。看看RouteCollection 属性:
public System.Web.Routing.RouteCollection RouteCollection
 {
get
 {
if (this._routeCollection == null)
 {
this._routeCollection = RouteTable.Routes;
}
return this._routeCollection;
}
set
 {
this._routeCollection = value;
}
}

看到了来自RouteTable,这不正是在Global.asax.cs 中添加的 Route 集合:
protected void Application_Start(object sender, EventArgs e)
 {
RegisterRoutes(RouteTable.Routes);
CreateDefaultUserIfNotExists();
}

public static void RegisterRoutes(RouteCollection routes)
 {
int iisVersion = Convert.ToInt32(ConfigurationManager.AppSettings["IISVersion"], System.Globalization.CultureInfo.InvariantCulture);

if (iisVersion >= 7)
 {
RegisterRoutesForNewIIS(routes);
}
else
 {
RegisterRoutesForOldIIS(routes);
}
}

private static void RegisterRoutesForNewIIS(ICollection<RouteBase> routes)
 {
 routes.Add(new Route("User/Login", new RouteValueDictionary(new { controller = "User", action = "Login" }), new MvcRouteHandler()));
 routes.Add(new Route("User/Logout", new RouteValueDictionary(new { controller = "User", action = "Logout" }), new MvcRouteHandler()));
 routes.Add(new Route("User/Signup", new RouteValueDictionary(new { controller = "User", action = "Signup" }), new MvcRouteHandler()));
 routes.Add(new Route("User/SendPassword", new RouteValueDictionary(new { controller = "User", action = "SendPassword" }), new MvcRouteHandler()));

 routes.Add(new Route("Story/Detail/{id}", new RouteValueDictionary(new { controller = "Story", action = "Detail" }), new MvcRouteHandler()));
 routes.Add(new Route("Story/Upcoming/{page}", new RouteValueDictionary(new { controller = "Story", action = "Upcoming" }), new MvcRouteHandler()));
 routes.Add(new Route("Story/Search/{q}/{page}", new RouteValueDictionary(new { controller = "Story", action = "Search" }), new MvcRouteHandler()));

var defaults = new RouteValueDictionary (
new
 {
controller = "Story",
action = "Category",
name = (string)null,
page = (int?)null
}
);

routes.Add(new Route("Story/Category/{page}", defaults, new MvcRouteHandler()));
routes.Add(new Route("Story/{action}/{name}/{page}", defaults, new MvcRouteHandler()));
routes.Add(new Route("{controller}/{action}/{id}", defaults, new MvcRouteHandler()));
routes.Add(new Route("Default.aspx", defaults, new MvcRouteHandler()));
}

private static void RegisterRoutesForOldIIS(ICollection<RouteBase> routes)
 {
 routes.Add(new Route("User.mvc/Login", new RouteValueDictionary(new { controller = "User", action = "Login" }), new MvcRouteHandler()));
 routes.Add(new Route("User.mvc/Logout", new RouteValueDictionary(new { controller = "User", action = "Logout" }), new MvcRouteHandler()));
 routes.Add(new Route("User.mvc/Signup", new RouteValueDictionary(new { controller = "User", action = "Signup" }), new MvcRouteHandler()));
 routes.Add(new Route("User.mvc/SendPassword", new RouteValueDictionary(new { controller = "User", action = "SendPassword" }), new MvcRouteHandler()));

 routes.Add(new Route("Story.mvc/Detail/{id}", new RouteValueDictionary(new { controller = "Story", action = "Detail" }), new MvcRouteHandler()));
 routes.Add(new Route("Story.mvc/Upcoming/{page}", new RouteValueDictionary(new { controller = "Story", action = "Upcoming" }), new MvcRouteHandler()));
 routes.Add(new Route("Story.mvc/Search/{q}/{page}", new RouteValueDictionary(new { controller = "Story", action = "Search" }), new MvcRouteHandler()));

var defaults = new RouteValueDictionary(
new
 {
controller = "Story",
action = "Category",
name = (string)null,
page = (int?)null
}
);

routes.Add(new Route("Story.mvc/Category/{page}", defaults, new MvcRouteHandler()));
routes.Add(new Route("Story.mvc/{action}/{name}/{page}", defaults, new MvcRouteHandler()));
routes.Add(new Route("{controller}.mvc/{action}/{id}", defaults, new MvcRouteHandler()));
routes.Add(new Route("Default.aspx" |