First we know that HTTP is a stateless request, and that his life cycle begins with a request from the client browser to the end of the response. So what does an MVC application do from making a request to getting a response?
In this article we will discuss in detail the life cycle of a request for an MVC application, from one control to another, how it is handled. We will also describe in detail the related components that are used throughout the life cycle of the request. Because in the normal development process, we may know how to use the MVC framework to handle the related requests, most of the time we just do the controller and the action method to do the relevant processing, for the actual internal operating mechanism may not be very understanding. In fact, when we have a certain understanding of the internal mechanism, we will find that Microsoft's MVC framework is very extensible, and there are extension interfaces everywhere, so that we can define the processing mechanism we need by extension, which is why the MVC framework is so famous.
When I first learned to use MVC, one of the problems that bothered me was what was the process control of a request? What's going on between the view and the controller and the action? At that time I was not sure what role the HTTP module and HTTP handler play in handling a request. After all, MVC is a Web development framework that definitely includes the HTTP module and HTTP handler throughout the request process. In fact, there are a lot of related components that are contained in a full MVC application request life cycle, and they play a very important role throughout the request process. Although most of the time we are using the default function provided by the framework, if we understand the role of each control, we can easily extend and use our own implementation of the method, for now, MVC is a more extensible framework.
HttpApplication we all know that before the ASP. NET MVC framework, most of our development uses the framework of ASP. In fact, both MVC and WebForm, most of them are the same in the request processing mechanism. This involves IIS processing the request, involving more knowledge, we do not introduce, next time I have the opportunity to write a special article. Let's start with the HttpApplication. Let's take a look at how Microsoft officially defines HttpApplication:
Defines methods, properties, and events common to all application objects in an ASP. This class is the base class for the application that the user defines in the Global.asax file.
Maybe my translation is not very accurate, the original text is connected here: Https://msdn.microsoft.com/en-us/library/system.web.httpapplication (v=vs.110). aspx
In Microsoft's Official document, there is a remark: instances of the HttpApplication class are created in the ASP. NET infrastructure, not directly created by the user. Use an instance of the HttpApplication class to handle the many requests received during its lifetime. However, it can only process one request at a time. This allows the member variable to be used to store data for each request.
This means that an ASP. NET application, either MVC or WebForm, will eventually arrive at an instance of the HttpApplication class. HttpApplication is at the heart of the entire ASP. NET infrastructure and is responsible for processing requests that are distributed to him. HttpApplication processing a request's cycle is a complex process that, throughout the process, triggers a matched event at different stages. We can register the appropriate event to inject the processing logic into a phase of the HttpApplication processing request.
In the HttpApplication class, 19 events are defined to handle requests that reach the HttpApplication instance. That is to say, whether MVC or webform, ultimately through the processing of these 19 events, so in addition to just said MVC and webfrom in the request processing mechanism is the majority of the same, where is the difference? Where did they start to go their separate ways? We suspect that it must be in these 19 methods. Let's keep looking down.
Let's take a look at these 19 events:
The application executes the events handled by the module or user code defined in the Global.asax file in the following order:
Event Name: |
Simple description: |
BeginRequest |
Occurs as the first event in an HTTP execution pipeline chain when ASP. NET responds to a request |
AuthenticateRequest |
Occurs when the security module has established a user ID. Note: The AuthenticateRequest event signaled that the configured authentication mechanism has authenticated the current request. The AuthenticateRequest event is booked to ensure that the request is authenticated before the attached module or event handler is processed |
Postauthenticaterequest |
Occurs when the security module has established a user ID. The Postauthenticaterequest event is raised after the AuthenticateRequest event occurs. The ability to subscribe to the Postauthenticaterequest event can access any data processed by postauthenticaterequest |
AuthorizeRequest |
Occurs when the security module has authenticated user authorization. The AuthorizeRequest event signaled that the current request was authorized by ASP. Booking the AuthorizeRequest event ensures that the request is authenticated and authorized before the attached module or event handler is processed |
Postauthorizerequest |
Occurs when the currently requested user is authorized. The Postauthorizerequest event signaled that the current request was authorized by ASP. Booking the Postauthorizerequest event ensures that the request is authenticated and authorized before the attached module or handler is processed |
Resolverequestcache |
Skips the execution of an event handler (for example, a page or XML Web Service) when ASP. NET finishes authorization event to cause the cache module to serve the request from the cache |
Postresolverequestcache |
Occurs when ASP. NET skips the execution of the current event handler and allows the cache module to satisfy requests from the cache. Creates an event handler (the page that corresponds to the request URL) after the Postresolverequestcache event, before the Postmaprequesthandler event |
Postmaprequesthandler |
Occurs when ASP. NET has mapped the current request to the appropriate event handler. |
AcquireRequestState |
Occurs when ASP. NET gets the current state, such as session state, associated with the current request. |
Postacquirerequeststate |
Occurs when a request state, such as session state, has been obtained associated with the current request. |
PreRequestHandlerExecute |
Occurs just before ASP. NET begins executing an event handler (for example, a page or an XML Web services). |
PostRequestHandlerExecute |
Occurs when an ASP. NET event handler (for example, a page or an XML Web service) finishes executing. |
ReleaseRequestState |
Occurs after all request event handlers have been executed by ASP. This event causes the state module to save the current state data. |
Postreleaserequeststate |
Occurs when ASP. NET has completed execution of all request event handlers and the request state data has been stored. |
Updaterequestcache |
Occurs when ASP. NET executes the event handler so that the cache module stores the response that will be used to serve the subsequent requests from the cache. |
Postupdaterequestcache |
This event occurs after ASP. NET completes the update of the cache module and stores the response to service the subsequent requests from the cache. |
Logrequest |
This event occurs after ASP. NET completes the update of the cache module and stores the response to service the subsequent requests from the cache. This event is supported only if IIS 7.0 is in Integrated mode and the. NET Framework is at least 3.0 versions |
Postlogrequest |
Occurs after ASP. NET finishes processing all event handlers for the Logrequest event. This event is supported only if IIS 7.0 is in Integrated mode and the. NET Framework is at least 3.0 versions. |
EndRequest |
Occurs as the last event in an HTTP execution pipeline chain when ASP. NET responds to a request. The EndRequest event is always raised when the CompleteRequest method is called. |
For an ASP. HttpApplication derivation and global.aspx (you can see that we've created an application that has a global.aspx file), we can set the HttpApplication request in the global.aspx file To inject an event in these 19 events for a logical processing operation. In global.aspx we use the method named "Application_{event name}" to register the event.
Event name is the name of the above 19 events. For example, Application_EndRequest is used to handle application endrequest events.
HttpModule
Asp. NET has a highly extensible engine and is able to handle requests for different resource types. This is HttpModule. When a request is transferred to an ASP. NET pipeline, the final processing request is the HttpHandler object that matches the resource, but before HttpHandler is processed, ASP will load and initialize all the configured HttpModule objects first.
When the HttpModule is initialized, some callback events are injected into the HttpApplication corresponding event. All HttpModule implements the IHttpModule interface, which has an Init method.
public interface IHttpModule
{//Methods
void Dispose (); void Init (HttpApplication context);
}
Seeing the Init method takes a HttpApplication object, it's easy to register an event in one of the 19 events in HttpApplication. This naturally starts when the HttpApplication object executes to an event.
HttpHandler
For requests of different resource types, ASP. NET will load different HttpHandler to handle. All HttpHandler implement the IHttpHandler interface.
public interface IHttpHandler
{
Methods
void ProcessRequest (HttpContext context);
Properties
BOOL IsReusable {get;}
}
We see this interface has a method ProcessRequest, as the name implies, this method is mainly used to handle the request. So each request is eventually distributed to its own corresponding HttpHandler to process the request.
ASP. NET MVC operating mechanism
Well, the above said so much, in fact, is to do the bedding here. Finally got to the point. Let's take a look at the following diagram, which describes the pipeline events of MVC's main experience:
is a complete MVC application that takes an HTTP request to the full response of the process. The response is generated from the UrlRoutingModule intercept request to the final ActionResult execution Executeresult method.
Let's take a closer look at what these processes have done.
UrlRoutingModule
Entry UrlRoutingModule for MVC applications
First, we start with a request that ASP. NET loads an initialization event init for an HttpModule object, and all HttpModule objects implement the IHttpModule interface. Let's look at the implementation of UrlRoutingModule:
From here we see that UrlRoutingModule implements the interface IHttpModule, which loads the init () method of the UrlRoutingModule object when a request is transferred to the ASP.
So why is UrlRoutingModule being loaded and initialized? Why not another HttpModule object? With this question we continue.
In ASP., the core of this is the "routing system", while the core of the routing system originates from a powerful System.Web.Routing.dll component. System.Web.Routing.dll is not unique to MVC, but the MVC framework is inseparable from it.
First, let's look at how UrlRoutingModule works.
(1) The configuration of the IIS Web site can be divided into two blocks: the global web. config and the site Web. config. The ASP. NET routing is global, so it is configured in the world Web. config, which we can find in the following path: "C\windows\microsoft.net\framework\ version number \CONFIG\Web.config ", I extracted some important configurations for everyone to look at:
<add name= "OutputCache" type= "System.Web.Caching.OutputCacheModule"/>
<add name= "Session" type= "System.Web.SessionState.SessionStateModule"/>
<add name= "windowsauthentication" type= "System.Web.Security.WindowsAuthenticationModule"/>
<add name= "FormsAuthentication" type= "System.Web.Security.FormsAuthenticationModule"/>
<add name= "passportauthentication" type= "System.Web.Security.PassportAuthenticationModule"/>
<add name= "rolemanager" type= "System.Web.Security.RoleManagerModule"/>
<add name= "urlauthorization" type= "System.Web.Security.UrlAuthorizationModule"/>
<add name= "fileauthorization" type= "System.Web.Security.FileAuthorizationModule"/>
<add name= "anonymousidentification" type= "System.Web.Security.AnonymousIdentificationModule"/>
<add name= "Profile" type= "System.Web.Profile.ProfileModule"/>
<add name= "Errorhandlermodule" type= "System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, version=4.0.0.0, Culture=neutral, publickeytoken=b03f5f7f11d50a3a "/>
<add name= "ServiceModel" type= "System.ServiceModel.Activation.HttpModule, System.ServiceModel.Activation, version=4.0.0.0, culture=neutral, publickeytoken=31bf3856ad364e35 "/>
<add name= "UrlRoutingModule-4.0" type= "System.Web.Routing.UrlRoutingModule"/>
<add name= "ScriptModule-4.0" type= "System.Web.Handlers.ScriptModule, System.Web.Extensions, version=4.0.0.0, Culture=neutral, publickeytoken=31bf3856ad364e35 "/>
You see no, I above the line marked red: <add name= "UrlRoutingModule-4.0" type= "System.Web.Routing.UrlRoutingModule"/>
UrlRoutingModule is not unique to MVC, which is a global configuration, meaning that all ASP. NET requests will arrive here, so the module does not ultimately decide whether to be MVC or webform requests. But it's also a crucial place.
(2) The Init () method of the UrlRoutingModule type is loaded by registering the SYSTEM.WEB.ROUTING.URLROUTINGMODULE,IIS request processing pipeline to the request in the global web. config. The source code into the following:
[Typeforwardedfrom ("System.Web.Routing, version=3.5.0.0, Culture=neutral, publickeytoken=31bf3856ad364e35")]
public class Urlroutingmodule:ihttpmodule
{
Fields
private static readonly Object _contextkey = new Object ();
private static readonly Object _requestdatakey = new Object ();
Private RouteCollection _routecollection;
Methods
protected virtual void Dispose ()
{
}
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)
{
HttpApplication application = (HttpApplication) sender;
HttpContextBase context = new Httpcontextwrapper (application. Context);
This. Postresolverequestcache (context);
}
[Obsolete ("This method is Obsolete. Override the Init method to use the Postmaprequesthandler event. ")]
public virtual void Postmaprequesthandler (HttpContextBase 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.CurrentCulture, 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);
}
}
}
}
[Targetedpatchingoptout ("Performance critical to-inline this type of method across NGen image boundaries")]
void Ihttpmodule.dispose ()
{
This. Dispose ();
}
[Targetedpatchingoptout ("Performance critical to-inline this type of method across NGen image boundaries")]
void Ihttpmodule.init (HttpApplication application)
{
This. Init (application);
}
Properties
Public RouteCollection RouteCollection
{
Get
{
if (this._routecollection = = null)
{
This._routecollection = routetable.routes;
}
return this._routecollection;
}
[Targetedpatchingoptout ("Performance critical to-inline this type of method across NGen image boundaries")]
Set
{
This._routecollection = value;
}
}
}
The life cycle of an ASP. NET MVC application (top)