How to find the IHttpHandler method in the asp. net mvc routing section

  • 2020-05-17 05:21:20
  • OfStack

It has been a long time since we learned to use asp.net. Now let's analyze the whole process of mvc. I plan to write a blog about mvc series, analyzing mvc only from the perspective of source code. When we touch mvc, we will experience routing, so how do we get the routing? In our web.config, we have the following sentence: < add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" / > It seems to be responsible for routing. There is a special class called UrlRoutingModule in dll
Let's take a look at the main core code:
 
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); 
} 
} 
} 
} 

An PostResolveRequestCache event is registered in IHttpModule.Init, and this event mainly calls the PostResolveRequestCache method. In this method, there are a few important lines of code
 
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) To understand this code we have to go back to our program, and we have this default in the RegisterRoutes method in the Global.asax.cs file
 
routes.MapRoute( 
"Default", //  The name of the routing  
"{controller}/{action}/{id}", //  parametric  URL 
new { controller = "Home", action = "Index", id = UrlParameter.Optional } //  Parameter default  
); 

The main purpose of this code is to register a route. Please note that url should not be written casually, but controller and action should be included. How did it work?
 
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; 
} 

The parameters are as follows
 
routeName="Default", //  The name of the routing  
routeUrl= "{controller}/{action}/{id}", //  parametric  URL 
defaults=new { controller = "Home", action = "Index", id = UrlParameter.Optional } //  Parameter default  
constraints=null 
namespaces=null 

Here you create an instance of Route and add it to RouteCollection.
Now let's go back to RouteData routeData = this.RouteCollection.GetRouteData (context); In this code, the main code of GetRouteData is as follows:
 
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; 
} 

So base2 here is the Route that we called MapRoute before. The method of GetRouteData of Route is as follows:
 
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; 
} 

This method is very complex and has many validations and checks. We are mainly concerned with 1 sentence RouteData data = new RouteData(this, this.RouteHandler);
Of course, RequestContext requestContext = new RequestContext(context, routeData);
context. Request. RequestContext = requestContext; These two sentences are nothing special.
Now let's look at IHttpHandler httpHandler = routeHandler.GetHttpHandler (requestContext); What does this mean? It is quite clear to get Httphandler.
So how does MvcRouteHandler get one Httphandler,
 
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { 
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext)); 
return new MvcHandler(requestContext); 
} 

Directly returns an instance of MvcHandler.
context.RemapHandler(httpHandler); It's easy to understand. In the HttpContext RemapHandler method, there is a sentence this. _remapHandler = handler;
This property is available in HttpContext
 
internal IHttpHandler RemapHandlerInstance 
{ 
get 
{ 
return this._remapHandler; 
} 
} 

So when is this thing called, the void HttpApplication.IExecutionStep.Execute () method call in HttpApplication's inner class MaterializeHandlerExecutionStep
 
if (httpContext.RemapHandlerInstance != null) 
{ 
httpContext.Handler = httpContext.RemapHandlerInstance; 
} 

You see the name of MaterializeHandlerExecutionStep, which I think you can guess. The BuildSteps method is found in the inner PipelineStepManager class
 
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); 
0
I think you can see here a general understanding of the whole mvc routing.

Related articles: