您的位置:首页 > 其它

在 .NET 中使用 COM+ 服务

2007-07-19 12:10 225 查看
在.NET中使用COM+服务

升级到Microsoft.NET
TimMcCarthy-InterKnowlogy
PaulD.Sheriff-PDSA,Inc.
2002年2月
摘要:将新的Microsoft.NET组件添加到现有的COM和COM+应用程序中,它们将协同工作;如果您需要开发能够参与事务、利用基于角色的安全性或者与队列交互的.NET应用程序,这样做对您很有帮助。
目标

学习在Microsoft®.NET中使用COM+服务。

创建被服务的组件。

部署被服务的组件。

前提条件
要彻底理解本文内容,需要满足以下条件:

曾经使用过MicrosoftTransactionServer(MTS)并在MicrosoftVisualBasic®6.0中分发过事务。

曾经使用过COM+服务中的基于角色的安全性。

曾经在COM+服务中创建和使用过队列。

非常熟悉.NET类。

能够在.NET中熟练创建控制台应用程序。

目录

在.NET中使用COM+服务

开发基于事务的组件

基于角色的安全性

使用排队组件

自VisualBasic6.0以来COM+的变化

总结

在.NET中使用COM+服务
您可能曾经使用COM+应用程序来托管使用VisualBasic或C++编写的组件。COM+提供了许多有价值的服务,例如事务处理、排队组件、实时激活、基于角色的安全性、共享属性等。使用COM+托管组件的一个主要优点在于:不必编写任何代码,就可以更改组件的行为方式,例如将组件的事务支持设置为“需要”。通过在组件服务MMC管理单元中,在COM+组件上设置单选按钮,每次创建组件时,都将在COM+事务的上下文中创建相应的组件。当组件使用COM+事务时,所有数据库事务都由分布式事务处理协调器(DTC)处理。图1显示了在组件服务界面中设置“需要”事务选项的一个示例。
图1:需要事务的COM+组件示例
设置组件安全性与设置事务支持一样简单。使用COM+服务管理单元,您不用重新编译代码就可以决定哪个用户可以运行哪个组件,甚至哪个方法。
.NET可以使用所有COM+服务
在.NET框架中,只要您的类是从System.EnterpriseServices.ServicedComponent类派生的,就可以继续使用COM+提供的所有服务。任何从ServicedComponent类派生的类都由COM+服务托管,并且可以使用所有可用的COM+服务。表1列出了.NET中支持的全部COM+服务以及每个服务的简短说明。
表1:可用的COM+服务
COM+服务
说明
自动事务处理
应用声明事务处理功能
COM事务处理集成器(COMTI)
将CICS和IMS应用程序封装到自动化对象中
补偿资源管理器(CRM)
对非事务性资源应用原子性和持久性属性
实时激活
通过方法调用激活对象,并在调用返回时停用此对象
松散耦合的事件
管理基于对象的事件
对象构造
在构造实例时向类实例传递持久字符串值
对象池
提供现成对象的池
排队组件
提供异步消息队列
基于角色的安全性
基于角色应用安全权限
共享属性
在服务器进程中的多个对象之间共享状态
同步(活动)
管理并发
XA互操作性
支持X/Open事务处理模型
在.NET中使用COM+服务的原因
如果要编写能够参与事务、利用基于角色的安全性或者与队列交互作用的.NET应用程序,就会用到.NET中提供的COM+服务。正如您将在本文中了解到的,.NET使这些服务很容易实现。
提示:如果.NET代码无需与COM+服务一起工作,也就是说,您只在.NET框架中工作,那么请不要使用System.EnterpriseServices,否则会造成性能下降。
COM+组件开发概述
在.NET中创建与COM+服务交互的组件时,需要执行以下步骤。表2包含对各个步骤的说明。
1.创建类库。
2.创建所有类,使它们继承System.EnterpriseServices.ServicedComponents类。
3.创建程序集。
4.创建强名称。
表2:创建.NET组件时使用的术语定义
术语
说明
类库
包含类的.dll项目类型,此类项目通常没有用户界面
System.EnterpriseServices.ServicedComponents
.NET框架中的一个类,使用它才能与COM+服务进行交互
程序集
对项目中所有类和接口的描述
强名称
从程序集生成GUID,以便可以使用COM+服务注册组件
开发基于事务的组件
在本文的第一部分,您将学习如何创建使用COM+的事务性服务的.NET组件,还将学习如何编写组件以及与此组件交互的前端应用程序。
创建COM+事务组件
要使.NET组件能够在COM+服务下运行,需要执行以下步骤。首先,必须创建一个从System.EnterpriseServices.ServicedComponent类派生的类。这个基类提供了与COM+服务交互所需的所有适当方法和属性。需要将该类标记为需要新事务,并将所创建的任何方法标记为在没有错误出现的情况下可以自动完成事务处理。下面是具体操作。
1.打开MicrosoftVisualStudio®.NET,创建一个新的ClassLibrary类型的项目。
2.将Class1.vb文件重命名为COMPlusServices.vb。
3.打开COMPlusServices.vb文件,将类名Class1更改为COMPlusServices
4.在此新类中键入如下所示的代码:
5.ImportsSystem.EnterpriseServices

