欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-03-05 14:04:42
学习是使用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整个路由应该有个大致的理解了吧。