经典技术文章翻译(1):COM+集成:.NET Enterprise Services 如何帮你建立分布式应用(2)

实现客户端
      当一个基于CLR 组件服务类被编译和部署,你就需要在客户端调用它。长远来看,组件服务类没什么特别之处;事实是使用COM+ 运行时服务是不相关的。 这个代码展示了简单类早期的定义MyTxCfgClass:
using ESExample;
 
public class Client
{
 public static void Main(string[] args)
 {
    MyTxCfgClass tcc = new MyTxCfgClass();
    ... // use object as desired
 }
}
      当然,与所有的CLR代码,客户端必须引用组件服务类程序集。
csc /r:ESExample.dll Client.cs
细微的复杂性
      这里你会看到,服务类通过 .NET CLR实现COM+是相当的容易。 System.EnterpriseServices 命名空间里的类提供了可以使用COM+运行时服务的API。运行时服务本身没什么改变;他们工作的方式还是 COM+开发者熟知的。已经说了, 集成COM+CLR 没有涉及到如此细微的复杂性。 有几个问题是使得使用CLR语言写 COM+ 代码比我刚才提到的复杂的多。 有些问题会产生,因为CLR毕竟不是 COM 因为它可以做COM做不到的事情。这些问题是不能解决的你只要知道如何CLR的特性如静态方法和垃圾回收器 如何影响COM+ 编程。
      
