通过《ASP.NET Web API的Controller是如何被创建的?》我们已经对HttpController激活系统的核心对象有了深刻的了解,这些对象包括用于解析程序集和有效HttpController类型的AssembliesResolver和HttpControllerTypeResolver、根据请求完整目标HttpController选择的HttpControllerSelector、负责激活目标HttpController实例的HttpControllerActivator、以及作为IoC容器的DependencyResolver。[本文已经同步到《How ASP.NET Web API Works?》]

一、HttpController激活流程

对于组成ASP.NET Web API核心框架的消息处理管道来说,处于末端的HttpMessageHandler是一个HttpRoutingDispatcher对象。当它完成路由解析工作之后(HttpRoutingDispatcher的路由解析只发生在Self Host寄宿模式下,对于Web Host寄宿模式来说,路由解析工作是由ASP.NET路由系统来完成的),在默认情况下它会将请求传递给一个HttpControllerDispatcher对象。

HttpControllerDispatcher实现了目标HttpController对象的激活与执行,并将代表执行结果的HttpResponseMessage对象返回给HttpRoutingDispatcher对象,后者将此HttpResponseMessage回传给消息管道进行相应处理后最终完成对请求的响应。

右图所示的UML体现了激活HttpController的整个流程。当HttpControllerDispatcher接管请求之后,它会获取注册的HttpControllerSelector对象,并调用其SelectController方法得到描述目标HttpController的HttpControllerDescriptor对象。

默认注册的HttpControllerSelector是一个DefaultHttpControllerSelector对象,后者借助于注册的HttpControllerTypeResolver对象得到所有HttpController类型,进而创建一个描述这些HttpController的HttpControllerDescriptor对象与HttpController名称之间的映射关系。当它的SelectController方法被执行后,它只需要根据请求携带的HttpRouteData对象获取目标HttpController的名称,并从此映射关系中选择对应的HttpControllerDescriptor即可。

HttpControllerDispatcher接下来调用这个HttpControllerDescriptor对象的CreateController方法得到激活的HttpController对象。对于这个HttpControllerDescriptor对象来说,当它的CreateController方法被调用之后,它会获取注册的HttpControllerActivator对象,并调用其Create方法实现针对目标HttpController对象的激活并将激活的对象返回。

默认注册的DefaultHttpControllerActivator对象会利用注册的DependencyResolver根据HttpController类型去获取代表目标HttpController实例的对象。如果后者返回一个具体的HttpController对象,该对象将直接作为方法的返回值,否则DefaultHttpControllerActivator直接采用反射的形式创建目标HttpController对象并返回。

由于默认注册的DependencyResolver是一个EmptyResolver对象,由它返回的HttpController对象总是Null,所以在默认情况下激活的HttpController对象总是以反射的形式创建的。正因为如此,我们定义的HttpController类型必须具有一个默认构造函数。

二、HttpController的释放

我们知道作为自定义HttpController默认基类的ApiController类型实现了IDispoable接口,资源释放工作可以通过调用实现的Dispose方法来完成,那么这个方法是在什么时候执行的呢?除此之外,我们知道表示请求的HttpRequestMessage类型具有一个字典类型的属性Properties,我们可以利用它将任何一个对象附加到一个HttpRequestMessage对象上,如果这些附加对象需要实施资源释放操作,这些操作又是在什么时候被执行的呢?

实际上HttpRequestMessage通过Properties属性表示的属性字典为需要释放的资源预留了存储空间,对应的Key为“MS_DisposableRequestResources”,对应的值是一个List<IDisposable>的对象。我们可以调用HttpRequestMessage具有如下定义的扩展方法GetResourcesForDisposal得到这个列表,也可以调用扩展方法RegisterForDispose将一个或者多个类型实现了IDisposable接口的对象放到这个列表中。

   1: public static class HttpRequestMessageExtensions

   2: {

   3:     //其他成员

   4:     public static IEnumerable<IDisposable> GetResourcesForDisposal(this HttpRequestMessage request);

   5:  

   6:     public static void RegisterForDispose(this HttpRequestMessage request, IEnumerable<IDisposable> resources);

   7:     public static void RegisterForDispose(this HttpRequestMessage request,IDisposable resource);

   8:  

   9:     public static void DisposeRequestResources(this HttpRequestMessage request);

  10: }

ASP.NET Web API还为释放这些附加到HttpRequestMessage上的对象定义了如上一个扩展方法DisposeRequestResources,那么这个方法究竟是在什么时候被调用的呢?

