ASP. NET Web API controller Execution Process (1), asp. netapi

Source: Internet
Author: User

ASP. NET Web API controller Execution Process (1), asp. netapi
ASP. NET Web APIController Execution Process(I)Preface

The previous two articles explain the process of creating a controller. They just give a brief understanding of the source code of the framework. The process executed after the controller is created is particularly important, this article briefly describes what the Controller will do after it is created.

 

ASP. NET Web API Controller Execution Process
  • ASP. NET Web APIController Execution Process (1)
  • ASP. NET Web APIController Execution Process (2)
Controller Execution Process

We know that the generation process of the controller is performed in the HttpControllerDispatcher type. If we want to know that the entry point for the Controller to perform the operation after creation must also be in the HttpControllerDispatcher type. Let's look at the following sample code:

Code 1-1

    private Task<HttpResponseMessage> SendAsyncInternal(HttpRequestMessage request, CancellationToken cancellationToken)    {        IHttpRouteData routeData = request.GetRouteData();        HttpControllerDescriptor descriptor = this.ControllerSelector.SelectController(request);             IHttpController controller = descriptor.CreateController(request);            HttpConfiguration configuration = request.GetConfiguration();        HttpControllerContext controllerContext = new HttpControllerContext(descriptor.Configuration, routeData, request) {            Controller = controller,            ControllerDescriptor = descriptor        };        return controller.ExecuteAsync(controllerContext, cancellationToken);}

If you have read the previous two articles, you will be familiar with the code here, and the Controller generation process will be included. In code 1-1, we will see the HttpControllerContext type, from the perspective of its name, we all know its role, representing the logical context Object Entering the Controller processing stage and encapsulating some important information.

 

HttpControllerContextController Context

Sample Code 1-2

    public class HttpControllerContext    {        public HttpControllerContext();        public HttpControllerContext(HttpConfiguration configuration, IHttpRouteData routeData, HttpRequestMessage request);        public HttpConfiguration Configuration { get; set; }        public IHttpController Controller { get; set; }        public HttpControllerDescriptor ControllerDescriptor { get; set; }        public HttpRequestMessage Request { get; set; }        public IHttpRouteData RouteData { get; set; }    }

Combined with code 1-2 and code 1-1, you can see the importance of the HttpConfiguration object in the HttpControllerContext type. It contains a lot of configuration information and container objects for storing infrastructure, then, the IHttpRouteData type of the route data object and the final Http request object HttpRequestMessage type object are assigned values for the Controller and ControllerDescriptor attributes of the HttpControllerContext type in code 1-1, the Controller attribute corresponds to the currently created Controller, while the ControllerDescriptor attribute represents the type of description corresponding to the Controller attribute, now let's look back at the HttpControllerContext type object to see how important it contains.

Now let's go back to code 1-1. Finally, we can see that the ExecuteAsync () method is called by the controller Variable of the IHttpController type and thus enters the controller. Generally, the controller inherits from ApiController, let's start with the ApiController type.

 

ApiControllerType

Sample Code 1-3

    public abstract class ApiController : IHttpController, IDisposable    {        public virtual 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, the ApiController is of the abstract type, and the main execution process of the controller is in the ExecuteAsync () method, the following is an example of code.

Code 1-4

    public virtual Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)    {        HttpControllerDescriptor controllerDescriptor = controllerContext.ControllerDescriptor;        ServicesContainer controllerServices = controllerDescriptor.Configuration.Services;        HttpActionDescriptor actionDescriptor = controllerServices.GetActionSelector().SelectAction(controllerContext);        HttpActionContext actionContext = new HttpActionContext(controllerContext, actionDescriptor);        FilterGrouping grouping = new FilterGrouping(actionDescriptor.GetFilterPipeline());        IEnumerable<IActionFilter> actionFilters = grouping.ActionFilters;        IEnumerable<IAuthorizationFilter> authorizationFilters = grouping.AuthorizationFilters;        IEnumerable<IExceptionFilter> exceptionFilters = grouping.ExceptionFilters;        return InvokeActionWithExceptionFilters(InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, () => actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>(delegate {            this._modelState = actionContext.ModelState;            return InvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () => controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))();        }, new CancellationToken(), false))(), actionContext, cancellationToken, exceptionFilters);   }

The execution process of the controller is defined in code 1-4. Let's take a look at the execution process of the controller from the source code perspective.

