be based on asp.net The life cycle of MVC application

Time:2020-10-3

First of all, we know that HTTP is a stateless request, and its life cycle starts from the client browser sending the request to the end of receiving 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 lifecycle of a request in an MVC application and how it is processed from one control to another. We will also describe in detail the relevant components used throughout the life cycle of the request. Because in the normal development process, we may know how to use the MVC framework to process the relevant requests. Most of the time, we only do the relevant processing between the controller and the action method. We may not be very familiar with the real internal operation mechanism. In fact, when we have a certain understanding of the internal mechanism, we will find that Microsoft’s MVC framework is very extensible. There are extension interfaces everywhere, so that we can define our own processing mechanism through extension. This is why MVC framework is so famous.

When I first learned how to use MVC, one of the problems that bothered me was how to control the flow of a request? What happened from view to controller to action? At that time, I didn’t know what role and role the HTTP module and HTTP handler played in processing a request. After all, MVC is a web development framework. In the whole process of request processing, it must contain HTTP module and HTTP handler. In fact, there are many related components contained in a complete MVC application request life cycle, they all play a very important role in the whole request process. Although most of the time we use the default functions provided by the framework, if we understand the role of each control, we can easily extend and use our own implementation methods. At present, MVC is a more extensible framework.

The following is the main content of this chapter:

HttpApplication

HttpModule

HttpHandler

ASP.NET MVC operation mechanism

UrlRoutingModule

RouteHandler

MvcHandler

ControllerFactory

Controller

ActionInvoker

ActionResult

ViewEngine

HttpApplication

We all know that ASP.NET Before the advent of the MVC framework, most of the frameworks we used for development were ASP.NET In fact, both MVC and webform have the same request processing mechanism. This involves the processing of requests by IIS, which involves a lot of knowledge. We will not introduce it. I will write a special article next time. Let’s start with httpapplication. Let’s take a look at how Microsoft officially defines httpapplication

definition ASP.NET Methods, properties, and events common to all application objects in an application. This class is the user’s Global.asax The base class of the application defined in the file.

Maybe my translation is not very accurate https://msdn.microsoft.com/en-us/library/system.web.httpapplication (v=vs.110).aspx

There is a sentence in the remark of Microsoft official documents: the instance of httpapplication class is in the ASP.NET Created in the infrastructure, not directly by users. Use an instance of the httpapplication class to handle many requests received during its lifetime. However, it can only process one request at a time. In this way, member variables can be used to store data for each request.

That means ASP.NET Applications, whether MVC or webform, eventually arrive at an instance of the httpapplication class. Httpapplication is the whole ASP.NET The core of the infrastructure is responsible for handling requests that are distributed to him. The processing cycle of httpapplication is a complex process. In the whole process, the corresponding events will be triggered at different stages. We can register the corresponding events and inject the processing logic into a certain stage of httpapplication processing requests. In the httpapplication class, 19 events are defined to handle requests arriving at httpapplication instances. That is to say, no matter MVC or webform, they all have to go through these 19 events in the end. So, except that MVC and webfrom are mostly the same in request processing mechanism, what are the differences? Where did they split up? We guess it must be in these 19 methods. Let’s move on.

Let’s look at these 19 events:

Applications are executed in the following order by global.asax Events handled by the module or user code defined in the file:

Event name:

Brief description:

BeginRequest

stayASP.NET As a response to a requestHTTP The first event in the execution pipeline chain occurs

AuthenticateRequest

Occurs when the security module has established a user ID. Note:AuthenticateRequest Event signals that the configured authentication mechanism has authenticated the current request. bookAuthenticateRequest Event ensures that the request is authenticated before processing the attached module or event handler

PostAuthenticateRequest

Occurs when the security module has established a user ID.PostAuthenticateRequest Event inAuthenticateRequest Raised after the event. bookPostAuthenticateRequest Event functions can be accessed byPostAuthenticateRequest Any data processed

AuthorizeRequest

Occurs when the security module has verified user authorization.AuthorizeRequest Event signalingASP.NET The current request has been authorized. bookAuthorizeRequest Events ensure that requests are authenticated and authorized before processing additional modules or event handlers

PostAuthorizeRequest

Occurs when the currently requested user is authorized.PostAuthorizeRequest Event signalingASP.NET The current request has been authorized. bookPostAuthorizeRequest Events ensure that requests are authenticated and authorized before processing additional modules or handlers

ResolveRequestCache

WhenASP.NET Occurs when an authorization event is completed to enable the cache module to service a request from the cache, skipping the event handler (for example, a page orXML Web services)Implementation of

PostResolveRequestCache

stayASP.NET Occurs when the execution of the current event handler is skipped and the cache module is allowed to satisfy a request from the cache.) stayPostResolveRequestCache After the incidentPostMapRequestHandler Create an event handler (corresponding to the request) before the eventURL Page of

PostMapRequestHandler

stayASP.NET Occurs when the current request has been mapped to the corresponding event handler.

AcquireRequestState

WhenASP.NET Occurs when the current state, such as session state, is associated with the current request.

PostAcquireRequestState

Occurs when the request state associated with the current request, such as session state, has been obtained.

PreRequestHandlerExecute

It happened thatASP.NET Start execution of an event handler (for example, a page or aXML Web services)Before.

PostRequestHandlerExecute

stayASP.NET Event handler (for example, a page or aXML Web service)Occurs when execution is complete.

ReleaseRequestState

stayASP.NET Occurs after all request event handlers have been executed. This event causes the status module to save the current state data.

PostReleaseRequestState

stayASP.NET Occurs when execution of all request event handlers has completed and the request status data has been stored.

UpdateRequestCache

WhenASP.NET Occurs when the event handler is executed so that the cache module stores the response that will be used to service subsequent requests from the cache.

PostUpdateRequestCache

stayASP.NET This event occurs when the update of the cache module is complete and the response used to service subsequent requests from the cache is stored.

LogRequest

stayASP.NET This event occurs when the update of the cache module is complete and the response used to service subsequent requests from the cache is stored.

Only inIIS 7.0 In integrated mode and.NET Framework At least3.0 Version is supported

PostLogRequest

stayASP.NET Occurs after all event handlers for the logrequest event have been processed.

Only inIIS 7.0 In integrated mode and.NET Framework At least3.0 Version is supported.

EndRequest

stayASP.NET As a response to a requestHTTP The last event in the execution pipeline chain occurs.

Always raised when the completerequest method is calledEndRequest event.