释放这些资源的时机取决于采用的寄宿模式。对于Web Host来说,ASP.NET Web API用于“处理请求、回复响应”的HttpMessageHandler管道是由HttpControllerHandler创建的,后者根据当前HTTP上下文创建一个表示当前请求的HttpRequestMessage对象并传入这个管道进行处理。在整个管道完成对请求的处理并最终对请求予以响应之后,HttpControllerHandler会负责完成如下三项与资源释放有关的工作。

  • 调用HttpRequestMessage对象的扩展方法DisposeRequestResources释放附加在自身属性字典中的对象。
  • 调用HttpRequestMessage对象的Dispose方法对请求消息本身作相应的释放工作。
  • 调用返回的HttpResponseMessage对象对响应消息作相应的释放工作。

对于Self Host来说,通过《Self Host模式下的ASP. NET Web API是如何进行请求的监听与处理的?》的介绍我们知道请求的监听、接收和响应是通过HttpBinding创建的信道栈来完成的。该信道栈处理的消息类型为HttpMessage,具体代表请求消息和响应消息的HttpMessage分别是对HttpRequestMessage和HttpResponseMessage对象的封装。WCF中表示消息的Message本身就是一个需要最终被释放的对象,在针对它的处理结束之后会调用其Close或者Dispose方法对它进行资源释放的工作。

当一个HttpMessage对象的Close或者Dispose方法被调用的时侯,被其封装的HttpRequestMessage或者HttpResponseMessage会相应地得到释放。对于请求消息来说,具体的资源释放工作包括针对HttpRequestMessage自身的释放和对附加到属性字典中资源的释放。

我们不妨通过一个简单的实例来演示Self Host寄宿模式下伴随着HttpMessage对象的释放对被封装的HttpRequestMessage对象的释放。我们在一个控制台应用中定义了如下三个需要被释放的类型Foo、Bar和Baz,它们共同的基类DisposableObject实现了IDisposable接口,并在实现Dispose方法中通过输出一段文字以确定具体的释放操作是否被执行。

   1: public class DisposableObject : IDisposable

   2: {

   3:     public void Dispose()

   4:     {

   5:         Console.WriteLine("{0}.Dispose()", this.GetType().Name);

   6:     }

   7: }

   8:  

   9: public class Foo : DisposableObject

  10: {}

  11:  

  12: public class Bar : DisposableObject

  13: {}

  14:  

  15: public class Baz : DisposableObject

  16: {}

然后我们再Main方法中编写了如下一段简短的程序。我们分别创建了类型为Foo、Bar和Baz的三个对象,并通过调用扩展方法RegisterForDispose将它们注册到创建的HttpRequestMessage对象上。我们针对这个HttpRequestMessage对象利用反射的方式创建了一个HttpMessage对象,最终调用其Close方法对它作相应的释放工作。

   1: class Program

   2: {

   3:     static void Main(string[] args)

   4:     {

   5:         HttpRequestMessage request = new HttpRequestMessage();

   6:         request.RegisterForDispose(new Foo());

   7:         request.RegisterForDispose(new Bar());

   8:         request.RegisterForDispose(new Baz());

   9:  

  10:         Type httpMessageType = Type.GetType("System.Web.Http.SelfHost.Channels.HttpMessage, System.Web.Http.SelfHost");

  11:         Message httpMessage = (Message)Activator.CreateInstance(httpMessageType, new object[] { request });

  12:         httpMessage.Close();

  13:     }

  14: }

我们运行这段程序后会控制台上得到如下的输出结果,由此可见通过调用扩展方法RegisterForDispose注册到某个HttpRequestMessage对象上的资源能够在它释放的时候得到释放。(S406)

   1: Foo.Dispose()

   2: Bar.Dispose()

   3: Baz.Dispose()

对于ApiController来说,当它的ExecuteAsync方法被执行的时候,它会调用扩展方法RegisterForDispose将自己注册到代表当前请求的HttpRequestMessage对象上。毫无疑问,ApiController对象的释放会通过对这个HttpRequestMessage的释放来完成。