6.ImportsSystem.Reflection

7.

8.'********************************************

9.'COM+注册详细信息

10.

11.'提供COM+应用程序名

12.<Assembly:ApplicationNameAttribute("ComPlusExample")>

13.

14.'提供具有强名称的程序集

15.<Assembly:_

16.AssemblyKeyFileAttribute("bin/ComPlusExample.snk")>

17.'********************************************

18.

19.<TransactionAttribute(TransactionOption.Required)>_

20.PublicClassCOMPlusServices

21.InheritsServicedComponent

22.

23.PublicSubNew()

24.MyBase.New()

25.EndSub

26.

27.<AutoComplete()>PublicFunctionDoTransaction()_

28.AsString

29.Return"COM+成功"

30.EndFunction

EndClass

此代码以导入多个名称空间开始,从而在声明组件时省略了一些键入内容。
31.接下来是COM+注册详细信息。请输入以下代码行:
32.'提供COM+应用程序名

<Assembly:ApplicationNameAttribute("ComPlusExample")>

此行指定ApplicationNameAttribute的值为ComPlusExample。这是在COM+目录中注册该COM+应用程序时要使用的名称。第一次调用此组件后,当打开MMC管理单元的COM+应用程序文件夹时,您会发现应用程序名称就是这个名称。
接下来的代码声明AssemblyKeyFileAttribute属性:
<Assembly:_

AssemblyKeyFileAttribute("bin/ComPlusExample.snk")>

此属性通知COM+目录有关强名称的信息所在的位置。在后面的步骤中,将创建用于描述COM+组件的.SNK文件。
最后,使用以下代码声明类名COMPlusServices:
<TransactionAttribute(TransactionOption.Required)>_

PublicPublicClassCOMPlusServices

此类名前面的属性通知COM+,您要将事务属性设置为“需要”。添加此行代码相当于打开COM+应用程序管理单元(如图1所示)并手动设置此属性。
该类中的下一行代码继承System.EnterpriseServices名称空间中的ServicedComponent。
InheritsServicedComponent

如果不包含此行,将无法使此组件在COM+下运行。
添加事务方法
现在,类已经设置完毕,可以创建真正能够实现某些功能的方法了。在您编写的代码中,DoTransaction函数返回一个字符串值,但它只给出了您必须使用的语法,如果不使用此语法该方法将无法参与事务。
<AutoComplete()>PublicFunctionDoTransaction()AsString

Return"COM+成功"

EndFunction

在此方法前面加上<AutoComplete()>属性很重要。这表示只要此方法中没有出现异常,当它结束时就会自动调用SetComplete。如果该方法中存在异常,则.NET运行时将自动调用SetAbort方法。这与在VisualBasic6.0中编写COM组件不同,在VisualBasic6.0中,必须手动显式调用SetComplete和SetAbort。
创建强名称
在编译组件之前,您需要为此组件的程序集指定一个强名称。如果不指定,COM+目录将不能识别该组件,也就无法注册它。实际上,您已经通过前面使用的AssemblyKeyFile属性指定了强名称,现在需要使用强名称工具(Sn.exe)创建强名称并使GUID与程序集关联。
1.打开命令提示。
2.要创建强名称,请在命令提示下键入以下代码,然后按Enter键。
sn-kComPlusExample.snk

3.将ComPlusExample.snk文件从硬盘驱动器的根目录(通常为C:/)复制到项目所在文件夹的bin目录下。
现在,需要编译此程序,使它能生成在COM+注册此组件必需的文件。在VisualStudio.NET中,在Build(生成)菜单上,单击Build(生成)。
生成客户端测试应用程序
现在,组件生成完毕,需要生成客户端应用程序来调用并测试此组件。创建简单的控制台应用程序,此程序中的模块文件的Main方法创建新组件实例,并调用DoTransaction()方法。以下是主要步骤:
1.在VisualBasic.NET中,创建新的控制台应用程序项目。
2.添加对刚创建的组件的引用。
3.键入如下所示的代码。
4.ModulemodMain

5.SubMain()

6.DimobjCOMPlusAsNew_

7.COMPlusJumpStart.COMPlusServices()

8.

9.Console.WriteLine(objCOMPlus.DoTransaction)

10.Console.ReadLine()

11.EndSub