For a ASP.NET For applications, httpapplication derives from Global.aspx (you can see that all the applications we create have one Global.aspx We can use the Global.aspx The httpapplication request is customized in the file, that is to inject one of the 19 events for logical processing. stay Global.aspx According to “application”_ {event name} “is named for event registration.

Event name is the name of the above 19 events. For example, application_ Endrequest is used to handle the endrequest event of the application.

HttpModule

ASP.NET It has a highly scalable engine and can handle requests for different resource types. This is the HttpModule. When a request goes in ASP.net In the pipeline, the HttpHandler object that matches the resource is ultimately responsible for processing the request, but before the HttpHandler processes it, ASP.NET All configured HttpModule objects are loaded and initialized first. When HttpModule is initialized, some callback events will be injected into the corresponding events of httpapplication. All httpmodules implement the ihttpmodule interface, one of which has an init method.


public interface IHttpModule
{
 // Methods
 void Dispose();
 void Init(HttpApplication context);
}

The init method accepts an httpapplication object. With this object, it is easy to register one of the 19 events in httpapplication. In this way, when the httpapplication object executes to an event, it will naturally start.

HttpHandler

For requests of different resource types, ASP.NET Different HttpHandler will be loaded to handle. All HttpHandler implements the ihtphandler interface.


public interface IHttpHandler
{
 // Methods
 void ProcessRequest(HttpContext context);

 // Properties
 bool IsReusable { get; }
}

We can see that the interface has a method processrequest, which, as the name suggests, is mainly used to process requests. So each request is eventually distributed to its own HttpHandler to process the request.

ASP.NET MVC operation mechanism

Well, the above said so much, in fact, is to pave the way for here. It’s time to get to the point. Take a look at the following figure to describe the main pipeline events experienced by MVC:

The figure above shows the whole process from an HTTP request to a response of a complete MVC application. From the urlroutingmodule intercepts the request to the final actionresult executes the executeresult method to generate the response.

Now let’s explain in detail what these processes do.

UrlRoutingModule

The entry URL routingmodule for MVC applications

Start with a request, which we talked about earlier ASP.NET The initialization event init of an HttpModule object is loaded, and all HttpModule objects implement the ihttpmodule interface. Let’s look at the implementation of the urlroutingmodule

From the figure above, we can see that the urlroutingmodule implements the interface ihttpmodule. When a request is transferred to ASP.NET For the urlroutingmodule objectInit()method.

So why is the urlroutingmodule loaded and initialized? Why not another HttpModule object? With that in mind, we continue.

stay ASP.NET MVC, the most core is“Routing system”And the core of the routing system comes from a powerfulSystem.Web.Routing.dllComponent.System.Web.Routing.dll Not unique to MVC, but the MVC framework is inseparable from it.

First, let’s look at how the urlroutingmodule works.

(1) The configuration of IIS website can be divided into two parts: global Web.config And this station Web.config 。 Asp.Net Routing is global, so it is configured globally Web.Config We can find it in the following path: “C / windows”\ Microsoft.NET \Framework version number\ Web.config “, I extract some important configurations for you to have a look:


<httpModules>
 <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"/>
 </httpModules>

Do you see the line marked in red on my top: < add name = “urlroutingmodule-4.0″ type=“ System.Web.Routing .UrlRoutingModule” />

The urlroutingmodule is not MVC specific, it is a global configuration, that is, all the ASP.NET Requests will arrive here, so the module can’t decide whether it’s an MVC or a webform request yet. But it’s also crucial.

(2) Through the global Web.Config Registered in System.Web.Routing.UrlRoutingModuleAfter receiving the request, the IIS request processing pipeline will load theInit()method. The source code is as follows:


[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;
 }
 }
}

Take a look at how to implement the init method in the urlroutingmodule source code above. In the init() method, I marked the red place:

application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);

This step is very important. See, it is to register the postresolverequestcache event in the 19 httpapplication events. The registered method is the onapplicationpostresolverequestcache event. That is to say, when the httpapplication object executes the postresolverequestcache event, it will execute the onapplication postresolverequestcache event. The decision is the key to the MVC mechanism processing requests, which is the onapplication postresolverequestcache event.

From the source code, we can see that when the onapplication postresolverequestcache event is executed, the postresolverequestcache method is finally executed. The key point is here.

When the request arrives at the urlroutingmodule, the urlroutingmodule takes out the routedata information such as controller and action in the request and matches all the rules in the routing table. If the request matches, it hands the request to iroutehandler, that is, mvcrotehandler. We can take a look at the source code of urlroutingmodule. Here are some core codes:

Let’s analyze the source code of this method

public virtual void PostResolveRequestCache(HttpContextBase context)
{
 //Through the static method getroutedata of routecollection, the instance of routedata encapsulating routing information is obtained
 RouteData routeData = this.RouteCollection.GetRouteData(context);
 if (routeData != null)
 {
 //Then get mvcroutehandler from routedata
 IRouteHandler routeHandler = routeData.RouteHandler;
 ......
 if (!(routeHandler is StopRoutingHandler))
 {
 ......
 //Call IRouteHandler.GetHttpHandler (), gets an instance of the ihttphandler type from the IRouteHandler.GetHttpHandler Get, this has to go to MVC source code to see
 IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
 ......
 //If appropriate, map the previously obtained ihttphandler type instance to the IIS HTTP processing pipeline
 context.RemapHandler(httpHandler);
 }
 }
}

See, through the routing rules, the return is not empty, indicating that the matching is correct. As for the matching of routing rules, it is not short. I will not introduce it here. I will explain the routing mechanism in detail next time when I have time. After successful matching, an object of type routedata is returned. What properties does the routedata object have? Take a look at this line of source code: iroutehandler routehandler= routeData.RouteHandler Or from the source code, we know that routedate has a routehandler property.

