ASP.NET Web API中的Controller


虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要求它实现IHttpController接口即可,所以我们将其统称为HttpController。既然HttpController指的是所有实现了How ASP.NET Web API Works?》]

   1: public interface IHttpController
   2: {
   3:     Task ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken);
   4: }
HttpController可以视为对ASP.NET Web API的消息处理管道的延续。通过“ASP.NET Web API标准的“管道式”设计”的介绍我们知道位于管道末端的是一个HttpRoutingDispatcher对象。当SendAsync方法被执行的时候,HttpRoutingDispatcher会利用隶属于它的HttpControllerDispatcher来激活目标HttpController对象,随后调用该对象的ExecuteAsync方法并将返回的Task对象作为返回值。右图揭示了包含激活的HttpController在内的消息处理管道的结构。

一、HttpControllerContext

与HttpMessageHandler的SendAsync方法有所不同,HttpController的ExecuteAsync方法并没有一个表示请求的类型为HttpRequestMessage的参数,取而代之的是一个HttpControllerContext类型的参数。HttpControllerContext定义在命名空间“System.Web.Http.Controllers”下,表示执行HttpController的上下文。

如下面的代码片断所示,通过定义在HttpControllerContext中的属性我们可以得到用于配置消息处理管道的HttpConfiguration对象和封装路由数据的HttpRouteData对象,以及表示当前请求的HttpRequestMessage对象。这三个属性可以在构建HttpControllerContext的时候直接通过构造函数的参数指定,我们也可以先创建一个空的HttpControllerContext对象之后直接对这些属性赋值。

   1: public class HttpControllerContext
   2: {
   3:     public HttpControllerContext();
   4:     public HttpControllerContext(HttpConfiguration configuration, IHttpRouteData routeData, HttpRequestMessage request);   
   5:     
   6:     public HttpConfiguration         Configuration { get; set; }
   7:     public IHttpRouteData            RouteData { get; set; }
   8:     public HttpRequestMessage        Request { get; set; }
   9:  
  10:     public IHttpController              Controller { get; set; }
  11:     public HttpControllerDescriptor     ControllerDescriptor { get; set; }
  12: }

一个HttpControllerContext对象表示执行HttpController的上下文,我们可以通过Controller属性来获取或者设置这个HttpController对象。除此之外,我们还可以利用另一个属性ControllerDescriptor获取或者设置用于描述HttpController的HttpControllerDescriptor对象(类型HttpControllerDescriptor定义在命名空间“System.Web.Http.Controllers”下)。

当执行ApiController的ExecuteAsync方法的时候会抛出如右图所示的InvalidOperation异常,并提示“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.”错误消息已经表明了ApiController是不能“重用”的,用于处理每一个请求的ApiController都应该是“全新”的。