ASP. NET Web API
Controller Execution Process
(
a
)
Preface
The previous two explained the creation process of the controller, just from the perspective of the framework source code to understand, in the controller after the implementation of the process is also particularly important, this article to explain briefly what the controller will do after the creation of the work.
ASP. NET Web API
Controller Execution Process
- ASP. NET Web API controller Execution Process ( i)
- ASP. NET Web API controller Execution Process ( II)
Controller Execution Process
We know that the controller generation process is operating in the Httpcontrollerdispatcher type, and we want to know that the entry point for the controller to perform operations after creation must also be found in the Httpcontrollerdispatcher type. Consider the following sample code:
Code 1-1
PrivateTasksendasyncinternal (httprequestmessage request, CancellationToken CancellationToken) {ihttproutedata routeDa Ta=request. Getroutedata (); Httpcontrollerdescriptor Descriptor= This. Controllerselector.selectcontroller (Request); Ihttpcontroller Controller=Descriptor. Createcontroller (Request); Httpconfiguration Configuration=request. GetConfiguration (); Httpcontrollercontext ControllerContext=NewHttpcontrollercontext (Descriptor. Configuration, Routedata, request) {Controller=Controller, Controllerdescriptor=descriptor}; returnController. Executeasync (ControllerContext, CancellationToken);}
See the previous two friends see the code here will be very familiar with, the controller's generation process is included in it, in code 1-1 we will see the Httpcontrollercontext type, from its name it must be known to everyone also know its role, Represents the logical context object that enters the controller processing phase and encapsulates some very important information.
Httpcontrollercontext Controller Context
Example code 1-2
Public classHttpcontrollercontext { PublicHttpcontrollercontext (); PublicHttpcontrollercontext (httpconfiguration configuration, Ihttproutedata Routedata, httprequestmessage request); PublicHttpconfiguration Configuration {Get;Set; } PublicIhttpcontroller Controller {Get;Set; } PublicHttpcontrollerdescriptor Controllerdescriptor {Get;Set; } PublicHttprequestmessage Request {Get;Set; } PublicIhttproutedata Routedata {Get;Set; } }
In combination with code 1-2 and code 1-1 you can see the object of type httpconfiguration in the Httpcontrollercontext type, it is not important to say, it contains a lot of configuration information and storage infrastructure container objects, Then is the routing data Object Ihttproutedata type, and the last HTTP Request object Httprequestmessage type Object, and the controller and Controllerdescriptor properties in the Httpcontrollercontext type are assigned in code 1-1, which corresponds to the controllers that are currently being created. While the Controllerdescriptor property is the description type that represents the Controller property, it is important to look back at the object of the Httpcontrollercontext type and see what it contains.
Now we go back to code 1-1, and finally we see that the variable controller called by the Ihttpcontroller type Executeasync () method into the controller, the general controller is inherited from Apicontroller, Let's start with the Apicontroller type.
Apicontroller type
Example code 1-3
Public Abstract class Apicontroller:ihttpcontroller, IDisposable { publicvirtual task<system.net.http.httpresponsemessage> Executeasync ( Httpcontrollercontext ControllerContext, CancellationToken cancellationtoken); }
In code 1-3 we can see that the Executeasync () method is defined in the Apicontroller type, Apicontroller is the abstract type, and the main execution of the controller is in the Executeasync () method, Let me take a look at the specific implementation, the following example code.
Code 1-4
Public VirtualTaskExecuteasync (Httpcontrollercontext controllercontext, CancellationToken cancellationtoken) {HttpController Descriptor Controllerdescriptor=Controllercontext.controllerdescriptor; Servicescontainer controllerservices=controllerDescriptor.Configuration.Services; Httpactiondescriptor Actiondescriptor=Controllerservices.getactionselector (). SelectAction (ControllerContext); Httpactioncontext Actioncontext=NewHttpactioncontext (ControllerContext, actiondescriptor); Filtergrouping Grouping=Newfiltergrouping (Actiondescriptor.getfilterpipeline ()); IEnumerable<IActionFilter> actionfilters =grouping. Actionfilters; IEnumerable<IAuthorizationFilter> authorizationfilters =grouping. Authorizationfilters; IEnumerable<IExceptionFilter> exceptionfilters =grouping. Exceptionfilters; returnInvokeactionwithexceptionfilters (Invokeactionwithauthorizationfilters (Actioncontext, CancellationToken, Authorizationfilters, () = ActionDescriptor.ActionBinding.ExecuteBindingAsync (Actioncontext, CancellationToken ). ThenDelegate { This. _modelstate =actioncontext.modelstate; returnInvokeactionwithactionfilters (Actioncontext, CancellationToken, actionfilters, () =Controllerservices.getactioninvoker (). Invokeactionasync (Actioncontext, CancellationToken)) (); }, NewCancellationToken (),false) ) (), Actioncontext, CancellationToken, exceptionfilters); }
Code 1-4 defines the implementation process of the controller, we will learn from the source point of view of the controller's execution process.
In code 1-4, we first get an instance of the Description object Httpcontrollerdescriptor type of the current controller type from the controller context object. Then from the Httpcontrollerdescriptor type instance from the instance of the service container Servicescontainer type that gets in Httpconfiguration, the space before these types is more or less spoken.
After this, get the Ihttpactionselector type's behavior selector from the service container and filter to get the Httpactiondescriptor type of the best match, as mentioned before Httpcontrollerdescriptor, The httpactiondescriptor here is similar to the meta-data information that represents the control of its behavior (method).
Let me explain the execution process of the controller behavior selector, which is a few steps of the filter method.
First of all we need to know the type of controller behavior selector, from code 1-4 can be seen through the Service container object extension method to get, in the previous space has been discussed, Here we can see that the type of controller behavior selector We are looking at is the Apicontrolleractionselector type.
Apicontrolleractionselector Controller Behavior Selector
Example code 1-5
Public classApicontrolleractionselector:ihttpactionselector {// Fields Private ReadOnly Object_cachekey; PrivateActionselectorcacheitem _fastcache; Private Const stringActionroutekey ="Action"; Private Const stringControllerroutekey ="Controller"; //Methods PublicApicontrolleractionselector (); Public Virtualilookup<string, httpactiondescriptor>getactionmapping (Httpcontrollerdescriptor controllerdescriptor); Privateactionselectorcacheitem getinternalselector (Httpcontrollerdescriptor controllerdescriptor); Public Virtualhttpactiondescriptor selectaction (Httpcontrollercontext controllercontext); //Nested Types Private classActionselectorcacheitem {}Private classlookupadapter:ilookup<string, Httpactiondescriptor>, ienumerable<igrouping<string, httpactiondescriptor>>, IEnumerable {}}
From code 1-5, we can see that the Apicontrolleractionselector type contains two private classes, which are also important after the two private classes.
Let's go back to the logic in code 1-4 and start by calling the SelectAction () method from the call controller behavior selector.
When you call SelectAction () in a apicontrolleractionselector type, the Getinternalselector () method is actually called by the SelectAction () method to generate a cache object for the Controller method. That is, the Apicontrolleractionselector type of private class Actionselectorcacheitem, and the real filtering work is done by it, so the following is the focus of the introduction.
Controller Method Selector
-
steps for filtering methods
1 Initialize Filter
At the time of initialization of the Actionselectorcacheitem type, the Actionselectorcacheitem instance first gets the type of the controller itself according to the Httpcontrollerdescriptor object. It then uses the technique of reflection to obtain all the methods in the current controller type according to the conditions, and finally save as methodinfo[]. The so-called condition is that (BindingFlags.Public, bindingflags.instance, method-owning type must be of type Apicontroller).
Let's take a look at the field information in the Actionselectorcacheitem type, which contains important data, which is explained later.
Example code 1-6
Private ReadOnlyreflectedhttpactiondescriptor[] _actiondescriptors; Private ReadOnlyilookup<string, reflectedhttpactiondescriptor>_actionnamemapping; Private ReadOnlyIdictionary<reflectedhttpactiondescriptor,string[]> _actionparameternames =NewDictionary<reflectedhttpactiondescriptor,string[]>(); Private ReadOnlyhttpmethod[] _cachelistverbkinds =Newhttpmethod[] {httpmethod.get, httpmethod.put, httpmethod.post}; Private ReadOnlyreflectedhttpactiondescriptor[][] _cachelistverbs; Private ReadOnlyHttpcontrollerdescriptor _controllerdescriptor;
1.1 basic information Initialization-reflectedhttpactiondescriptor[] _actiondescriptors
At this point the initialization is not done, and each MethodInfo instance in the methodinfo[] array is encapsulated into an object of type Reflectedhttpactiondescriptor, which is later on for the type. After encapsulating an object of type Reflectedhttpactiondescriptor, each instance is also stored in an array of type Reflectedhttpactiondescriptor.
1.2 basic information Initialization-Idictionary<reflectedhttpactiondescriptor, string[]> _actionparameternames
After 1.1 of the work is done, the object of each reflectedhttpactiondescriptor type is analyzed and analyzed. The parameter name of the parsing method, and the way that has been 1:n exists idictionary<reflectedhttpactiondescriptor, string[]> the type of key value in the team. The value stored here is a method that describes the object as the key value, and the value is the name of all the parameters for this method.
1.3 basic information Initialization-ilookup<string, reflectedhttpactiondescriptor> _actionnamemapping
The work here is based on the results of the 1.1 work, using the _actiondescriptors variable to group according to ActionName, and the value in the last _actionnamemapping is the collection type, but the value in each item is a 1:N key-value team value. Because the controller method may have overloaded conditions.
1.4 basic information Initialization-reflectedhttpactiondescriptor[][] _cachelistverbs
Initialization of the _cachelistverbs value at the end, it is defined as a two-dimensional array, the array is initially determined to be three rows n columns, three rows of control is controlled by the _cachelistverbkinds value, here is initialized according to the results of 1.1 work will _ The actiondescriptors value is categorized by the HTTP method type, so I'm talking about three rows n columns.
The above steps are a bit annoying, but it's easy to understand the following.
2. Action name filtering
Example code 1-7
Public Httpactiondescriptor selectaction (Httpcontrollercontext controllercontext)
In the SelectAction () method of the Actionselectorcacheitem type, there will be a few remaining filtering steps, starting with a route data object obtained from the parameter ControllerContext of the method. And in its values property to query for the "Action" key corresponding to the method name value, this time there will be the following two cases.
2.1 If there is an action in the registered route name
This situation will bring the work of the above 1.3, _actionnamemapping according to the action name to a reflectedhttpactiondescriptor type of array, this array in the entire process can not go down, Also filtered, the rule for filtering is to determine whether the HTTP method type supported in Reflectedhttpactiondescriptor supports the HTTP method type of the current request.
This involves handling the Iactionhttpmethodprovider type characteristics within the Reflectedhttpactiondescriptor type, not to mention the following article. Let's make an impression on the last picture here.
Figure 1
2.2 There is no route name based on the HTTP Method Type
In this case, the current request type is obtained according to the method parameter ControllerContext of the method in code 1-7, and then from the 1.4 work result in _ The Cachelistverbs value gets an array instance of the Reflectedhttpactiondescriptor type based on the HTTP method type of the current request.
3. Match According to the request parameter name, quantity
3.1 in case of a parameter
In this case, the keys in the values property of the routing data object are stored in a collection A, and then the collection of query strings for the current request is obtained, and all the key values in the collection are added to the collection A, which causes all the requested parameter names to be in a single collection. Then it will be based on the current instance of the Reflectedhttpactiondescriptor type from the 1.2 result ( This is the next 2 process, So here is the array traversal of the Reflectedhttpactiondescriptor type, which gets the corresponding array of parameter names from _actionparameternames, Then the collection a will and get the array of parameter names to do a one by one comparison, to see if the collection A contains the parameter name, if all have the condition is satisfied.
It is still possible to return an array of type reflectedhttpactiondescriptor, because when a method has overloads, such as Get (string a) and get (string a,string B) two methods, If there are two parameters of A and B in the request, Get (string a) also satisfies the condition.
3.2 with no parameters
In this case it is relatively simple, from the results of 1.2, as described above, the traversal based on the Reflectedhttpactiondescriptor type instance gets the parameter name array, found the array length of 0.
4. Controller method to exclude iactionmethodselector type characteristics
To the last filter, or iterate through each item in the Reflectedhttpactiondescriptor type array, and find out if they have an attribute that implements the Iactionmethodselector interface.
4.1 There is a use for implementing Iactionmethodselector features of the interface
In this case, the Iactionmethodselector type is obtained, and its implementation method Isvalidforrequest () is called, This reflectedhttpactiondescriptor type can only be used if it returns True, which is also a handy way to give us a custom implementation, which is typically the case below.
4.2 does not use implementation Iactionmethodselector features of the interface
In this case, the Reflectedhttpactiondescriptor type is added to the collection that returns the instance.
The last controller behavior selector returns only the first item in the Reflectedhttpactiondescriptor type collection and must be only one, and the exception is thrown in all other cases.
This time the mind back to code 1-4, see Httpactiondescriptor (reflectedhttpactiondescriptor) type variable is assigned value, recall the process above, feel a long time.
Finally, it's a rough patch.
Figure 2
Jinyuan
Source: http://www.cnblogs.com/jin-yuan/
This article is copyrighted by the author and the blog Park, welcome reprint, but without the consent of the author must retain this statement, and on the article page
ASP. NET Web API Controller execution Process (i)