How does the urlrouting module select matching rules?

Let’s take a look at our new MVC application, which is in app_ There is one under the start folder RouteConfig.cs Class. The contents of this class are as follows:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace ApiDemo
{
 public class RouteConfig
 {
 public static void RegisterRoutes(RouteCollection routes)
 {
 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 routes.MapRoute(
 name: "Default",
 url: "{controller}/{action}/{id}",
 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
 );
 }
 }
}

In this class, we mainly add routing rules to the routing table. Looking at the above urlroutingmodule class, there is a routcollection property, so the urlroutingmodule can obtain all the rules in the routing table. It is worth noting that the matching of routing rules is sequential. If multiple rules can be matched, the urlroutingmodule will return to select the first matching rule and will not continue to match. On the contrary, if a request does not match any routes, the request will not be processed.

The routehandler in routedata returned here is mvcroutehandler. Why? Let’s move on to routehandler.

RouteHandler

Generate mvcghander

In the process of route matching above, mvcroutehandler, which is associated with matching route, implements iroutehandler interface. Mvcroutehandler is mainly used to obtain references to mvcganneler. MVC handler implements the ihtttpandler interface.

The function of mvcroutehandler is to generate MVC handler that implements the ihttphandler interface. As we said before, the final processing of requests is the corresponding HttpHandler. Then MVC is the natural processing of the request. Therefore, it is very important to return mvcroutehandler here

So,MvcRouteHandlerWhere did it come from? as everyone knows, ASP.NET MVC project is launched from application in global_ The start() method starts, so take a look at it:


public class MvcApplication : System.Web.HttpApplication
 {
 protected void Application_Start()
 {

 RouteConfig.RegisterRoutes(RouteTable.Routes);
 BundleConfig.RegisterBundles(BundleTable.Bundles);
 }
 }

 public class RouteConfig
 {
 public static void RegisterRoutes(RouteCollection routes)
 {
 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
System.Web.Mvc.RouteCollectionExtensions
 routes.MapRoute(
 name: "Default",
 url: "{controller}/{action}/{id}",
 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
 );
 }
 }

Take a look at the red code above me: This is route registration, and the mystery is here. Let’s take a look at the maproute source code


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()
 };
 ......
 return route;
 }

Take a look at our 5-8 lines of code. In the MVC application, when the route is registered, we have given it a default httproutehandler object, which is new Mvcroutehandler (). Now we push back. Our MVC program has determined that httproutehandler is mvcroutehandler when the route is registered. In the previous postresolverequestcache method, when our request matches the route successfully, it will return mvcroutehandler.

OK, the mvcroutehandler is generated. So what can mvcroutehandler do? What did you do?

Looking back at the postresolverequestcache method, after successfully obtaining the ihttproutehandler object, namely mvcroutehandler, the following operation is performed:

IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

Let’s look at the source code of this ihttphandler


namespace System.Web.Routing
{ 
 public interface IRouteHandler
 { 
 IHttpHandler GetHttpHandler(RequestContext requestContext);
 }
}

There is a gethttphandler method, which is called exactly. Let’s see how mvcroutehandler implements this gethttphandler


public class MvcRouteHandler : IRouteHandler
{
 // Fields
 private IControllerFactory _controllerFactory;

 // Methods
 public MvcRouteHandler()
 {
 }

 public MvcRouteHandler(IControllerFactory controllerFactory)
 {
 this._controllerFactory = controllerFactory;
 }

 protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
 {
 requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
 return new MvcHandler(requestContext);
 }

 protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)
 {
 string str = (string) requestContext.RouteData.Values["controller"];
 if (string.IsNullOrWhiteSpace(str))
 {
  throw new InvalidOperationException(MvcResources.MvcRouteHandler_RouteValuesHasNoController);
 }
 IControllerFactory factory = this._controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
 return factory.GetControllerSessionBehavior(requestContext, str);
 }

 IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
 {
 return this.GetHttpHandler(requestContext);
 }
}

