Controller in ASP. NET Web API

Source: Internet
Author: User

Although the Visual Studio wizard in ASP. the Controller type created in the NET Web API project is derived from the default and abstract type ApiController, but ASP. NET Web API framework only requires it to implement the IHttpController interface, so we collectively call it HttpController. Since HttpController refers to all types that implement the IHttpController interface, we naturally need to first understand the definition of this interface. The following code snippet defines only the unique ExecuteAsync method in the IHttpController interface. It executes HttpController asynchronously and returns a Task <HttpResponseMessage> object. [This Article has been synchronized to How ASP. NET Web API Works?]

   IHttpController
 {
     Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken);
 }

HttpController can be regarded as a continuation of the message processing pipeline of ASP. NET Web APIs. Through the introduction of ASP. NET Web API standard "pipeline-based" design ", we know that the end of the pipeline is an HttpRoutingDispatcher object. When the SendAsync method is executed, HttpRoutingDispatcher uses HttpControllerDispatcher to activate the target HttpController object, then calls the ExecuteAsync method of the object and uses the returned Task <HttpResponseMessage> object as the return value. The right figure shows the structure of the message processing pipeline, including the activated HttpController.

Unlike the SendAsync method of HttpMessageHandler, The ExecuteAsync method of HttpController does not have a parameter indicating the request type as HttpRequestMessage, instead it is an HttpControllerContext parameter. HttpControllerContext is defined in the namespace "System. Web. Http. Controllers" to indicate the context for executing HttpController.

As shown in the following code snippet, by defining the attributes in HttpControllerContext, we can obtain the HttpConfiguration object used to configure the message processing pipeline, the HttpRouteData object used to encapsulate route data, and the HttpRequestMessage object that represents the current request. These three attributes can be directly specified by the constructor parameters when building HttpControllerContext. You can also create an empty HttpControllerContext object and assign values to these attributes directly.

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

An HttpControllerContext object indicates the context of the HttpController execution. We can use the Controller attribute to obtain or set this HttpController object. In addition, we can use another property ControllerDescriptor to obtain or set the HttpControllerDescriptor object used to describe HttpController (the type of HttpControllerDescriptor is defined in the namespace "System. Web. Http. Controllers ).

HttpControllerDescriptor encapsulates the metadata of an HttpController type. We can regard it as a description object of an HttpController type. HttpControllerDescriptor can create an HttpController Based on metadata. In fact, the HttpController activation system of ASP. NET Web API creates a target HttpController Based on HttpControllerDescriptor.

As shown in the following code snippet, you can use the attributes Configuration, ControllerName, and ControllerType of HttpControllerDescriptor to obtain the current HttpConfiguration object and the name and type of the HttpController to be described. These three attributes can be explicitly specified by the parameters of the constructor when building HttpControllerDescriptor. You can also create an empty HttpControllerDescriptor object and then manually set these attributes.

   HttpControllerDescriptor
 {   
      HttpControllerDescriptor();
      HttpControllerDescriptor(HttpConfiguration configuration,  controllerName, Type controllerType);
  
       IHttpController CreateController(HttpRequestMessage request);
  
       Collection<T> GetCustomAttributes<T>()  T: ;
       Collection<T> GetCustomAttributes<T>( inherit)  T: ;
       Collection<IFilter> GetFilters();
    
      HttpConfiguration     Configuration { get; set; }
                      ControllerName { get; set; }
      Type                  ControllerType { get; set; }
  
       ConcurrentDictionary<, > Properties { get; }
 }

HttpControllerDescriptor has the ability to create an HttpController mainly reflected in its CreateController method, which completes the activation of the target method. In other words, the target HttpController is activated by calling the CreateController method that describes its HttpControllerDescriptor object. The core of this chapter is to analyze the implementation logic of this method.

You can use the GetCustomAttributes <T> method of HttpControllerDescriptor to obtain a list of features of the specified type applied to the described HttpController type. Call another method GetFilters to obtain all the filters applied to the target HttpController type. The filters are stored in ASP. NET Web API is a very important concept and also a common extension method. We will separately introduce the Filter in Chapter 12th "Filter" in this book.

HttpControllerDescriptor also has a dictionary-type read-only attribute Properties, which allows us to attach any object to an HttpControllerDescriptor. We have seen a similar design in the HttpRequestMessage and HttpConfiguration types.

Now we will introduce how to create the default inherited base class ApiController of the HttpController type. As shown in the following code snippet, in addition to implementing the IHttpController interface, HttpController also implements the IDisposable interface in a standard way. If custom HttpController needs to implement resource recycling, it can be defined in the overwritten (protected) virtual method Dispose.

    ApiController : IHttpController, IDisposable
 {
       Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken);
        Initialize(HttpControllerContext controllerContext);
     
       Dispose();
        Dispose( disposing);
   
      HttpControllerContext     ControllerContext { get; set; }
      HttpConfiguration         Configuration { get; set; }
      HttpRequestMessage        Request { get; set; }
      IHttpRouteData            RouteData { get; set; }
  
      ModelStateDictionary     ModelState { get; }
      UrlHelper                Url { get; set; }
      IPrincipal               User { get; }
 }

