总体介绍ASP.NET Web API下Controller的激活与释放流程

时间:2022-03-01 12:17:46

通过《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下Controller的激活与释放流程

对于组成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&period;NET Web API下的HttpController激活:程序集的解析

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

  2. ASP&period;NET Web API下Controller激活

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

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

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

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

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

  5. How ASP&period;NET Web API 2&period;0 Works&quest;&lbrack;持续更新中…&rsqb;

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

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

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

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

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

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

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

  9. &lbrack;ASP&period;NET Web API&rsqb;如何Host定义在独立程序集中的Controller

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

随机推荐

  1. linux定时器(crontab)实例

    linux实验示例----实现每2分钟将“/etc”下面的文件打包存储到“/usr/lobal”目录下 ·Step1:编辑当前用户的crontab并保存终端输入:>crontab -u root ...

  2. php开发工具之火狐浏览器插件

    相信做开发的都有一种火狐情怀吧!  下面来介绍下一些自己在php开发工程中用到几个火狐浏览器插件. 1.[firebug]: 这个插件可以说是一个神奇,功能不用过对介绍. 2.[hostAdmin]: ...

  3. Clr Via C&num;读书笔记---I&sol;O限制的异步操作

    widows如何执行I/O操作      构造调用一个FileStream对象打开一个磁盘文件-----FileStream.Read方法从文件中读取数据(此时线程从托管代码转为本地/用户模式代码)- ...

  4. Oracle删除表、字段之前判断表、字段是否存在

    这篇文章主要介绍了Oracle删除表.字段之前判断表.字段是否存在的相关资料,需要的朋友可以参考下 在Oracle中若删除一个不存在的表,如 “DROP TABLE tableName”,则会提示: ...

  5. this&period;state&period;menuList&period;toArray&lpar;&rpar;&lbrack;0&rsqb;&period;get&lpar;&&num;39&semi;id&&num;39&semi;)

    用toArray()处理传过来的list用get(")获取里面的值 而我用的是attributes得方法

  6. myeclipse编码问题

    在中文操作系统中,Eclipse中的Java类型文件的编码的默认设置是GBK, 但是对Properties资源文件的编码的默认设置是ISO-8859-1. 所以编辑Java文件中的中文不会出现问题,但 ...

  7. Redis内存数据库快速入门

    Redis简介 Redis是一个开源(BSD许可),内存数据结构存储,用作数据库,缓存和消息代理.它支持数据结构,如 字符串,散列,列表,集合,带有范围查询的排序集,位图,超级日志,具有半径查询和流的 ...

  8. OVF3为订单原因分配成本中心时报错&OpenCurlyDoubleQuote;成本中心未定义”,消息号:VT806

    问题:OVF3为订单原因分配成本中心时报错“成本中心未定义”,消息号:VT806.KS03检查成本中心数据是已经建立的. 原因:OVF3往右边拉动,还有一个需要填入的字段“有效起始日”,此字段值必须在 ...

  9. T-Sql之集合

    1.知识点 先了解一下集合概念,集合运算(UNION(并).EXCEPT(补).INTERSECT(交))是指表之间的垂直操作.区别联接(CROSS,INNER.OUTER)是指表之间的水平操作,基础 ...

  10. java设计模式-----8、策略模式

    Strategy模式也叫策略模式是行为模式之一,它对一系列的算法加以封装,为所有算法定义一个抽象的算法接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法选择交由客户端决定(策略).S ...