博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
经典技术文章翻译(1):COM+集成:.NET Enterprise Services 如何帮你建立分布式应用(1)
阅读量:6350 次
发布时间:2019-06-22

本文共 9951 字,大约阅读时间需要 33 分钟。

  今天我尝试翻译一下这个非常不错文章,只为与大家分享学习.英文题目:COM+ Integration How _NET Enterprise Services Can Help You Build Distributed Applications,中文题目:COM+集成:.NET Enterprise Services 如何帮你建立分布式应用.作者简介:作者Tim Ewald: DevelopMento的首席科学家, 最近出版的 事务性COM+: 创建可伸缩的应用系统 (Addison-Wesley, 2001)的作者.(本文由FrankXu Lei亲自翻译\校订,如有错误希望指正,).另外在此表达对作者的敬意
COM+ Integration How _NET Enterprise Services Can Help You Build Distributed Applications
COM+
集成
:.NET Enterprise Services 
如何帮你建立分布式应用
作者:
Tim Ewald 
翻译:
Frank Xu Lei
本文假定你熟悉
 COM 
C++
难度
    
 1   2   3 
本文代码下载
: ComPlus.exe (41KB)
查看本文代码在
 Code Center
摘要
 .NET 
公共语言运行时
 (CLR) 
是微软下一代的组件技术。
 CLR
COM
技术的取代者, 
但是对于
 COM+
 COM+ 
现在称作
.NET Enterprise Services
,是微软为可升级的系统开发工作指定的运行时环境。

      
本文阐述了如何使用
CLR
实现和部署
COM+ 
定制的类,如何访问对象上下文环境和调用上下文环境, 
和管理环境相关的对象引用的规则。另外讨论了如何管理如数据库链接、池中的对象,
COM+ 
 
新的
.NET Remoting
架构之间的关系。
2000
7
1
 
微软正式宣布
 Microsoft® 
NET
成为 
网络为中心的新一代开发平台。
.NET
的核心就是公共语言运行时
 (CLR)
 
新一代组件技术继承自
(
且向前兼容
) COM
 
公共语言运行时在很多方面改进了
COM
 
最重要的就是使用元数据描述组件实现和其他组件依赖的所有类型。所有的类型信息都可以通过反射获得和属性扩展。 
这样就可以轻而易举创建任何开发者梦寐以求的复杂的组件, 
如自动支持对象的序列化。

      CLR
公共语言运行时是
COM
的取代者, 
但是却不是
 COM+
的取代者。
 COM+
是为对象提供一组可以方便建立分布式系统的服务的运行时环境。 
当你使用
COM
时如果你发现
COM+
有用,那么当你使用公共语言运行时的时候你同样会看到
COM+
非常有用。 
本文是关于如何使用
CLR
进行
COM+
编程的。我们先快速回顾一下
COM+
 
然后就是
.NET Enterprise Services
快速回顾
COM+
     