再学习这些问题前,你必须知道CLR 的类和 and COM+ 上下文环境的关系。 首先,调用继承自ServicedComponent的类的实例都会被COM+ 上下文环境边界侦听。这些对象称为上下文环境边界。调用没继承自ServicedComponent的类的实例就不会被上下文环境边界侦听。 这些对象称为context-agileCLR对象默认就是context-agile 当你继承自ServicedComponent它们会变成context-bound (这个与 .NET remoting 上下文环境没有关系,我下面会讲到。 9说明的这个架构
经典技术文章翻译(1):COM+集成:.NET Enterprise Services 如何帮你建立分布式应用(2)
 9 上下文环境对象

     
非常有趣的是CLR 对象可以实现类似COM 对象和COM+ 上下文环境交互这样的行为。通过 COM,调用对象通常默认都会被侦听所有的对象都是context-boundCOM 对象是context-agile 只有当它聚集了freethreaded marshaler (FTM)且不是第一个在COM+ 上下文环境里 被创建的对象(因为它不是可识别的对象) 这样情况下,调用不会被侦听。 新方法确保调用真的需要的时候被预处理和迟处理的好处是减少了侦听负荷。 特别地,如果组件服务类的实例返回了一个非组件服务类的实例 (例如一个 ADO.NET DataSet 对象),这个调用不会被侦听。 并且DataSet对象不需要做任何事情,它就是照常工作。
      第二个你应该知道的事情是, 除了减少真正需要的交叉上下文侦听外, CLR/COM+集成尽可能地避免了托管类型和自有类型间的转换。 来自托管的CLR 代码到COM的调用是比较昂贵的。重要的部分就是类型的前后转换大部分在CLR stringsCOM BSTRs之间。 请求穿过COM+环境边界需要 调用一些固有的代码, 组件已经相当聪明可以避免同样来自CLR且处在同一进程里的调用者和被调用者之间的类型转换。 或许有一天所有的COM+ 运行时服务都会用CLR语言重新实现,调转就不成问题了。 那时不管如何,这个优化都会使得COM+ 侦听更加快速。
静态方法和属性
      现在你知道了CLR代码如何关联上下文环境, 思考这个问题:如果一个基于CLR 组件服务类 包括静态方法和属性访问器, 它将在什么上下文里执行呢?答案是调用者。 这个看起来不是很直观, 但是它确实很有意义当你想静态成员不是对象定义且不许要在对象驻留的上下文里访问。例如,组件服务类在 10有个静态方法,2 和静态属性,4。这个代码会在调用者的上下文里执行。 调用实例的方法1 或者属性3,通常在对象的上下文里执行。
     
这时你或许想知道当你在属性里保存了一个对象的静态引用且你想在另外一个上下问里引用会发生什么事情。基于COMCOM+编程里, 在被成为静态属性的全局变量里保存了一个原始的对象引用, 会导致严重的错误因为你不可以把对象不加包装地从原来的上下文里带走。使用基于CLR COM+ 代码, 这个就不是一个问题。 CLR 使用相当瘦的代理包装了每个组件服务类的实例子这样其它上下问的对象就不需要保留对象的直接引用。如果代码在一个保留基于CLR 组件服务类引用在静态属性的的上下文执行。它实际保留的是一个引用。如果另一个上下文里的代码要通过静态属性访问它, 特定的代理就发现变化而且封装它自己保留的引用这样侦听就触发了。这个是有个优美的解决方案,本质上你可以任何地方保存基于CLR服务类的实例并且都会正确触发。
     
管理珍贵的资源
     我现在开始另外一个管理对象引用的话题',另外一个问题你必须注意CLR靠垃圾收集器回收内存。 这是个重要的事情因为它要自动帮助避免内存泄露并且释放闲置的内存。非常不幸的是, 垃圾收集器使得内存管理变的容易,但是他同样带来了其他问题,比如管理COM+设计的对象变的困难。因此高效地管理资源是建立可伸缩的系统的关键,这正是COM+ 的设计目标,你需要知道如果合理地释放基于CLR的资源。
     
考虑 CLR类使用到了SqlConnection 对象连接数据库, 如下所示:
public void UseADatabase(void)
{
 System.Data.SqlClient.SqlConnection =
      new System.Data.SqlClient.SqlConnection(…);
    …// use connection to execute statements
}
UseADatabase方法的结束部分, SqlConnection 对象被释放。 SqlConnection对象封装了处理数据库的连接并且为了效率考虑被ADO.NET底层机制池化(Beta 1 使用COM+ 对象池; Beta 2 使用了类似COM+ 对象池的机制) 问题是 SqlConnection对象管理的连接何时归还到对象池不等垃圾收集器进入,就意识到SqlConnection 对象不在被使用,就调用终结器。finalizer 把连接归还给对象池, 然后SqlConnection对象的内存就被回收。
      
问题是数据库连接资源是非常珍贵的资源,你不能让他们无约束地飘荡在内存里,直到垃圾收集器来回收。 需要一些方法来回收这样的资源。一种方式就是强制垃圾收集器执行回收工作,如下所示:
public void UseADatabase(void)
{
 System.Data.SqlClient.SqlConnection conn =
      new System.Data.SqlClient。SqlConnection(…);
 … // use connection to execute statements
 conn = null;
 System.GC.Collect();   
}
然而,这个方法相当的笨拙且有很多潜在问题。
     更好的方法是调用SqlConnection 对象实现的接口的 IDisposable.Dispose方法。 IDisposable 接口在System命名空间,它规范拥有昂贵的要清理的资源的对象通过客户端定义操作释放资源代理垃圾收集器回收的行为。SqlConnection实现了Dispose,快速归还对象给对象池 (事实上和调用finalizer的作用一样)
      
下面代码是新版本的UseADatabase方法,它显示的清除了SqlConnection
public void UseADatabase(void)
{
 System.Data.SqlClient.SqlConnection conn =
      new System.Data.SqlClient.SqlConnection(…);
 try
 {
    … // use connection to execute statements
 }
 finally
 {
    Conn.Dispose();
 }
}
注意到Dispose出现在finally块里确保它可以执行,不管是否抛出异常。
      
那这个和COM+与服务类有什么关系呢首先,你的服务类很可能使用数据库连接和其它昂贵的资源, 所以如果你希望系统净化,你就应该知道如果合理地释放资源。 第二是, 所有基于CLR 服务类 实现了IDisposable.Dispose方法, 因为基类,ServicedComponent。你应该知道当客户端调用Dispose时发生了什么。默认实现的行为取决于你的组件服务类 使用了什么运行时服务。如果你没使用对象池激活, Dispose就会立即调用 finalizer (如果已经被垃圾收集器回收,就不会再调用)。如果你的组件服务类 使用了对象池而不是JIT 激活, Dispose调用Deactivate去通知对象已经离开它当前的上下文。然后它就调用 CanBePooled 去询问对象是否重用或销毁。 如果CanBePooled返回true 对象会返回到对象池里。 返回false 对象的finalizer就会调用 (如果已经被垃圾收集器回收,就不会再调用) 非常重要是客户端为池化的对象调用方法Dispose,如下所示。
public void UseAPooledObject(void)
{
 MyPooledCfgClass pcc = new MyPooledCfgClass();
 try
 {
    …// use pooled object to do something
 }
 finally
 {
    Pcc.Dispose();
 }
}
      如果不调用Dispose,对象 (如描述的数据库连接) 只有等到垃圾收集器回收资源。 最后, 如果你自己实现组件服务类的Dispose方法, 你必须调用基类的实现去实现这些描述的行为。
[ Synchronization(SynchronizedOption.Required) ]
public class MyCfgClass : ServicedComponent
{
 public new void Dispose()
 {
    … // do whatever
    Base.Dispose(); // call base to clean up
 }
}
    你或许想知道 JIT 激活和反激活一个对象在方法的结束。 那解决了资源的管理问题了吗?答案是否。 反激活使得对象在结束调用前释放自己成员所有的资源, 同样包括想使用相同资源的的每个方法调用。你可以通过不保存任何资源的方式达到这个目的。如果你没有选择 JIT 激活 和反激活在每次方法调用的结尾, 知道客户端调用Dispose实际上是强制你的对象重激活到饭激活并且重新终结一次。通常情况下, CLR的转换不会改变的JIT 激活规则。 应该避免使用它除非运行时服务需要它 (比如声明的服务因为它不会更高效,  比你自己管理昂贵的资源效率低。
展望
      ServicedComponent 类继承自 SystemContextBoundObject 它又继承自SystemMarshalByRefObject 这个基类可以使对象可以通过.NET remoting机制 被访问到。在Remoting顶层 上进行CLR/COM+集成有两个好处。首先你能通过Remoting层使用SOAP访问COM+ 运行时服务的远程对象。但是你不能够使用SOAP传递事务到另外的进程 (非你所愿, 但道理如此) 第二点,打开了新版的新的基于CLR Remoting上下文架构实现的COM+ 运行时服务的方式 这是现在的COM+所没有用到的。 将来一定会够发生。 真要这样,服务就可以与SOAP或者其他的传输无逢集成,并且上下文就可以真的可以扩展了。那时, 已经正确跨出一大步的CLR 就会使得COM+编程变的更加容易。
 
相关文章:
Windows XP: Make Your Components More Robust with COM+ 1.5 Innovations
House of COM: Migrating Native Code to the.NET CLR
the "samples"technologies"component服务 subdirectory of the.NET Framework SDK
事务al COM+: Building 可伸缩的应用系统 by Tim Ewald (Addison-Wesley, 2001)
作者Tim Ewald: DevelopMento的首席科学家, 最近出版的 事务性COM+: 创建可伸缩的应用系统 (Addison-Wesley 2001)的作者
翻译Frank Xu Lei:程序员,技术博客http://www.cnblogs.com/frank_xl/
来自10 2001 MSDN杂志



 本文转自 frankxulei 51CTO博客,原文链接:http://blog.51cto.com/frankxulei/321005,如需转载请自行联系原作者


上一篇:android 自定义 dialog


下一篇:如何为云原生应用带来稳定高效的部署能力?