通过《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. mac中显示隐藏文件

    显示隐藏文件 defaults write com.apple.finder AppleShowAllFiles -bool ture 重新隐藏 defaults write com.apple.fi ...

  2. CommonJS, AMD 和 RequireJS之间的关系(转载)

    先说说CommonJS CommonJS - 大家是不是觉得JavaScript仅仅是一个客户端的编译语言,其实JavaScript设计之初不仅仅是针对客户端设计的语言.后来只是由于Web的迅速流行, ...

  3. Arduino下LCD1602综合探究(上)——1602的两种驱动方式,如何使LCD的控制编程变得更简单

    一.前言: LCD ( Liquid Crystal Display 的简称)液晶显示器,已经逐渐替代CRT成为主流的显示设备之一,因此也成为了单片机发烧友绕不过的话题之一:而LCD1602更是很多单 ...

  4. Python 端口,IP扫描

    Python Socket函数 (1)TCP发送数据时,已建立好连接,不需要指定地址.UDP是面向无连接,每次分别指定发给谁. (2)s.bind(address) 将套接字绑定到地址,在AF_INE ...

  5. uva12063数位dp

    辣鸡军训毁我青春!!! 因为在军训,导致很长时间都只能看书yy题目,而不能溜到机房鏼题 于是在猫大的帮助下我发现这道习题是数位dp 然后想起之前讲dp的时候一直在补作业所以没怎么写,然后就试了试 果然 ...

  6. 【BZOJ3036】绿豆蛙的归宿 概率与期望

    最水的概率期望,推荐算法合集之<浅析竞赛中一类数学期望问题的解决方法> #include <iostream> #include <cstdio> using na ...

  7. CentOS搭建SVN记录

    1.安装subversion(client and server) $ yum install subversion $ yum install mod_dav_svn 安装成功之后使用 svnser ...

  8. 快速理解-Ajax

    AJAX即“Asynchronous JavaScript and XML”,意思是异步JavaScript和XML,是指一种创建交互式网页的网页开发技术. 虽然现在很少有人去自己手动写AJAX,大多 ...

  9. PHP:函数赋参数默认初值

    函数的默认参数 允许定义函数时,指定参数的默认值,如: function js_location($url, $alert='', $top=''){ if($alert=='' && ...

  10. css选择器万年不变的优先级和权重

    我们在使用CSS对网页元素定义样式时经常会遇到这种情况:要对一般元素应用一般样式,然后在更特殊的元素上覆盖它们.那么我们怎么样来保证我们所新定义的元素样式能覆盖目标元素上原有的样式呢? 在CSS中,会 ...