2013年8月26日星期一

ASP.NET Web API core objects: HttpController

   

For ASP.NET Web API, the so-called Web API is defined in a class that inherits from ApiController, most readers may ApiController is the most familiar type. But we will ASP.NET Web API is called Controller under HttpController, it is all of it implements the interface IHttpController Controller type is referred to, but ApiController merely as an implementation of the interface IHttpController only, so we will put more emphasis on HttpController concept. [This article has been synchronized to " How ASP.NET Web API Works? "]

 
  

directory
HttpController
HttpControllerContext
HttpControllerDescriptor
ApiController
examples demonstrate: proof HttpController created for each request are "new"

 
 

HttpController

 

Since HttpController means all realized IHttpController type of interface, we naturally have to look down to the definition of this interface . As shown in the following code snippet in IHttpController interface defines only the only way ExecuteAsync method in an asynchronous manner HttpController.

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

with our " message processing pipeline " in introduced HttpMessageHandler the SendAsync method, the method returns ExecuteAsync is still a Task object that represents a response message for processing Task. In fact HttpController can be considered for ASP.NET Web API continuation of message processing pipeline. As shown on the right, the last one as a message processing pipeline of HttpRoutingDispatcher HttpMessageHandler activate and use their HttpControllerDispatcher call ExecuteAsync method to perform target HttpController. Method call returns an object of the Task official HttpControllerDispatcher the SendAsync method's return value.

 

HttpMessageHandler the SendAsync methods and the difference is: ExecuteAsync method parameter is no longer represents the requested HttpRequestMessage object, but a HttpControllerContext object. As the name implies, HttpControllerContext represents the current context based HttpController, HttpController may be considered in this context.

 

HttpControllerContext

 

as shown in the following code fragment, by defining the attributes in HttpControllerContext we can get used to configure the message processing pipeline HttpConfiguration, encapsulated routing data HttpRouteData, and represents the current request HttpRequestMessage. These three properties can be built in HttpControllerContext time directly through the constructor parameter to specify, we can first create an empty HttpControllerContext object directly after the assignment of these attributes.

 
public class HttpControllerContext 
{
public HttpControllerContext();
public HttpControllerContext(HttpConfiguration configuration, IHttpRouteData routeData,HttpRequestMessage request);

public HttpConfiguration Configuration { get; set; }
public IHttpRouteData RouteData { get; set; }
public HttpRequestMessage Request { get; set; }

public IHttpController Controller { get; set; }
public HttpControllerDescriptor ControllerDescriptor { get; set; }
}
   

Since HttpControllerContext for HttpController context, we naturally can gain this HttpController. In addition we can attribute Controller Gets or sets the corresponding HttpController, you can also take advantage of another property ControllerDescriptor Gets or sets the object used to describe HttpController of System.Web.Http.Controllers.HttpControllerDescriptor.

 

HttpControllerDescriptor

 

HttpControllerDescriptor encapsulates a HttpController types of metadata can be regarded as a description of the corresponding type of object HttpController. In addition, HttpControllerDescriptor also has a corresponding HttpController based metadata creation ability, in fact, ASP.NET Web API's HttpController activation system is based on the HttpControllerDescriptor to create the target HttpController's.

 

as shown in the following code snippet, we can HttpControllerDescriptor properties Confiruation, ControllerName and ControllerType get the current HttpConfiguration and described HttpController name and type. These three properties can be constructed HttpControllerDescriptor through the constructor argument explicitly specified, we can construct an empty can first HttpControllerDescriptor object, and then manually set these properties.

 
public class HttpControllerDescriptor 
{
public HttpControllerDescriptor();
public HttpControllerDescriptor(HttpConfiguration configuration, string controllerName, Type controllerType);

public virtual IHttpController CreateController(HttpRequestMessage request);

public virtual Collection<T> GetCustomAttributes<T>() where T: class;
public virtual Collection<T> GetCustomAttributes<T>(bool inherit) where T: class;
public virtual Collection<IFilter> GetFilters();

public HttpConfiguration Configuration { get; set; }
public string ControllerName { get; set; }
public Type ControllerType { get; set; }

public virtual ConcurrentDictionary<object, object> Properties { get; }
}
   

