asp.net mvc路由篇 如何找到 IHttpHandler方法介绍
程序员文章站
2024-03-06 16:25:56
学习是使用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整个路由应该有个大致的理解了吧。
我们来看看它里面主要的核心代码吧:
复制代码 代码如下:
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整个路由应该有个大致的理解了吧。
上一篇: Android 代码JIT友好度检测工具