EndModule

试一试
最后,运行此程序并查看其运行情况。
1.打开组件服务MMC管理单元,验证您的组件已经动态注册到COM+目录中。您应该看到图2所示的界面。
2.编译并运行控制台应用程序。
图2:COM+目录中的新建.NET服务组件
基于角色的安全性
如果多个用户调用在COM+下运行的COM组件,您需要进行验证,只允许特定用户访问某个组件。COM+允许您定义角色并为其分配NT用户。定义并设置角色后,就可以指定哪些角色可以运行哪些组件,甚至指定可以运行组件上的哪些方法。
请在此COMPlusServices类中添加一个方法,以添加基于角色的安全性。您需要创建名为Managers的角色,并在新方法中进行测试,查看调用者是否为Managers角色。
添加基于角色的安全性的步骤
不用直接从组件服务MMC管理单元修改COM+应用程序来添加安全角色,只需在项目中添加一个新属性。使用SecurityRoleAttribute类添加新的Managers角色。这个类的构造函数有两个参数:role(字符串值)和everyone(布尔值)。role参数指定要创建的角色的名称,everyone参数指定是否将内置Everyone组添加到此角色的用户中。
1.在注释“COM+注册详细信息”下键入以下代码,将新的安全性角色添加到[b]COM+应用程序中。[/b]
2.'********************************************

3.'COM+注册详细信息

4.

5.'基于角色的安全性属性

<Assembly:SecurityRoleAttribute("Managers",False)>

6.更改安全级别设置,以便在进程级和组件级执行访问检查。这使COM+应用程序具有安全性调用上下文。
7.显示COM+服务管理单元。
8.单击Security(安全性)选项卡并更改安全级别,如图3所示。
图3:在COM+目录中设置安全级别属性
除了手动进行处理外,还可以在组件中添加属性,通知组件执行访问级别检查。以下是在COMPlusServices类一开始的“COM+注册详细信息”部分添加的代码。
<Assembly:ApplicationAccessControlAttribute

(AccessChecksLevel:=AccessChecksLevelOption.ApplicationComponent)>

检查安全性角色
现在,将新方法添加到名为IsManager的类中。此方法将检查用户是否为具有Managers角色的成员。此方法是一个函数,它返回一个布尔值,表明调用者是否为Managers角色。要访问调用该方法的用户的安全上下文,需要使用SecurityCallContext类。通过调用CurrrentCall方法,获得当前用户的上下文。然后调用IsCallerInRole方法,并传递Managers作为此角色的名称。
1.将以下方法添加到COMPlusServices类中。
2.PublicFunctionIsManager()AsBoolean

3.

4.DimobjCallContextAsSecurityCallContext=_

5.SecurityCallContext.CurrentCall

6.

7.IsManager=_

8.objCallContext.IsCallerInRole("Managers")

9.

EndFunction

现在,需要重新生成该组件以测试此新方法。
10.从VisualStudio.NET的Build(生成)菜单中,单击RebuildSolution(重新生成解决方案)。
试一试
1.修改控制台客户端应用程序的SubMain()方法中的代码。此代码应如下所示:
2.SubMain()

3.

4.DimobjCOMPlusAsNew_

5.COMPlusJumpStart.COMPlusServices()

6.

7.Console.WriteLine(objCOMPlus.DoTransaction)

8.Console.WriteLine(objCOMPlus.IsManager().ToString)

9.Console.ReadLine()

10.

EndSub

11.在命令提示下键入您编译的可执行文件的名称,运行控制台应用程序。
第一次运行该代码时会发生异常,并说明访问被拒绝的原因是Managers角色中没有添加任何用户。要纠正这个异常,请将您自己添加为Managers中的用户,并再次运行该应用程序。这次应该不会出现任何异常。也可以在代码中添加异常处理。以下是添加了异常处理代码的客户端应用程序示例:
SubMain()


Try


DimobjCOMPlusAsNew_

COMPlusJumpStart.COMPlusServices()


Console.WriteLine(objCOMPlus.DoTransaction)

Console.WriteLine(objCOMPlus.IsManager().ToString)

Console.ReadLine()


CatchobjExceptionAsException

Console.WriteLine("出现错误。"_

&"详细信息:"_

&objException.Message)

Console.ReadLine()


EndTry


EndSub

使用排队组件
COM+应用程序中,添加排队支持很简单。只需确保该应用程序作为服务器程序运行(进程外),然后在选项卡上设置Queued(排队)和Listen(侦听)属性。完成这些设置后,客户端应用程序就可以异步或同步调用组件。该功能的精妙之处在于,不必更改COM对象中的代码,只需在COM+目录中更改其属性。
.NET框架支持排队组件,而且,正如您期望的那样,您可以通过使用属性,而不用手动更改COM+目录即可为组件提供排队支持。
请在COMPlusServices类中添加一个方法,然后在.NET客户端应用程序中使用COM+排队组件服务异步调用它。
1.将COM+应用程序作为服务器程序(进程外)。这是排队组件的要求。要使用属性达到此目的,请将以下代码添加到项目中:
2.'********************************************