we say HttpControllerDescriptor with metadata information according to the ability to create the target HttpController mainly reflected in its CreateController methods. In fact, the core of this chapter, "HttpController activation" is reflected in HttpControllerDescriptor this CreateController methods, all subsequent content basically unfolded around this way.

 

HttpControllerDescriptor dictionary type also has a read-only attribute Properties, which allows us to specify a string through the Key to any one type of object attached to a HttpControllerDescriptor, then this Key people no circumstances will this additional extracted object. We have already seen in HttpRequestMessage type over a similar design.

 

ApiController

 

We now introduce our HttpController type defaults to create a base class ApiController. As shown in the following code fragment, in addition to implementing the interface IHttpController outside, HttpController also implements the interface IDisposable. If you need to implement some custom HttpController recycling work, they can be defined in the overridden Dispose method (protected virtual method Dispose).

 
public abstract class ApiController : IHttpController, IDisposable 
{
public virtual Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken);
protected virtual void Initialize(HttpControllerContext controllerContext);

public void Dispose();
protected virtual void Dispose(bool disposing);

public HttpControllerContext ControllerContext { get; set; }
public HttpConfiguration Configuration { get; set; }
public HttpRequestMessage Request { get; set; }
public IHttpRouteData RouteData { get; set; }

public ModelStateDictionary ModelState { get; }
public UrlHelper Url { get; set; }
public IPrincipal User { get; }
}
   

we can attribute ControllerContext object from ApiController get or set it to a HttpControllerContext object as its context, the other three properties Configuration, Request and RouteData with this HttpControllerContext the same name attribute references this same object.

 

ApiController ModelState returns a read-only attribute with dictionary data structure ModelStateDictionary object that contains the data would be to "Model Binding" in the form bound to a target Action method parameters. In addition, ApiController the ModelState property is also used to store parameter validation fails with an error message. Another parameter Url return a type UrlHelper the object, which is used to provide under the registered HttpRoute and routing variables generates the corresponding URL.

 

ApiController the User returns the current thread's Principal. I believe that readers will remember the "message processing pipeline" introduces HttpServer when we talked about: If the current thread's Principal is Null, as a message processing pipeline "leading" the HttpServer implementation process in SendAync method to create an empty object as the current GenericPrincipal thread of the "anonymous" Principal. So for anonymous requests it, ApiController User property will return the empty set through HttpServer GenericPrincipal object.

 

from above code snippet we will see ApiController contains a protected Initialize method, the method according to the specified HttpControllerContext their own initialization process accordingly. Once you execute the Initialize method, the object will be in the current ApiController initialization state. By default, this will be achieved ExecuteAsync Initialize method is called.

 

By default, ASP.NET Web API's HttpController activation system always creates a new HttpController to deal with every request. For its type inherits from ApiController of HttpController, if the implementation of the method, it was found ExecuteAsync current ApiController already in the "initialization" state, will have a direct throw an InvalidOperationException exception.

 

example demonstrates: Prove HttpController created for each request are "new"

 

cite a simple example, we define as a class that inherits from ApiController MyApiController, and through the following manner originally protected Initialize method to convert a public method to facilitate our follow-up calls.

 
public class MyApiController : ApiController 
{
public new void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
}
}
   

Then we execute the following piece of code, it is particularly pointed out that: We call MyApiController object ExecuteAsync method before calling the Initialize method made its initialization process.

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

 
    
 

 

When performing ApiController of ExecuteAsync method shown in Figure 4-2 will be thrown when the InvalidOperation, and prompts: "Cannot reuse an 'ApiController' instance. 'ApiController' has to be constructed per incoming message. Check your custom 'IHttpControllerActivator' and make sure that it will not manufacture the same instance. "error message has shown ApiController be able" reuse ", and to process each request ApiController should be" new '.

没有评论:

发表评论