所有的
COM+
服务都是在上下文环境里实现的。 
上下文环境是一个提供运行时服务或者对象驻留场所的进程类的空间 
。当一个上下文环境里的对象
(
或线程
调用另外一个上下文环境里的对象, 
方法就会被截取, 
如图
1
所示。 
代理给
COM+ 
运行时预处理或迟处理请求以及执行满足对象需求的服务代码的机会, 
例如调用序列化, 
声明事物管理等。
图1 上下文环境和侦听

      COM+
提供了为需要运行时服务的类所需要的运行时服务。 如果一个类需要服务,COM+会确保实例驻留在能够提供服务的上下文环境里。例如,如果一个类使用了声明的事务,COM+确保每个实例驻留在为对象提供使用的分布式事务的上下文环境里。类是通过声明属性使用COM+运行时服务。每个服务声明用来控制自身行为的属性。
      
使用COM+运行时服务和标志了声明的属性的类称为配置类。没有使用COM+服务的类或者没标志任何声明的属性的类,称做非配置的类。 COM+在一个称做目录的元数据库存储配置类声明的属性值。 这个目录被分割在控制配置类的实例映射到进程的应用中。有两种应用程序, 库和服务应用程序。 每个配置类属于单个应用。如果一个配置类在库应用程序中, 这种类型的对象通常在客户端创建。如果配置 类在服务应用中,这个类型的对象通常在专有的代理进程dllhost.exe里创建。
      
当一个配置类被初始化, 对象的创建者必须确保新对象消亡在提供运行时服务的上下文环境里。 当一个新对象对象被创建, 对象的创建者会检查它的服务需求, 比如在类的存储在COM+ 目录里属性值。 如果对象的需求可以被创建者的上下文环境满足, 新对象就驻留在那里,调用不会被侦听。如果新对象的创建者上下文环境不能满足它需求, 新的上下文环境将创建来提供对象所需要的运行时服务。新对象 驻留在新上下文环境里,所有的调用都会被侦听以便确保对象对象访问了它所需要的服务。当配置类被初始化,对象创建者通常将新对象放在创建者的上下文环境。
 2 对象上下文环境  调用上下文环境对象
      
一个特定上下文环境里的对象也许想要与提供给它上下文环境的运行时服务交互。COM+ 为每个上下文环境建模为一个COM 对象,称作一个对象上下文环境对象 (简称对象上下文环境)。它同样为每个执行的逻辑线程(因果关系)建模为COM 对象,称作一个调用上下文环境 对象 (简称上下文环境)。任何上下文环境里执行的代码能够通过CoGetObjectContext  CoGetCallContext获得对象的引用,。(等价与Visual Basic 6.0里的 GetObjectContext and GetSecurityCallContext)。图2说明了这个架构。
CLR
实现
 COM+ 
服务类
      
COM
一样,
CLR
依赖与
COM+
提供方便开发者建立可伸缩的应用系统的运行时服务。使用
CLR 
实现
COM+ 
服务类相当容易,某些时候, 
比用
COM
实现更加高效。要知道单独通过
COM
的互操作难以实现两种技术的集成。因为当你使用
CLR 
实现使用
COM+
COM 
组件,
CLR 
COM+
的集成度已经很深, 
产生了一个更好的与其他的
CLR
技术如
Remoting
和代码访问安全集成的编程模型。
 CLR
访问
COM+
API
有命名空间
System.EnterpriseServices
类定义。
CLR 
依赖
 COM+
的类使用这些类来设置属性和与对象交互以及调用上下文环境。

      System.EnterpriseService 
里最重要的类是
ServicedComponent
 
所有使用
COM+
运行时服务的
CLR
 
必须扩展
ServicedComponent
 
如下所示:
using System.EnterpriseServices;
 
namespace ESExample
{
 public class MyCfgClass : ServicedComponent
 {
    public MyCfgClass() {}
    …
 }
}
      ServicedComponent 
出现在被继承的位置就是告诉 
公共语言运行时的对象创建者类已经被设置,这个类可能需要使用
COM+
上下文环境。 
继承自
ServicedComponent
的类必须是公开和实际的, 
必须提供缺省的公共的构造函数。
声明的属性
     
一个继承自
ServicedComponent
的服务组件类是否需要上下文环境取决于他的声明的属性。记住 
配置的服务组件类声明的属性存储在
 COM+
目录里。
使用基于
COM
的类, 
把目录和适当的信息关联的任务就是你的了。 
你既可以写脚本来访问目录也可以通过组件服务浏览管理器手动配置

      
使用基于
CLR
的组件服务类,你可以利用
CLR
固有的支持扩展元数据和直接在类的定义里嵌入相关的声明的属性。 
安装时这些信息都可以从服务组件类里萃取并被设置到
COM+
目录里。
 System.EnterpriseServices 
命名空间 
定义了一个集合的用来设置服务类
COM+
运行时需要的属性的类。 
最重要的属性类在这里
 (
还有一些其他的控制访问其他
 COM+ 
服务象队列组件
)

      
这段代码如何使用一个类属性。
using System.EnterpriseServices;
 
namespace ESExample
{
 [ Transaction(TransactionOption
。Required) ]
 public class MyTxCfgClass : ServicedComponent
 {
    public MyTxCfgClass() {}
    …
 }
}
这段代码里,
 Transaction
属性表明类
MyTxCfgClass
需要
COM+
托管的分布式事务。

      
当一个类的配置信息加到
COM+
目录里, 
这个类通常就被加到了
COM+
应用中。使用传统的基于
COM
服务类, 
没办法在代码里建立这样的关联。 
有了基于
CLR
的服务类,
 CLR
元数据的扩展性就可以提供帮助。
 System.EnterpriseServices 
命名空间定义了一组 
属性类可以描述程序里服务类属于的应用程序集。
 
列出了最重要的程序集级别的属性
 (
还有一些其他的控制访问其他
 COM+ 
服务象队列组件
)

      
下面展示了如何使用程序集属性。
using System.EnterpriseServices;
 
[assembly: ApplicationName("MyApp")]
[assembly: ApplicationActivation(ActivationOption.Library)]
 
namespace ESExample
{
 [ Transaction(TransactionOption.Required) ]
 public class MyTxCfgClass : ServicedComponent
 {
    public MyTxCfgClass() {}
    …
 }
}
      
这个例子里,
 MyTxCfgClass
被编译进标志为库应用的程序集
MyApp
里。 
如果构造函数改变了
 ApplicationActivation 
属性为
ActivationOption.Server
 
类将会被实现到服务端程序集里。 
注意到这些应用属性并没提供完全的针对所有应用的
COM+
设置。 
例如,没办法用应用属性 
定义服务应用应该运行那种安全规则。 
这样也非常的明智,因为在
CLR 
程序集元数据里里保存帐户和密码不是一个好主意。

实现接口 IObjectConstruct  IObjectControl

      
一些
 COM+ 
运行时服务, 
包括对象创建,对象池,和
just-in-time (JIT) 
激活, 
需要在使用他们的对象上调用 
标准的方法。 
特别是, 
对象创建服务调用接口
IObjectConstruct
定义的构造函数去传递构造函数字符串给每个新实例。 
对象池和
JIT
激活服务调用
Activate
Deactivate
,和
 CanBePooled IObjectControl
定义的方法去通知一个对象生命周期内的事件。 
如果你认为使用这些服务你在你的继承自
ServicedComponent
的服务类必须显示实现接口
IObjectConstruct
 IObjectControl
,事实并非如此。类
ServicedComponent 
已经提供了对方法实现,一个类可以重写即可。

      
例如,下面代码展示了一个池化的对象 
可以有选择地实现接口
IObjectControl
的方法。
namespace ESExample
{
 [ ObjectPooling(true, 5, 20) ]
 public class MyPooledCfgClass : ServicedComponent
 {
    public MyPooledCfgClass() {}
 
    // override CanBePooled so that instances can be
    // reused, use default implementations of Activate
    // and Deactivate provided by ServicedComponent
    public override bool CanBePooled() { return true; }
 }
}
在这个例子中, 
MyPooledCfgClass
设置了
ObjectPooling
属性, 
最小数目
和最大数目
20
 
类重写了方法
 CanBePooled 
和返回
 true
的实现,这样
类的实例就可以被重用。 
缺省情况下返回
false
 
意味着类的实例不可以重用。类没重写
Activate 
或者
Deactivate;
它依赖与
ServicedComponent
实现。
缺省的
 Activate
返回
successfully
 
因此允许激活继续。 
缺省的
 Deactivate
什么都没做。

      
另外要重点指出的是类
ServicedComponent 
提供接口
IObjectConstruct
 IObjectControl
的方法缺省的实现, 
实际并没。 
取而代调用你的类的内部类
(ProxyTearoff)
实现,看起来不和情理, 
但是你将很快明白这个的重要性。

ContextUtil  SecurityCallContext

      
服务类经常需要他们使用的运行时服务交互。
 COM+ 
通过截取实现了自己的服务, 
对象通过上下文和服务交互。
 System.EnterpriseServices.ContextUtil
类包装了
 CoGetObjectContext
 COM+ API 
获取对象的上下文环境。
 ContextUtil 
通过一组静态方法暴露
COM+ 
对象的上下文环境 
对象和属性列表在
 

      
的代码展示
ContextUtil
类是怎么用来操作
COM+
声明的事务
happy 
done
 
特别地, 
它设置
 ContextUtil.DeactivateOnReturn 
属性为
true
 
done
位打开表明声明的事务将会在方法结束调用以前完。 
然后设置
ContextUtil.MyTransactionVote
属性为
TransactionVote.Abort
 
关闭
happy
位表明声明的事务会终止如果一个方法没执行成功
换句话说, 
如果抛出一个异常。然后当处理了一些数据库后,方法会设置
ContextUtil.MyTransactionVote
属性为
TransactionVote.Commit
 
打开
happy
位表明
COM+
将侦听声明事务提交的组件。
      COM+
安全服务通过调用上下文环境暴露其行为,不是对象的上下文环境。
System.EnterpriseServices.SecurityCallContext 
类包装了
CoGetCallContext
 COM+ API for 
获取调用上下文环境。
SecurityCallContext
使用一组方法和属性列表
。调用上下文环境的功能。

      
这个静态属性,
 CurrentCall
,为当前的调用返回一个
SecurityCallContext
 
引用。
  
提供了
GetCallerName
方法使用
SecurityCallContext
获取当前调用者的例子。
(
注意到
 ApplicationAccessControl
属性是在库应用
MyApp 
里用来做基于角色的安全
)

编译组件服务类

      
一旦组件服务类实现完毕, 
就必须编译。编译代码相当容易, 
但是要记住两样东西,首先
COM+ 
集成组件需要编译为强名程序集。 
创建一个强名强名程序集, 
你必须使用强名工具
sn.exe
创建一个密钥。然后你就可以引用这个存储在文件里的密钥。你的组件使用一个来自于命名空间
System.Reflection
称作
AssemblyKeyFileAttribute
程序集级别的属性:
using System.EnterpriseServices;
using System.Reflection;
 
[assembly: ApplicationName("MyApp")]
[assembly: ApplicationActivation(ActivationOption。Library)]
 
// AssemblyKeyFile attribute references keyfile generated
// by sn.exe - assembly will have strong name
[assembly: AssemblyKeyFile("keyfile")]
 
namespace ESExample
{
•••
}
      
2
 
当你编译 
强名程序集, 
你必须引用
 System.EnterpriseServices 
命名空间,
 System
EnterpriseServices.dll
 
这里是创建密钥和编译组件服务类的命令
:
sn -k keyfile
csc /out:ESExample.dll /t:library
    /r:System.EnterpriseServices.dll MyCfgClass.cs

 部署组件服务类

      
当基于基于
CLR 
组件服务类编译完成,程序集就需要部署 
你可以运行服务注册工具
regsvcs.exe
。在命令行里 
如下所示:
regsvcs ESExample.dll
这个工具做了
3
个事情。 
第一,注册
CLR 
程序集为
COM 
组件
 (
如果你运行了程序集注册工具
regasm.exe)
 
第二, 
产生一个
COM
类型库文件
 (
如果你运行了程序集类型转换工具,
 tlbexp.exe) 
使用它部署你的程序集在
COM+
目录实现的服务类。
 Regsvcs.exe
缺省根据
ApplicationName 
 ApplicationActivation
属性创建目标你的程序集应用。
 (
你可以重写这些方法使用
command-line switches
第三, 
为服务类它使用
 .NET
反射
 APIs 
询问你程序集里实现的元数据且使用这些信息更新
COM+
目录,所以每个类必须有适当的属性设置
      
如果你的组件服务类没有特别声明的属性,
regsvcs.exe 
会使用缺省值。 
通常来说, 
缺省选项会关闭运行时服务。 
这样减少了过载 
确保你的服务类只加载组件显示声明需要的服务。有些环境, 
无论无何, 
regsvcs.exe 
根据属性设置获取值时。 
例如,
 MyTxCfgClass 
查看
  
既没标注
 Synchronization 
 JustInTimeActivation 
属性。 
但是因为
COM+ 
声明的事物服务依赖与这俩个服务, 
他们将可以使用当注册到
COM+
目录时。如果
MyTxCfgClass 
标记了额外的属性,他们的值必须和事务定义的值是兼容的, 
如下所示。
// all these attributes
// are compatible
[ Transaction(TransactionOption.Required) ]
[ Synchronization(SynchronizationOption.Required) ]
[ JustInTimeActivation(true) ]
public class MyTxCfgClass : ServicedComponent
{
 public MyTxCfgClass() {}
 •••
}
      
所以,这些声明的属性是使得继承自
ServicedComponent
的组件类可以用正确的信息简单的初始化
COM+
目录, 
或者有更深远的意义呢?证明了, 
托管的
 COM+ API 
服务反射不依赖
COM+
目录, 
依赖你类里声明的属性去查找你要的服务。使用这些信息来约束行为。

      
例如, 
我早先提到的
ProxyTearoff 
 
,如果你的类属性标记为
System.EnterpriseServices 
ObjectPooling
JustInTimeActivation
ProxyTearoff
仅仅向前调用你的服务组件类里实现的接口否则你的对象不会被通知, 
不管
COM+
目录怎么说。

     
某种意义上说,
COM+
目录是你组件类的声明的属性的一个视图, 
不是真正的代码
 COM+
目录里唯一的一个会变化的属性就是部署相关的,比如对象构造字符串和安全设置。 
这是一个次数签名。
 COM+
目录存在因为
COM
没有可扩展的元数据模型从二进制组件里。
 CLR
有, 
所以你可以看到一个将来版本的完全依赖
CLR
元数据和抛弃目录的
COM+
运行时服务。

      
不值得这样, 
缺省情况下你类里公共的方法不会出现在
COM+
目录里。因为他们不会出现在
regsvcs.exe
为注册生成的类型库里,这个是默认的行为当一个
CLR 
类是来自
COM
 
你可以在你自己的组件服务类里重写方法或者给你的类设置
 System.ClassInterfaceAttribute
属性。

      
除了部署一个实现了基于
CLR 
COM+
里的服务类的程序集,你必须部署它,基于
CLR
客户端才能够加载。你可以通过直接拷贝到客户端的目录下
 (
或者任何客户端配置的可以找到的目录里
)
部署你的程序集为私有的,这样就只有单个客户端可以使用。或者你可以部署为公开的程序集对机器上的所有程序公开,方式是注册到全局共享程序集缓存里
 (GAC)
 
你可以在命令行使用
GAC
工具
 gacutil.exe
,可以使用开关
-i
命令是:
gacutil -i ESExample.dll
      
如果基于
CLR 
服务类 
被部署到
COM+
服务程序,
 COM+ 
组件需要不依赖客户端程序运行的目录加载程序集。这样的情况下,你的程序集必须部署到
 GAC; 
否则, 
任何实例化组件服务类的操作都将失败。

      .NET Framework
一个目标就是通过
XCOPY
部署简化安装。
XCOPY 
借助于
MS-DOS 
命令行工具从一个地方到另外的地方拷贝文件和目录。
XCOPY
部署可以不需要执行代码在远程服务器上安装部署组件。为了支持
 XCOPY
部署,
 CLR/COM+
集成组件允许你在安装时间执行
 regsvcs.exe
和管理已经注册的基于
CLR 
组件服务类。

      
你要知道
XCOPY 
部署基于
CLR 
服务类也有缺点。首先,
 COM+
目录只能被
COM+
系统应用程序定义的具有管理员权限的用户更新。 
默认的仅仅是本地机器上的管理员。为了成功注册你的组件,基于
CLR 
服务类的代码必须具有管理员权限。不然, 
注册会失败。
 (
当然任何执行
regsvcs.exe
工具的人都具备这个权限。
)
      
2
个缺点是 
如果当你简单的拷贝程序集到合适的目录,你的组件服务类安装在
COM+ 
服务应用程序里还有额外的过要做。特别是设置
COM+
服务程序的安全策略, 
这个就是我刚提到的为什么不能使用元数据来实现的原因。如果你部署服务类在
 COM+
库服务里, 
这个就不存在问题只要你的客户端可以找到程序集。例如,假如你在利用
CLR
实现一个
ASP.NET
程序使用的组件服务类, 
你可以使用
XCOPY 
安装
COM+ 
库应用和程序集的类到
ASP.NET application's"bin 
子目录,
 ASP.NET code
代码会找到这里。
 
 本文转自 frankxulei 51CTO博客,原文链接:http://blog.51cto.com/frankxulei/321003,如需转载请自行联系原作者
你可能感兴趣的文章
(23)Spring Boot启动加载数据CommandLineRunner【从零开始学Spring Boot】
查看>>
Android ImageView加载圆形图片且同时绘制圆形图片的外部边缘边线及边框
查看>>
链表的反转
查看>>
动态从数据库获取数据(Vue.js)【数据可变】
查看>>
操作linux命令
查看>>
IOC 控制反转
查看>>
算法导论(Introduction to Algorithms )— 第十二章 二叉搜索树— 12.1 什么是二叉搜索树...
查看>>
专题开发十二:JEECG微云高速开发平台-基础用户权限
查看>>
Dubbo(二) -- Simple Monitor
查看>>
java.lang.ClassNotFoundException: org.apache.commons.lang.exception.NestableRuntimeException
查看>>
给软工大二学生:用行动開始改变
查看>>
WinForm 窗口缩放动画效果
查看>>
2015年终总结
查看>>
Java 封装 HDFS API 操作
查看>>
复习C#的方法Math.Max和Math.Min
查看>>
做中学之教与学工具箱
查看>>
vue2.0 常用的 UI 库
查看>>
Chrome内核保存为mhtml(单网页)
查看>>
SQL Server-聚焦ROW_NUMBER VS TOP N性能
查看>>
011-Shell 文件包含
查看>>