The Configuration, Request, and RouteData attributes of ApiController have the same reference with the attributes of the same name as the HttpControllerContext object. The HttpControllerContext object that executes the current ApiController context can be obtained through the ControllerContext attribute, which is a read/write attribute, meaning that we can also set this attribute to specify the corresponding context. If we do not explicitly set the ControllerContext attribute, it will be automatically assigned a value when it is obtained for the first time.

The read-only attribute ModelState of ApiController returns a ModelStateDictionary object with a dictionary data structure. The data contained in the object is bound to the corresponding parameter of the target Action method in the form of "Model binding. In addition, this ModelStateDictionary is used to save the error message after the parameter verification fails. Another parameter Url returns an object of UrlHelper type (UrlHelper is defined in the namespace "System. web. http. under Routing), we can use it to generate a complete URL Based on the registered HttpRoute and provided route variables.

The User attribute of ApiController returns the Principal of the current thread. I believe that readers will remember to introduce HttpServer in Chapter 3rd "message processing pipeline": if the Principal of the current thread is Null, httpServer, as the "Leader" of the message processing pipeline, creates an empty GenericPrincipal object during the SendAsync method execution as the "anonymous" Principal of the current thread. Therefore, for anonymous requests, this User attribute returns the empty GenericPrincipal object set through HttpServer.

From the code snippet given above, we can also see that ApiController contains a protected Initialize method, which initializes itself based on the context information provided by the specified HttpControllerContext. Once the Initialize method is successfully executed, the current ApiController object will be initialized. This Initialize is automatically called in the implemented ExecuteAsync method by default. By default, the HttpController activation system of ASP. NET Web API always creates a new HttpController to process every request. For HttpController whose type is inherited from ApiController ,.

For example, we define the next DemoController type inherited from ApiController and convert the originally protected Initialize method to a public method in the following way, to facilitate subsequent calls.

   DemoController : ApiController
 {
        Initialize(HttpControllerContext controllerContext)
     {
         .Initialize(controllerContext);
     }
 }

Then we execute the following code. The special feature of this Code is that the Initialize method is called before the ExecuteAsync method of the DemoController object is called.

 DemoController controller =  DemoController ();
 HttpControllerContext controllerContext =  HttpControllerContext( HttpConfiguration(),  HttpRouteData( HttpRoute()),  HttpRequestMessage());
 controller.ControllerContext = controllerContext;
 controller.Initialize(controllerContext);
 controller.ExecuteAsync(controllerContext,  CancellationToken());

When the ExecuteAsync method of ApiController is executed, the InvalidOperation exception shown in the right figure is thrown, and the message "Cannot reuse an 'apicontroller' instance is displayed. 'apicontroller' has to be constructed per incoming message. check your custom 'ihttpcontrolleractivator' and make sure that it will not manufacture the same instance. "the error message indicates that ApiController cannot be" reused ". The ApiController used to process every request should be" brand new.

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.