asp.Netmvcルーティング編IHttpHandlerメソッドの紹介

7795 ワード

勉強はaspを使う.Netはもう長い間、mvcのプロセスを分析してみましょう.個人はmvcシリーズのブログを書き、ソースコードの観点からmvcを分析する計画だ.mvcに触れると必ずルートを経験しますが、ルートはどうやって作られたのでしょうか.私たちのwebではconfigには、ルーティングがどのように責任を負っているのかという言葉があります.この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;
}

ここでbase 2は、以前に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 pair in values)
{
data.Values.Add(pair.Key, pair.Value);
}
if (this.DataTokens != null)
{
foreach (KeyValuePair 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);この文はいったい何をしたのか、意味がよく分かります.
ではMvcRouteHandlerはどのようにしてHttphandlerを取得しましたか?
 
  
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
}

MvcHandlerインスタンスを直接返します.
一番いいのはRemapHandler(httpHandler); 簡単でわかりやすいでしょう、HttpContextのRemapHandlerメソッドにこんなことがあります.remapHandler = handler;
HttpContextにこの属性があります
 
  
internal IHttpHandler RemapHandlerInstance
{
get
{
return this._remapHandler;
}
}

では、これはいつ呼び出されたのでしょうか.HttpApplicationの内部クラスM a t e r ializeHandlerExecutionStepのvoid HttpApplicationです.IExecutionStep.Execute()メソッド呼び出し
 
  
if (httpContext.RemapHandlerInstance != null)
{
httpContext.Handler = httpContext.RemapHandlerInstance;
}

MaterializeHandlerExecutionStepというクラス名を見て、皆さんは推測できると思います.内部クラスPipelineStep ManagerでBuildStepメソッドには
 
  
HttpApplication.IExecutionStep step = new HttpApplication.MaterializeHandlerExecutionStep(app);
app.AddEventMapping("ManagedPipelineHandler", RequestNotification.MapRequestHandler, false, step);

ここではmvc全体のルーティングについて大まかな理解があると思います.