If you look at lines 16-20, you should understand. As a matter of course, the MVC handler object is returned. As we said earlier, the request is ultimately processed by the corresponding HttpHandler object. MVC handler is the HttpHandler used to process MVC requests. Mvcproutehandler hands over the request to MVC handler to handle subsequent events in the request processing pipeline.

Let’s take a look at what MVC handler does:

MvcHandler

MVC handler is the final processing of the request.

Mvvhandler is defined as follows:

We can see that mvczandler is an ordinary HTTP handler. We know that an HTTP handler needs to implement a processrequest() method, which is the core of processing the request. So MVC handler implements the processrequest () method.

Main functions of processrequest:

(1) In ASP.NET In MVC, the processrequest() method of mvchandler will be called. This method will activate the controller class object of the specific request, trigger the action method, and return the actionresult instance.

(2) If the actionresult is a non viewresult, such as jsonresult and contentresult, these contents will be directly sent to the response response flow and displayed to the client. If the actionresult is a viewresult, it will enter the next rendering view phase.

(3) In the view rendering phase, the viewengine finds the view to be rendered, and the view is loaded into webviewpage < tModel > type, and then renders to generate HTML, and finally returns HTML.

Processrequest() is defined as follows:


// Copyright (c) Microsoft Open Technologies, Inc.<pre>// All rights reserved. See License.txt in the project root for license information.
void IHttpHandler.ProcessRequest(HttpContext httpContext) 
{
 ProcessRequest(httpContext);
}
protected virtual void ProcessRequest(HttpContext httpContext) 
{
 HttpContextBase iHttpContext = new HttpContextWrapper(httpContext);
  ProcessRequest(iHttpContext);
}
protected internal virtual void ProcessRequest(HttpContextBase httpContext) {
 SecurityUtil.ProcessInApplicationTrust(() => {
 IController controller;
 IControllerFactory factory;
 ProcessRequestInit(httpContext, out controller, out factory);
 try
 {
 controller.Execute(RequestContext);
 }
 finally
 {
 factory.ReleaseController(controller);
 }
 });
}

As can be seen from the above code, a processrequestinit() method is called, which is defined as follows:


private void ProcessRequestInit(HttpContextBase httpContext, 
  out IController controller, out IControllerFactory factory) {
 // If request validation has already been enabled, make it lazy.
 // This allows attributes like [HttpPost] (which looks
 // at Request.Form) to work correctly without triggering full validation.
 bool? isRequestValidationEnabled = 
 ValidationUtility.IsValidationEnabled(HttpContext.Current);
 if (isRequestValidationEnabled == true) {
 ValidationUtility.EnableDynamicValidation(HttpContext.Current);
 }
 AddVersionHeader(httpContext);
 RemoveOptionalRoutingParameters();
 // Get the controller type
 string controllerName = RequestContext.RouteData.GetRequiredString("controller");
 // Instantiate the controller and call Execute
 factory = ControllerBuilder.GetControllerFactory();
 controller = factory.CreateController(RequestContext, controllerName);
 if (controller == null) {
 throw new InvalidOperationException(
 String.Format(
  CultureInfo.CurrentCulture,
  MvcResources.ControllerBuilder_FactoryReturnedNull,
  factory.GetType(),
  controllerName));
 }
}

stayIn the processrequestinit() method, the object factory of controllerfactory() is first created. Then, the controllerfactory creates an instance of the relevant controller. Finally, the excete() method of the controller is called.

OK, let’s take a look at the controllerfactory:

ControllerFactory

It is mainly used to generate controller objects

Controllerfactory implements the interfaceIControllerFactory.

Controller

reachHere, we will know that mvczandler finally creates the controller object through the processrequest() method. Here, we should know that there are many action methods in the controller, and at least one action method will be called for each request. In order to explicitly implement the icontroller interface, a controllerbase class in the framework has implemented the icontroller interface. In fact, our own controller can not inherit the controllerbase, as long as we implement the icontroller interface.


public abstract class ControllerBase : IController
{
 protected virtual void Execute(RequestContext requestContext)
 {
 if (requestContext == null)
 {
  throw new ArgumentNullException("requestContext");
 }
 if (requestContext.HttpContext == null)
 {
  throw new ArgumentException(
  MvcResources.ControllerBase_CannotExecuteWithNullHttpContext, 
  "requestContext");
 }
 VerifyExecuteCalledOnce();
 Initialize(requestContext);
 using (ScopeStorage.CreateTransientScope())
 {
  ExecuteCore();
 }
 }
 protected abstract void ExecuteCore(); 
 // .......

The controller object actually uses actioninvoker to call the action method. After the controller object is created, the excet method in the controllerbase class of the controller object will be executed. The excite method also calls the excelcore() method. The excelcore() method is implemented in the controller class. Excelcore calledThe invokeraction method of actioninvoker is used to call the action method.

ActionInvoker

The actioninvoker method has a very important responsibility to find the action method in the controller and call it.

Actioninvoker is an object that implements the iactioninvoker interface


bool InvokeAction(
  ControllerContext controllerContext,
  string actionName
) 

If an actioninvoker property is exposed in the controller class, a ControllerActionInvoker will be returned. Actioninvoker creates a ControllerActionInvoker object through the createactioninvoker () method.


public IActionInvoker ActionInvoker {
 get {
 if (_actionInvoker == null) {
  _actionInvoker = CreateActionInvoker();
 }
 return _actionInvoker;
 }
 set {
 _actionInvoker = value;
 }
}
 protected virtual IActionInvoker CreateActionInvoker() {
 return new ControllerActionInvoker();
}

We can see that createactioninvoker () is a virtual method, and we can implement our own actioninvoker

The actioninvoker class needs to be executed by matching the detailed actions in the controller, which are provided by the controllerdescriptor. Controllerdescriptor and actiondescriptor play an important role in actioninvoker. These two are detailed descriptions of controller and action. The controller descriptor describes the relevant information of the controller, such as name, action, type, etc.

The actiondescriptor describes the details related to the action, such as name, controller, parameters, attributes and fifters.

One of the required methods in actiondescriptor is findaction(), which returns an actiondescriptor object, so actioninvoker knows which action to call.

ActionResult

So far, we’ve seen action methods called by actioninvoker. All action methods have a feature that returns data of type actionresult.


public abstract class ActionResult
 {
 public abstract void ExecuteResult(ControllerContext context);
 }

Executeresult() is an abstract method, so different subclasses can provide different implementations of executeresult().

After the actionresult is executed, the response is output to the client.

ViewEngine

Viewresult is almost the return type of most applications, and the view is displayed mainly through the viewengine engine. The viewengine may primarily be the engine that generates HTML elements. Framework provides two kinds of engines, razor view engine and web form view engine. If you want to customize the engine, you can create an engine by implementing iviewengine interface.

Iviewengine has the following methods:

1. Findpartialview: the findpartialview method is called when the controller needs to return a partialview.

2、FindView

3. Releaseview: mainly used to release resources from viewengine

Viewresultbase and viewresultThey are two important classes. Viewresultbase contains the following implementation code:


if (View == null)
  {
  result = FindView(context); //calls the ViewResult's FindView() method
  View = result.View;
  }

  ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);
  View.Render(viewContext, context.HttpContext.Response.Output);

protected abstract ViewEngineResult FindView(ControllerContext context); //this is implemented by          //the ViewResult

protected override ViewEngineResult FindView(ControllerContext context)
 {
 ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);
 if (result.View != null)
 {
  return result;
 }
 //rest of the code omitted 
 }

When the executeresult method of viewresult is called, the executeresult method of viewresultbase is called, and then viewresultbase calls findview of viewresult. Next, viewresult returns viewengineresult, which then calls the render() method to draw the HTML output response.

Conclusion: if we understand what happened in the whole process, which classes and which methods are called, we can easily extend where we need to extend.

The above article is based on asp.net The life cycle of MVC application (detailed explanation) is the whole content that Xiaobian shares with you. I hope to give you a reference and also hope that you can support developeppaer more.