总体介绍ASP.NET Web API下Controller的激活与释放流程的更多相关文章

  1. ASP.NET Web API下的HttpController激活:程序集的解析

    ASP.NET Web API下的HttpController激活:程序集的解析 HttpController的激活是由处于消息处理管道尾端的HttpRoutingDispatcher来完成的,具体来 ...

  2. ASP.NET Web API下Controller激活

    一.HttpController激活流程 对于组成ASP.NET Web API核心框架的消息处理管道来说,处于末端的HttpMessageHandler是一个HttpRoutingDispatche ...

  3. 剖析Asp.Net Web API中HttpController的激活

    在Asp.Net Web API中,请求的目标是定义在某个HttpController中的某个Action方法.当请求经过Asp.Net Web API消息处理管道到达管道"龙尾" ...

  4. ASP.NET Web API的Controller是如何被创建的?

    Web API调用请求的目标是定义在某个HttpController类型中的某个Action方法,所以消息处理管道最终需要激活目标HttpController对象.调用请求的URI会携带目标HttpC ...

  5. How ASP.NET Web API 2.0 Works?[持续更新中…]

    一.概述 RESTful Web API [Web标准篇]RESTful Web API [设计篇] 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用 二.路由 ...

  6. ASP.NET Web API 路由对象介绍

    ASP.NET Web API 路由对象介绍 前言 在ASP.NET.ASP.NET MVC和ASP.NET Web API这些框架中都会发现有路由的身影,它们的原理都差不多,只不过在不同的环境下作了 ...

  7. ASP.NET Web API 开篇示例介绍

    ASP.NET Web API 开篇示例介绍 ASP.NET Web API 对于我这个初学者来说ASP.NET Web API这个框架很陌生又熟悉着. 陌生的是ASP.NET Web API是一个全 ...

  8. Self Host模式下的ASP. NET Web API是如何进行请求的监听与处理的?

    构成ASP.NET Web API核心框架的消息处理管道既不关心请求消息来源于何处,也不需要考虑响应消息归于何方.当我们采用Web Host模式将一个ASP.NET应用作为目标Web API的宿主时, ...

  9. [ASP.NET Web API]如何Host定义在独立程序集中的Controller

    通过<ASP.NET Web API的Controller是如何被创建的?>的介绍我们知道默认ASP.NET Web API在Self Host寄宿模式下用于解析程序集的Assemblie ...

随机推荐

  1. Ubuntu菜鸟入门(四)—— 搜狗输入法

    一 搜狗输入法安装 1  下载安装包:   http://pinyin.sogou.com/linux/ 2  安装安装包 (1)"GDebi",这是一个用于安装你自己手动下载包的 ...

  2. js获取css中的样式

    众所周知,obj.style只能够获取 <div id="a" style="width:100px;"></div> 结构上的样式 如 ...

  3. d3 中exit() remove()正确工作的方式

    在官网中给出的代码[1]是有问题的,如下的代码并不能正常工作: // Update… var p = d3.select("body").selectAll("p&quo ...

  4. Angular内置指令(一)

    要注意的是不要把自己开发的指令以ng开头,以免与内置指令冲突  目录:ng-disabled,ng-readonly,ng-checked,ng-selected,ng-href,ng-src,ng- ...

  5. myeclipse 无法启动

    1.对项目中的一个文件重新命名,导致卡死,结束myeclipse进程不管用,重启不管用. 删除工程下的文件  以  .markers.snap 和  marker开头的两个文件   位置: 工作空间\ ...

  6. bzoj1103树状数组水题

    (卧槽,居然规定了修改的两点直接相连,亏我想半天) 非常水的题,用dfs序(而且不用重复,应该是直接规模为n的dfs序)+树状数组可以轻松水 收获:树状数组一遍A(没啥好骄傲的,那么简单的东西) #i ...

  7. 使用canal分析binlog(一) 入门

    canal介绍 canal是应阿里巴巴存在杭州和美国的双机房部署,存在跨机房同步的业务需求而提出的.早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存在跨机房同步的业务需求.不过早期的数据库同步 ...

  8. CF-补题1

    CF-补题1 1.CodeForces 735C    题意:n个人淘汰赛,两个人可以比赛的条件是:两人打过的场数之差绝对值<2.求冠军最多可以打多少场.  总结:看了题解,转换一下思路.求n个 ...

  9. 一个简便的方法,获取某个页面元素的Xpath值

    今天了解到一个比较方便获取页面元素Xpath的方法,以下是获取步骤. 1:使用chrome浏览器打开百度:http://www.baidu.com 2:点击邮件,检查. 3:定位到某个页面的元素:点击 ...

  10. 使用git把项目提交到github

    1.需要在https://github.com/注册一个账户 2.注册成功后,新建一个repository,用来存放你要上传的项目,如下图所示 这里你需要输入你的项目的名称,可以对你的项目进行描述,如 ...