In code 1-4, the system first obtains the description object HttpControllerDescriptor type instance of the current controller type from the Controller context object, and then obtains the ServicesContainer type instance of the Service container in HttpConfiguration from the HttpControllerDescriptor type instance, I have mentioned the length of these types more or less.

After that, the IHttpActionSelector type behavior selector is obtained from the service container and the HttpActionDescriptor type that best matches is obtained through filtering. HttpControllerDescriptor has been mentioned before, and the HttpActionDescriptor here is similar to it, is the metadata information that controls the behavior (method.

 

Next I will explain the execution process of the controller behavior selector, that is, the steps of its filtering method.

First, we need to know the type of the controller behavior selector. From code 1-4, we can see that it is obtained through the extension method of the Service container object. We have discussed it in the previous sections, the type of the controller behavior selector we want to view is ApiControllerActionSelector.

 

ApiControllerActionSelectorController behavior Selector

Sample Code 1-5

    public class ApiControllerActionSelector : IHttpActionSelector    {        // Fields        private readonly object _cacheKey;        private ActionSelectorCacheItem _fastCache;        private const string ActionRouteKey = "action";        private const string ControllerRouteKey = "controller";        // Methods        public ApiControllerActionSelector();        public virtual ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor);        private ActionSelectorCacheItem GetInternalSelector(HttpControllerDescriptor controllerDescriptor);        public virtual HttpActionDescriptor SelectAction(HttpControllerContext controllerContext);        // Nested Types        private class ActionSelectorCacheItem        {        }        private class LookupAdapter : ILookup<string, HttpActionDescriptor>, IEnumerable<IGrouping<string, HttpActionDescriptor>>, IEnumerable        {        }   }

From code 1-5, we can see that the ApiControllerActionSelector type contains two private classes, which will play an important role later.

Let's go back to the logic in code 1-4 and start from calling the SelectAction () method in the Controller action selector.

 

When SelectAction () is called in the ApiControllerActionSelector type, the SelectAction () method calls the GetInternalSelector () method to generate a cache object for the Controller method, that is, the private class ActionSelectorCacheItem of the ApiControllerActionSelector, the actual filtering work is implemented by it, so the following is the focus of the introduction.

 

Controller Method Selector - Procedure

1Initialize Filter

When the ActionSelectorCacheItem type is initialized, The ActionSelectorCacheItem instance first obtains the Controller type based on the HttpControllerDescriptor object, and then obtains all the methods of the current controller type based on the condition using the reflection technique, save it as MethodInfo []. The so-called condition is (BindingFlags. Public, BindingFlags. Instance, and method must belong to the ApiController type ).

 

Let's take a look at the field information in the ActionSelectorCacheItem type. All these fields store important data, which will be described in the following sections.

Sample Code 1-6

        private readonly ReflectedHttpActionDescriptor[] _actionDescriptors;        private readonly ILookup<string, ReflectedHttpActionDescriptor> _actionNameMapping;        private readonly IDictionary<ReflectedHttpActionDescriptor, string[]> _actionParameterNames = new Dictionary<ReflectedHttpActionDescriptor, string[]>();        private readonly HttpMethod[] _cacheListVerbKinds = new HttpMethod[] { HttpMethod.Get, HttpMethod.Put, HttpMethod.Post };        private readonly ReflectedHttpActionDescriptor[][] _cacheListVerbs;        private readonly HttpControllerDescriptor _controllerDescriptor;

1.1Initialize basic information-ReflectedHttpActionDescriptor [] _ actionDescriptors

Initialization is not completed at this time. At this time, every MethodInfo instance in the MethodInfo [] array will be encapsulated into a ReflectedHttpActionDescriptor type object. After encapsulated as an object of the ReflectedHttpActionDescriptor type, each instance is saved to an array of the ReflectedHttpActionDescriptor type.

1.2Initialize basic information-IDictionary <ReflectedHttpActionDescriptor, string []> _ actionParameterNames

After 1.1 of the work is done, we will analyze each ReflectedHttpActionDescriptor type object. What is the analysis? The Parameter Name of the analysis method, and the 1: n method already exists in the IDictionary <ReflectedHttpActionDescriptor, string []> type key-value team. The value stored here is a method description object as the key value, and the value is the name of all parameters of this method.

 

1.3Initialize basic information-ILookup <string, ReflectedHttpActionDescriptor> _ actionNameMapping

The work here is to use the _ actionDescriptors variable to group based on the ActionName Result Based on 1.1. The value in the last _ actionNameMapping is also a set type, but the value in each item is 1: the key value of n. Because the Controller method may be overloaded.

 

1.4Initialize basic information-ReflectedHttpActionDescriptor [] [] _ cacheListVerbs

_ CacheListVerbs value is initialized at the end. It is defined as a two-dimensional array. The array is initially identified as three rows and N columns. The control of the three rows is controlled by the value of _ cacheListVerbKinds, here, the value of _ actionDescriptors is initialized according to the result of the 1.1 operation according to the Http method type, so I am talking about three rows and N columns.

 

Although the above steps are a bit annoying, it is easy to understand them below.

2. ActionName Filtering

Sample Code 1-7

public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)

In the SelectAction () method of the ActionSelectorCacheItem type, the following filtering steps are performed. First, the route data object is obtained from the controllerContext parameter of the method, in addition, you can check whether there is a method name value corresponding to the "Action" key in the Values attribute. The following two cases may occur.

 

2.1If Action exists in the registered routeName

In this case, the results of the above 1.3 will be taken. _ actionNameMapping obtains an array of the ReflectedHttpActionDescriptor type based on the Action name. This array cannot go down in the entire process, the filtering rule is to determine whether the Http method type supported by ReflectedHttpActionDescriptor supports the Http Method Type of the current request.

The ReflectedHttpActionDescriptor class involves handling IActionHttpMethodProvider type features. The previous figure will give you an impression.

Figure 1

2.2If there is no route nameMethod Type

In this case, the current request type is obtained according to the method parameter controllerContext of the method in code 1-7, then, the array instance of the ReflectedHttpActionDescriptor type is obtained based on the Http Method Type of the current request using the _ cacheListVerbs value in the 1.4 work result.

 

3.Match by request parameter name and quantity

 

3.1With Parameters

In this case, the Keys value in the Values attribute of the route data object is first stored in set A, and then the query string set of the current request is obtained, add all the Key values in the set to set A, so that all request parameter names are in the same set, then, according to the current ReflectedHttpActionDescriptor type instance (Next2So here is the ReflectedHttpActionDescriptorType array Traversal) Get the corresponding parameter name array from _ actionParameterNames, and then compare set A with the obtained parameter name array to see if set A contains the parameter name, if yes, the conditions are met.

 

The returned result may still be an array of the ReflectedHttpActionDescriptor type, because when a method has an overload, such as Get (string a) and Get (string a, string B, if there are two parameters a and B in the request, Get (string a) also meets the conditions.

 

3.2If no parameter exists

In this case, it is relatively simple. In the result of 1.2, as shown above, the parameter name array is retrieved Based on the ReflectedHttpActionDescriptor type instance, and the array length is 0.

 

4.ExcludeIActionMethodSelectorType features Controller Method

By the end of the filter condition, we still traverse each item in the ReflectedHttpActionDescriptor array and find whether they have implemented the IActionMethodSelector interface.

 

4.1IActionMethodSelectorInterface features

In this case, the IActionMethodSelector type is obtained and Its Implementation Method IsValidForRequest () is called. If true is returned, the ReflectedHttpActionDescriptor type can be used, this is also a convenient way for us to customize the implementation. This is usually the case below.

4.2IActionMethodSelector is not implementedInterface features

In this case, the ReflectedHttpActionDescriptor type is added to the collection of returned instances.

Finally, the Controller action selector returns only the first item in the ReflectedHttpActionDescriptor type set and must have only one item. In other cases, an exception is thrown.

At this time, I thought back to code 1-4 and saw that the type variable HttpActionDescriptor (ReflectedHttpActionDescriptor) was assigned a value. I thought back to the above process and thought it was the same for a long time.

Last, I posted a rough post.

Figure 2

 

Author: Jin Yuan

Source: http://www.cnblogs.com/jin-yuan/

The copyright of this article is shared by the author and the blog Park. You are welcome to reprint this article. However, you must keep this statement without the author's consent and go to the Article Page.


How can angularjs remotely call the aspnet web api?

Webapi is an interface that provides standard RESTAPI. JSON is returned by default. Therefore, angularjs accesses the asp.net web API just like accessing any http REST api Protocol.
 
Why is the program execution slow during the first execution of ASPnet page processing?

The first time you load the page, you need to compile the program.
 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.