视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
asp.net mvc路由篇 如何找到 IHttpHandler方法介绍
2020-11-27 22:42:14 责编:小采
文档


学习是使用asp.net已经有很长一段时间了,现在就来分析一下mvc的整过过程吧。个人计划写一个mvc系列的博文,仅从源代码的角度来分析mvc。在接触mvc时我们一定会经历路由,那么路由这东东是怎么搞出来的啊。在我们的web.config中有这么一句: <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD3E35" /> 看来路由是它咋负责了。在这个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整个路由应该有个大致的理解了吧。

下载本文
显示全文
专题