3.'COM+注册详细信息

4.

<Assembly:ApplicationActivationAttribute(ActivationOption.Server)>

5.在组件中添加排队支持。使组件可访问MSMQ队列,并使其侦听自己的队列以处理消息。下面是使用属性完成此过程的代码:
6.'********************************************

7.'COM+注册详细信息

8.

9.<Assembly:ApplicationQueuingAttribute(Enabled:=True,

QueueListenerEnabled:=True)>

10.在类QueueTest中添加一个方法。确保它是子例程且不返回任何值。使用它在Windows应用程序日志中写入信息。此代码应如下所示:
11.PublicSubQueueTest()

12.System.Diagnostics.EventLog.WriteEntry(_

13."COMPlusServces","队列测试",_

14.Diagnostics.EventLogEntryType.Error)

EndSub

就到这里吧。这就是为使组件成为COM+排队组件需要完成的全部操作。
试一试
现在,应该通过创建另一个控制台应用程序并调用此组件,来尝试运行该排队组件。
1.创建新的控制台应用程序。
2.将以下代码添加到控制台应用程序的SubMain过程中。
3.SubMain()

4.DimobjTestAsCOMPlusJumpStart.COMPlusServices

5.DimstrMoniker

6.

7.strMoniker=_

8."queue:/new:COMPlusJumpStart.COMPlusServices"

9.objTest=GetObject(strMoniker)

10.objTest.QueueTest()

EndSub

它将异步调用组件中的QueueTest方法。如果要同步调用此方法,可以象调用该组件中的所有其他方法一样调用它。
现在,可以运行此控制台应用程序,尝试运行此排队组件。
自VisualBasic6.0以来COM+的变化
您已经通过VisualBasic6.0或COM了解了.NET中的许多内容。现在,您已经获得了在.NET框架中工作的好处,这有助于实现对象的平稳交互,您只需编写少量代码,执行少量维护即可。
这类简化操作中最典型的是,在VisualBasic6.0中,必须手动显式调用SetComplete和SetAbort。而在.NET中,SetComplete和SetAbort由<AutoComplete()>属性调用。
VisualBasic.NET和VisualBasic6.0的另一个不同之处是,由于使用单线程单元线程模型,VisualBasic6.0组件不能使用COM+对象池。而VisualBasic.NET组件是.NET组件,支持任何单元线程模型,所以可以使用COM+对象池。
总结
可以看出,利用.NET框架可以方便地利用COM+提供的服务。这意味着您可以将新的.NET组件添加到使用COM和COM+编写的现有程序中,而且它们可以协同工作。这一点非常重要,因为这意味着您不必放弃现有的全部COM和COM+代码。如果您从头开始生成新应用程序,强烈建议您完全在.NET框架中生成它,因为这样效率会更高。
关于作者
TimMcCarthy(MCSD,MCT)是InterKnowlogy的总工程师,他利用最新的Microsoft技术设计并建立了多层应用程序。他经常在DevDays发表演讲,最近刚为MSDNFieldContentTeam编写了.NET培训内容。Tim曾参与编写了许多由Wrox出版社出版的书,最近出版的一本书是《ProfessionalVB.NET》。他还为《SQLServerMagazine》的“DeveloperDotNETUpdate”时事专栏撰写了多篇文章。
PaulD.Sheriff是PDSA,Inc.的所有者。该公司位于南加利福尼亚州,是一家自定义软件开发和咨询公司。Paul是南加利福尼亚的MSDN区域总监,著有《PaulSheriffTeachesVisualBasic》一书,他为KeystoneLearningSystems制作了70多套关于VisualBasic、SQLServer、.NET和Web开发的视频教材,最近还将与KenGetz合作为SAMS写一本书,书名是《ASP.NETJumpstart》。有关详细信息,请访问PDSA,Inc.的Web站点www.pdsa.com。
关于InformantCommunicationsGroup
InformantCommunicationsGroup,Inc.(www.informant.com)是一家专注于信息技术行业的多媒体公司。ICG成立于1990年,致力于与软件开发有关的出版物、会议、目录发布和Web站点等领域。ICG在美国和英国均设有办事处,目前已成为享有盛誉的媒体和营销内容集成商,并以高质量的技术信息满足IT人员不断增长的需求。
©2002InformantCommunicationsGroup和MicrosoftCorporation版权所有。
技术编辑:PDSA,Inc.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: