In the previous article, "ASP. 19 Key Links (7-12) for the pipeline life cycle," which has experienced 7-12 key points, this article continues.
⒀ when the request arrives at UrlRoutingModule, UrlRoutingModule takes out the controller, action and other routedata information in the request, matches all the rules in the routing table, if matching, Give the request to Iroutehandler, namely Mvcroutehandler
Mvcroutehandler is used to generate mvchandler that implements the IHttpHandler interface:
namespace system.web.routing{ publicinterface iroutehandler { IHttpHandler Gethttphandler (RequestContext requestcontext);} }
UrlRoutingModule how to hand over the request to Mvcroutehandler?
By analyzing the source code of UrlRoutingModule, you can see:
Obtaining Routedata instances that encapsulate routing information through the static method of RouteCollection Getroutedata
Routedata Routedata = this. Routecollection.getroutedata (context);
And get Mvcroutehandler from Routedata.
Iroutehandler Routehandler = Routedata.routehandler;
Why is it possible to get Mvcroutehadnler from Routedata?
Because when we registered the route using the Maproute () method in HttpApplication's first pipeline event, the Mvcroutehandler was injected into the route through the route class's constructor.
Public StaticRoute MapRoute ( ThisRouteCollection routes,stringNamestringUrlObjectDefaultsObjectConstraintsstring[] namespaces) { if(Routes = =NULL) { Throw NewArgumentNullException ("Routes"); } if(url = =NULL) { Throw NewArgumentNullException ("URL"); } Route Route=NewRoute (URL,NewMvcroutehandler ()) {Defaults=Newroutevaluedictionary (defaults), Constraints=Newroutevaluedictionary (constraints), Datatokens=Newroutevaluedictionary ()}; if((Namespaces! =NULL) && (namespaces. Length >0) ) {route. datatokens["Namespaces"] =namespaces; } routes. ADD (name, route); returnRoute; }
⒁mvcroutehandler, hand over the request to Mvchandler.
or from UrlRoutingModule source can be seen, through the HttpHandler Gethttphandler () method to achieve the IHttpHandler interface Mvchandler:
IHttpHandler HttpHandler = Routehandler.gethttphandler (requestcontext); context. Remaphandler (HttpHandler);
Mvchandler part of the source code is:
Public classMvchandler:ihttpasynchandler, IHttpHandler, irequiressessionstate{protected Internal Virtual voidProcessRequest (HttpContextBase HttpContext) {securityutil.processinapplicationtrust ()={IController controller; Icontrollerfactory Factory; Processrequestinit (HttpContext, outController outFactory);//initialized the Controllerfactory Try{controller. Execute (RequestContext); } finally{Factory. Releasecontroller (Controller); } }); } Private voidProcessrequestinit (HttpContextBase HttpContext, outIController Controller, outIcontrollerfactory Factory) { BOOL? isrequestvalidationenabled =validationutility.isvalidationenabled (httpcontext.current); if(isrequestvalidationenabled = =true) {validationutility.enabledynamicvalidation (httpcontext.current); } addversionheader (HttpContext); Removeoptionalroutingparameters (); stringControllername = RequestContext.RouteData.GetRequiredString ("Controller"); Factory=controllerbuilder.getcontrollerfactory (); Controller=Factory. Createcontroller (RequestContext, controllername); if(Controller = =NULL) { Throw NewInvalidOperationException (String.Format (cultureinfo.currentculture,mvcresources.controllerbuilder_ Factoryreturnednull,factory. GetType (), controllername)); } }}
⒂ from the above can be seen: first through the static method of Controllerbuilder Getcontrollerfactory get to achieve Icontrollerfactory interface Controllerfactory, The controller name is then obtained from the routing data in the context, and the controller that implements the IController interface is created accordingly
Controller is derived from Controllerbase, and Controllerbase implements the IController interface. Controllerbase part of the source code is as follows:
Public Abstract classcontrollerbase:icontroller{protected Virtual voidExecute (RequestContext requestcontext) {if(RequestContext = =NULL) { Throw NewArgumentNullException ("RequestContext"); } if(Requestcontext.httpcontext = =NULL) { Throw NewArgumentException (Mvcresources.controllerbase_cannotexecutewithnullhttpcontext,"RequestContext"); } verifyexecutecalledonce (); Initialize (RequestContext); using(Scopestorage.createtransientscope ()) {Executecore (); } } protected Abstract voidExecutecore (); ......}
It can be viewed as:
The Execute () method of the base class Controllerbase is executed each time the controller is called
The Execute () method also calls the abstract method of Executecore ()
Executecore () The implementation of this abstract method is defined in the controller
The Executecore () method in the controller invokes the Invokeaction () method of Actioninvoker
⒃actioninvoker Firing Action Method
The Actioninvoker implements the Iactioninvoker interface:
Public Interface iactioninvoker{ boolstring actionname);}
The default actioninvoker for MVC is controlleractioninvoker.
In the controller class, an attribute Actioninvoker of type iactioninvoker is provided, and when the Executecore () method is executed, the Actioninvoker call Invokeaction () method to fire the action. As follows:
Public classcontroller{ ...PrivateIactioninvoker _actioninvoker; Publiciactioninvoker Actioninvoker {Get { if(_actioninvoker = =NULL) {_actioninvoker=Createactioninvoker (); } return_actioninvoker; } Set{_actioninvoker=value; } } protected VirtualIactioninvoker Createactioninvoker () {return NewControlleractioninvoker (); } Public Override voidExecutecore () {actioninvoker.invokeaction (...); } .....}
Actioninvoker will need information about the Controller and action when executing the Invokeaction () method, in fact, the controller information (such as the controller's name, type, contained action, etc.) Encapsulated in the Controllerdescriptor class, action information (such as the name of the action, parameters, attributes, filters, and so on) is encapsulated in the actiondescriptor.
In addition, Actiondescriptor provides a findaction () method to find the action that needs to be executed.
⒄actioninvoker in the Execute Invokeaction () method returns ActionResult
ActionResult is an abstract class:
Public Abstract class actionresult{ publicabstractvoid Executeresult (controllercontext context);}
If the ActionResult is non-viewresult, such as Jsonresult, Contentresult, the content will be delivered directly to the response response stream and displayed to the client; Will go to the next render view link.
⒅viewengine find the view that needs to be rendered
The default is the Razor view engine and the Web Form view engine, which implements the Iviewengine interface.
Iviewengine interface Method:
Findpartialview
Findview
Releaseview
If you want to create a custom view Engine, you only need to derive from the Virtualpathproviderviewengine class.
⒆view is loaded into the webviewpage<tmodel> type and renders the generated HTML
Call Viewresult's Executeresult () method to render HTML through the iview render () method.
Public Abstract classviewresultbase:actionresult{ Public Override voidExecuteresult (ControllerContext context) {if(Context = =NULL) { Throw NewArgumentNullException ("Context"); } if(String.IsNullOrEmpty (ViewName)) {ViewName= Context. Routedata.getrequiredstring ("Action"); } viewengineresult result=NULL; if(View = =NULL) { //get to Viewengineresult through the view engine, where the template page "aspx" is loaded into the webviewpage<tmodel>result =Findview (context); View=result. View; } TextWriter writer=context. HttpContext.Response.Output; ViewContext ViewContext=Newviewcontext (context, View, ViewData, TempData, writer); View.render (ViewContext, writer); if(Result! =NULL) {result. Viewengine.releaseview (context, View); } }}
completed~~