自由、创新、研究、探索……

Linux/Windows Mono/DotNet [ Open Source .NET Development/ 使用开源工具进行DotNet软件开发]
posts - 477, comments - 1903, trackbacks - 121, articles - 55
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

做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 管线会依次处理下面的请求:

  1. 对请求进行验证,将检查浏览器发送的信息,并确定其是否包含潜在恶意标记。

  2. 如果已在 Web.config 文件的 UrlMappingsSection 节中配置了任何 URL,则执行 URL 映射。

  3. 引发 BeginRequest 事件。

  4. 引发 AuthenticateRequest 事件。

  5. 引发 PostAuthenticateRequest 事件。

  6. 引发 AuthorizeRequest 事件。

  7. 引发 PostAuthorizeRequest 事件。

  8. 引发 ResolveRequestCache 事件。

  9. 引发 PostResolveRequestCache 事件。

  10. 根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理。如果该请求针对从 Page 类派生的对象(页),并且需要对该页进行编译,则 ASP.NET 会在创建该页的实例之前对其进行编译。

  11. 引发 PostMapRequestHandler 事件。

  12. 引发 AcquireRequestState 事件。

  13. 引发 PostAcquireRequestState 事件。

  14. 引发 PreRequestHandlerExecute 事件。

  15. 为该请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步版 BeginProcessRequest)。例如,如果该请求针对某页,则当前的页实例将处理该请求。

  16. 引发 PostRequestHandlerExecute 事件。

  17. 引发 ReleaseRequestState 事件。

  18. 引发 PostReleaseRequestState 事件。

  19. 如果定义了 Filter 属性,则执行响应筛选。

  20. 引发 UpdateRequestCache 事件。

  21. 引发 PostUpdateRequestCache 事件。

  22. 引发 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"