在上一篇"ASP.NET MVC请求处理管道生命周期的19个关键环节(1-6) ",体验了1-6关键环节,本篇继续。
⑦根据IsapiWorkerRequest对象,HttpRuntime创建HttpContext对象
⑧HttpApplicationFactory创建新的或者从HttpApplication池获取现有的、可用的HttpApplication对象
HttpApplication的工作包括:
● 初始化的时候加载全部的HttpModule
● 接收请求
● 在不同阶段引发不同的事件,使得HttpModule通过订阅事件的方式加入到请求的处理过程中
● 在一个特定阶段获取一个IHttpHandler实例,最终将请求交给具体的IHttpHandler来实现
⑨接下来,就是HttpModules发挥作用的时候
所有的HttpModules都实现了IHttpModule接口:
public interface IHttpModule { void Init(HttpApplication app); void Dispose(); }
可见,HttoModules正是由Init方法,根据传入的HttpApplication类型参数,订阅了HttpApplication的所有事件。
我们自定义一个HttpModule:
public class TestModule : IHttpModule { public void Dispose(){} public void Init(HttpApplication app) { app.PostAcquireRequestState += new EventHandler(app_PostAcuiredRequestState); app.PreRequestHandlerExecute += new EventHandler(app_PreRequestHandlerExecute); } void app_PreRequestHandlerExecute(object sender, EventArgs e) { //TODO: } void app_PostAcquiredRequestState(object sender, EventArgs e) { //TODO: } }
⑩当某个请求与一个规则匹配后,ASP.NET会调用匹配的HttpHandlerFactory的GetHandler方法来获取一个HttpHandler实例, 最后由一个HttpHandler实例来处理当前请求,生成响应内容
所有的HttpHandlers都实现了IHttpHandler接口:
public interface IHttpHandler { bool IsReusable{get;} void ProcessRequest(HttpContext context); }
比如我们可以自定义一个HttpHandler来响应一类特定的请求:
public class Login : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; string username = context.Request.Form["name"]; string password = context.Request.Form["password"]; if(password="sth") { System.Web.Security.FormsAuthentication.SetAuthCookie(username, false); context.Response.Write("ok"); } else { context.Response.Write("用户名和密码不正确"); } } }
⑾ASP.NET MVC的入口在UrlRoutingModule,即订阅了HttpApplication的第7个管道事件PostResolveRequestCahce,换句话说,是在HtttpApplication的第7个管道事件处对请求进行了拦截
UrlRouteModlue实现了IHttpModule:
public class UrlRoutingModule : IHttpModule { // Fields private static readonly object _contextKey = new object(); private static readonly object _requestDataKey = new object(); private RouteCollection _routeCollection; // Methods protected virtual void Dispose() { } protected virtual void Init(HttpApplication application) { if (application.Context.Items[_contextKey] == null) { application.Context.Items[_contextKey] = _contextKey; application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); } } private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) { HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context); this.PostResolveRequestCache(context); } [Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")] public virtual void PostMapRequestHandler(HttpContextBase context) { } 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); } } } } void IHttpModule.Dispose() { this.Dispose(); } void IHttpModule.Init(HttpApplication application) { this.Init(application); } // Properties public RouteCollection RouteCollection { get { if (this._routeCollection == null) { this._routeCollection = RouteTable.Routes; } return this._routeCollection; } set { this._routeCollection = value; } } }
UrlRoutingModule是在Web.config或默认的web.config中配置:
<httpModules> ...... <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" /> </httpModules>
⑿而在请求到达UrlRoutingModule之前,我们在全局文件中做了如下配置
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { ...... BundleConfig.RegisterBundles(BundleTable.Bundles); } } public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } }
这意味着:在HttpApplication的第一个管道事件BeginRequest处,通过MapRoute()方法把路由注册到了RouteCollection中。在实际使用中,UrlRoutingModule是通过RouteTable的静态属性RouteCollection获取路由。
未完待续~~