ASP.NET Web API的核心对象:HttpController
ASP.NET Web API的核心对象:HttpController
对于ASP.NET Web API来说,所谓的Web API定义在继承自ApiController的类中,可能ApiController是大部分读者最为熟悉的类型了。但是我们将ASP.NET Web API下的Controller称为HttpController,它是对所有实现了接口IHttpController的所以Controller类型的统称,而ApiController仅仅视为IHttpController接口的一个实现而已,所以我们会更多地强调HttpController的概念。[本文已经同步到《How ASP.NET Web API Works?》]
目录
HttpController
HttpControllerContext
HttpControllerDescriptor
ApiController
实例演示:证明针对每次请求创建的HttpController都是“全新的”
HttpController
既然HttpController指的是所有实现了IHttpController接口的类型,我们自然得下来了解一下这个接口的定义。如下面的代码片断所示,在IHttpController接口中仅仅定义了唯一的方法ExecuteAsync方法,该方法以异步的方式执行HttpController。
public interface IHttpController
{
Task<HttpResponseMessage> ExecuteAsync( HttpControllerContext controllerContext, CancellationToken cancellationToken);
}
与我们在“消息处理管道”中介绍的HttpMessageHandler的SendAsync方法一样,该ExecuteAsync方法返回的依然是一个Task<HttpResponseMessage>对象,代表一个用于处理响应消息的Task。实际上HttpController可以视为对ASP.NET Web API的消息处理管道的延续。如右图所示,作为消息处理管道最后一个HttpMessageHandler的HttpRoutingDispatcher利用自身的HttpControllerDispatcher激活并调用ExecuteAsync方法执行目标HttpController。方法调用返回的Task<HttpResponseMessage>对象正式HttpControllerDispatcher的SendAsync方法的返回值。
与HttpMessageHandler的SendAsync方法不同之处在于:ExecuteAsync方法的参数不再是表示请求的HttpRequestMessage对象,而是一个HttpControllerContext对象。顾名思义,HttpControllerContext表示当前基于HttpController的上下文,HttpController可以认为是在该上下文中执行。
HttpControllerContext
如下面的代码片断所示,通过定义在HttpControllerContext中的属性我们可以得到用于配置消息处理管道的HttpConfiguration,封装路由数据的HttpRouteData,以及表示当前请求的HttpRequestMessage。这三个属性可以在构建HttpControllerContext的时候直接通过构造函数的参数指定,我们也可以先创建一个空的HttpControllerContext对象之后直接对这些属性赋值。
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; }
}
既然HttpControllerContext是针对HttpController的上下文,我们自然可以从中得到这个HttpController。我们除了可以通过属性Controller获取或者设置对应的HttpController之外,还可以利用另一个属性ControllerDescriptor获取或者设置用于描述HttpController的System.Web.Http.Controllers.HttpControllerDescriptor对象。
HttpControllerDescriptor
HttpControllerDescriptor封装了某个HttpController类型的元数据,可以视为对应HttpController类型的描述对象。除此之外,HttpControllerDescriptor还具有根据元数据创建对应HttpController的能力,实际上ASP.NET Web API的HttpController激活系统就是根据HttpControllerDescriptor来创建目标HttpController的。
如下面的代码片断所示,我们可以通过HttpControllerDescriptor的属性Confiruation、ControllerName和ControllerType获取当前的HttpConfiguration和被描述HttpController的名称和类型。这三个属性可以在构建HttpControllerDescriptor时通过构造函数的参数显式指定,我们可以可以先 构建一个空的HttpControllerDescriptor对象,然后手工设置这些属性。
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; }
}
我们说HttpControllerDescriptor具有根据元数据信息创建目标HttpController的能力主要体现在其CreateController方法上。实际上本章的核心内容“HttpController的激活”就体现在HttpControllerDescriptor的这个CreateController方法上,所有后续的内容基本上都是围绕着这个方法展开的。
HttpControllerDescriptor还具有一个字典类型的只读属性Properties,它使我们可以将通过指定一个字符串类型的Key将任何一个对象附加到某个HttpControllerDescriptor,然后通过这个Key人任何情况下将这个附加的对象提取出来。我们在HttpRequestMessage类型中已经看到过了类似的设计。
ApiController
我们现在来介绍一下我们创建HttpController类型默认采用的基类ApiController。如下面的代码片断所示,除了实现接口IHttpController外,HttpController还实现了接口IDisposable。如果在自定义HttpController需要实现一些资源回收的工作,可以将它们定义在重写的Dispose方法中(受保护的虚方法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; }
}
我们可以通过属性ControllerContext从ApiController对象中获取或者为它设置一个HttpControllerContext对象作为其上下文,另外三个属性Configuration、Request和RouteData与此HttpControllerContext的同名属性引用这同一个对象。
ApiController的只读属性ModelState返回一个具有字典数据结构的ModelStateDictionary对象,包含其中的数据会被以“Model绑定”的形式绑定到目标Action方法的某个参数。除此之外,ApiController的ModelState属性还用于保存参数验证失败后的 错误消息。另一个参数Url返回一个类型为UrlHelper的对象,该对象用于根据注册的HttpRoute和提供的路由变量生成相应的URL。
ApiController的User返回当前线程的Principal。相信读者还会记得在“消息处理管道”中介绍HttpServer时我们谈到:如果当前线程的Principal为Null,作为消息处理管道“龙头”的HttpServer会在SendAync方法执行过程创建一个空的GenericPrincipal对象作为当前线程的“匿名”Principal。所以对于匿名请求来说,ApiController的User属性会返回这个通过HttpServer设置的空GenericPrincipal对象。
从上面给出的代码片断我们还会看到ApiController包含一个受保护的Initialize方法,该方法根据指定的HttpControllerContext对自身作相应的初始化处理。一旦执行了Initialize方法,当前ApiController对象将处于初始化状态。在默认情况下,此Initialize会在实现的ExecuteAsync方法中被调用。
在默认情况下,ASP.NET Web API的HttpController激活系统总是创建一个新的HttpController来处理每一个请求。对于其类型继承自ApiController的HttpController来说,如果在执行ExecuteAsync方法的时候发现当前的ApiController已经处于“初始化”的状态,会直接抛出一个InvalidOperationException异常。
实例演示:证明针对每次请求创建的HttpController都是“全新的”
举个简单的例子,我们定义了如下一个继承自ApiController的类MyApiController,并通过如下的方式将原本为受保护的Initialize方法转换成一个公有方法,以方便我们后续的调用。
public class MyApiController : ApiController
{
public new void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
}
}
然后我们执行如下一段代码,它的特别指出在于:我们在调用MyApiController对象的ExecuteAsync方法之前调用了Initialize方法对其作了初始化处理。
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));
当执行ApiController的ExecuteAsync方法的时候会抛出如图4-2所示的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都应该是“全新”的。
出处:http://artech.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
ASP.NET Web API的核心对象:HttpController的更多相关文章
- Asp.net Web API 返回Json对象的两种方式
这两种方式都是以HttpResponseMessage的形式返回, 方式一:以字符串的形式 var content = new StringContent("{\"FileName ...
- ASP.NET Web API路由系统:路由系统的几个核心类型
虽然ASP.NET Web API框架采用与ASP.NET MVC框架类似的管道式设计,但是ASP.NET Web API管道的核心部分(定义在程序集System.Web.Http.dll中)已经移除 ...
- ASP.NET Web API框架揭秘:路由系统的几个核心类型
ASP.NET Web API框架揭秘:路由系统的几个核心类型 虽然ASP.NET Web API框架采用与ASP.NET MVC框架类似的管道式设计,但是ASP.NET Web API管道的核心部分 ...
- ASP.NET Web API 框架研究 核心的消息处理管道
ASP.NET Web API 的核心框架是一个由一组HttpMessageHandler有序组成的双工消息处理管道:寄宿监听到请求接受后,把消息传入该管道经过所有HttpMessageHandler ...
- HttpActionDescriptor,ASP.NET Web API又一个重要的描述对象
HttpActionDescriptor,ASP.NET Web API又一个重要的描述对象 通过前面对“HttpController的激活”的介绍我们已经知道了ASP.NET Web API通过Ht ...
- ASP.NET Web API 路由对象介绍
ASP.NET Web API 路由对象介绍 前言 在ASP.NET.ASP.NET MVC和ASP.NET Web API这些框架中都会发现有路由的身影,它们的原理都差不多,只不过在不同的环境下作了 ...
- ASP.NET Web API标准的“管道式”设计
ASP.NET Web API的核心框架是一个消息处理管道,这个管道是一组HttpMessageHandler的有序组合.这是一个双工管道,请求消息从一端流入并依次经过所有HttpMessageHan ...
- 学习ASP.NET Web API框架揭秘之“HTTP方法重写”
最近在看老A的<ASP.NET Web API 框架揭秘>,这本书对于本人现阶段来说还是比较合适的(对于调用已经较为熟悉,用其开发过项目,但未深入理解过很多内容为何可以这样“调用”).看到 ...
- ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道
Web Host 模式下的路由本质上还是通过ASP.NET 路由系统来进行路由的,只是通过继承和组合的方式对ASP.NET路由系统的内部的类进行了一些封装,产生自己专用一套类结构,功能逻辑基本都是一样 ...
随机推荐
- java学习笔记2——Eclipse的安装及汉化图解
Eclipse的安装 有了JDK,你可以编译Java源码,运行Java程序,但是还没有代码编辑器,没有版本管理工具,也不能方便的管理工程文件,不能与团队协作.安装Eclipse,你才能完成这些工作. ...
- MyReport报表引擎2.7.6.7新功能
新增二维码控件PDF417 设计器新增数据选项卡,可以拖放字段进行绑定 相关链接 MyReport演示.产品站点 相关文章 MyReport专栏
- 响应式web前端框架Foundation & Bootstrap 对比
Foundation & Bootstrap都是易用.强大且灵活的前端框架,用于构建基于任何设备上的 Web 应用.提供流式布局,及多种 js UI 组件,如导航.表单.按钮.Tabs 等等. ...
- ASP.NET MVC3中Model验证
原文:ASP.NET MVC3中Model验证 概述 上节我们学习了Model的数据在界面之间的传递,但是很多时候,我们在数据传递的时候为了确保数据的有效性,不得不给Model的相关属性做基本的数据验 ...
- 解决方案命名空间“System.Web.Mvc”中不存在类型或命名空间名称“Ajax”(是否缺少程序集引用?)
首先对System.Web.Mvc这个dll文件重新引用本地的,添加引用,搜索mvc就可以出来,选择相应的版本.如果还不能正常运行, 然后右键打开这个项目引用System.Web.Mvc, 将复制本地 ...
- 检测浏览器版本类型的JavaScript代码,终极版
下面的JavaScript代码,不仅可以判断PC端浏览器类型,还可以判断安卓.iOS.其他智能手机.平板电脑或游戏系统. 说废话貌似不是我的风格哈,直接上代码吧: var client = funct ...
- lsof基本使用
当你想在计算机上启动一个服务,电脑已经建议"port already in use",此时,可以使用lsof命令查看占用端口的进程(lsof -i:port). lsof这是LiS ...
- 干净的架构The Clean Architecture
干净的架构The Clean Architecture 这是著名软件大师Bob大叔提出的一种架构,也是当前各种语言开发架构.干净架构提出了一种单向依赖关系,从而从逻辑上形成一种向上的抽象系统. 我们经 ...
- ASP.NET中Partial Class部分类
原文:ASP.NET中Partial Class部分类 如果您在开发项目的公用函数库,用于公用函数库的内容越丰富越好,但这不可能一下子就写好,需要一点一点的积累,这时就可以使用Partial Clas ...
- CreateFont详细解释
CFont * f; f = new CFont; f->CreateFont(10, // nHeight 0, // nWidth 0, // n ...