服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服务器之家 - 编程语言 - ASP.NET教程 - asp.net mvc路由篇 如何找到 IHttpHandler方法介绍

asp.net mvc路由篇 如何找到 IHttpHandler方法介绍

2019-10-09 15:02asp.net教程网 ASP.NET教程

学习是使用asp.net已经有很长一段时间了,现在就来分析一下mvc的整过过程吧。个人计划写一个mvc系列的博文,仅从源代码的角度来分析mvc。在接触mvc时我们一定会经历路由,那么路由这东东是怎么搞出来的啊

学习是使用asp.net已经有很长一段时间了,现在就来分析一下mvc的整过过程吧。个人计划写一个mvc系列的博文,仅从源代码的角度来分析mvc。在接触mvc时我们一定会经历路由,那么路由这东东是怎么搞出来的啊。在我们的web.config中有这么一句: <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 看来路由是它咋负责了。在这个dll中有一个很特殊的类UrlRoutingModule 
我们来看看它里面主要的核心代码吧: 

复制代码代码如下:


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); 


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); 




在IHttpModule.Init中注册了一个PostResolveRequestCache事件,而该事件主要是调用PostResolveRequestCache这个方法,在这个方法里面有几句很重要的代码是 

复制代码代码如下:


RouteData routeData = this.RouteCollection.GetRouteData(context); 
IRouteHandler routeHandler = routeData.RouteHandler; 
RequestContext requestContext = new RequestContext(context, routeData); 
context.Request.RequestContext = requestContext; 
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); 
context.RemapHandler(httpHandler); 


让我们来分析第一句RouteData routeData = this.RouteCollection.GetRouteData(context) ,这句我们猜测是获取路由信息。要想理解这句代码又得回到我们程序中来,我们在Global.asax.cs文件中的RegisterRoutes方法中,默认有这么一句 

复制代码代码如下:


routes.MapRoute( 
"Default", // 路由名称 
"{controller}/{action}/{id}", // 带有参数的 URL 
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值 
); 


这句代码主要是注册一个路由,这里的url要注意不能随便写,需要有controller和action。具体是怎么实现的了? 

复制代码代码如下:


public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) { 
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; 


各参数如下 

复制代码代码如下:


routeName="Default", // 路由名称 
routeUrl= "{controller}/{action}/{id}", // 带有参数的 URL 
defaults=new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值 
constraints=null 
namespaces=null 


在这里创建了一个Route实例并且把它加入到RouteCollection中了。 
现在又让我们回到 RouteData routeData = this.RouteCollection.GetRouteData(context);这句代码中来,GetRouteData的主要代码如下: 

复制代码代码如下:


public RouteData GetRouteData(HttpContextBase httpContext) 

using (this.GetReadLock()) 

foreach (RouteBase base2 in this) 

RouteData routeData = base2.GetRouteData(httpContext); 
if (routeData != null) 

return routeData; 



return null; 


在这里的base2就是我们先前调用MapRoute是添加的Route的。而Route的GetRouteData的方法如下: 

复制代码代码如下:


public override RouteData GetRouteData(HttpContextBase httpContext) 

string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo; 
RouteValueDictionary values = this._parsedRoute.Match(virtualPath, this.Defaults); 
if (values == null) 

return null; 

RouteData data = new RouteData(this, this.RouteHandler); 
if (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest)) 

return null; 

foreach (KeyValuePair<string, object> pair in values) 

data.Values.Add(pair.Key, pair.Value); 

if (this.DataTokens != null) 

foreach (KeyValuePair<string, object> pair2 in this.DataTokens) 

data.DataTokens[pair2.Key] = pair2.Value; 


return data; 


这个方法很复杂,有许多验证和检查,我们主要关心一句 RouteData data = new RouteData(this, this.RouteHandler); 
当然剩下 RequestContext requestContext = new RequestContext(context, routeData); 
context.Request.RequestContext = requestContext;这2句没什么特别了。 
现在让我们来看看IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);这句究竟干了些什么,意思很明白获取Httphandler。 
那么MvcRouteHandler是如何获取一个Httphandler的了, 

复制代码代码如下:


protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { 
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext)); 
return new MvcHandler(requestContext); 


直接返回了一个MvcHandler实例。 
最有一句context.RemapHandler(httpHandler); 很简单很好明白吧,在HttpContext的RemapHandler方法中有这么一句 this._remapHandler = handler; 
在HttpContext中有这个属性 

复制代码代码如下:


internal IHttpHandler RemapHandlerInstance 

get 

return this._remapHandler; 


那么这个东西又是什么时候调用的了,在HttpApplication的内部类MaterializeHandlerExecutionStep中的 void HttpApplication.IExecutionStep.Execute()方法调用 

复制代码代码如下:


if (httpContext.RemapHandlerInstance != null) 

httpContext.Handler = httpContext.RemapHandlerInstance; 


看到MaterializeHandlerExecutionStep这个了类名,我想大家都能猜到吧。在内部类PipelineStepManager中BuildSteps方法有 

复制代码代码如下:


HttpApplication.IExecutionStep step = new HttpApplication.MaterializeHandlerExecutionStep(app); 
app.AddEventMapping("ManagedPipelineHandler", RequestNotification.MapRequestHandler, false, step); 


我想大家看到这里对mvc整个路由应该有个大致的理解了吧。

延伸 · 阅读

精彩推荐