分享
 
 
 

将COM+ Events进行到底

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

将COM+ Events进行到底(一)

Article last modified on 2002-7-4

----------------------------------------------------------------

The information in this article applies to:

- Microsoft Windows 2000 Advanced Server

- Microsoft Windows 2000 Server

- Microsoft Windows 2000 Professional

- Microsoft Component Service 1.0

----------------------------------------------------------------

概要

通常,我们在组件和客户程序之间实现事件通知与订阅时,会采用这两种方法:回调(Callback),和连接点(ConnectionPoint)。他们的本质其实都是,订阅者将接口传递给发布者,当有事情发生时,发布者调用接口的方法。这种类型的事件叫Tightly Coupled Event(TCE),属于Request-Reply方式。

TCE的限制在于:

1. 订阅者必须知道它所请求的通知来自于哪一个发布者。发布者和订阅者紧紧绑定在一起,双方程序代码依赖于接口的定义,我们必须在编译时刻知道对方的信息(CLSID,或ProgID);

2. 要求订阅者和发布者必须同时在线。也就是说,在生存周期上必须重叠(overlap);

3. 不包含过滤或截取机制。

COM+提供了一种全新的服务:COM+ Events或者Loosely Coupled Events(LCE)。不过此事件非彼事件。用微软的话说就是“COM+ 事件不与传统 ConnectionPoints 事件关联,并且在完全不同的方案中使用。”

它的思路是,发布者亲自维护一个外部数据库(我们管它叫EventList),其中存储了订阅的所有事件的列表。发布者通过这个表知道该如何发送事件通知。订阅者也可以读入此列表,并选择它感兴趣的事件。发布者再维护另一个数据库(我们管它叫SubscribtionList),其中存储了订阅者的CLSID。从概念上讲,这个数据库相当于一个邮件列表。订阅者可以向这个库中添加自己的CLSID。发布者想要激发事件时,会检查这个数据库,找到所有订阅这个事件的订阅者的CLSID,创建每一个相关类的新对象,并调用对象的方法。

这个属于Publisher-Subscriber方式。

(图1可参看http://www.microsoft.com/CHINA/msdn/library/techart/com+agvb4.gif)

Fig 1

具体执行的顺序,图2说得非常明白:

(图2可参看http://www.idevresource.com/images/articles/com+eventsintro1.gif)

Fig 2 shows a typical COM+ events life cycle.

LCE的优点就在于:

n 订阅者不必知道上层事件处理的细节;

n 发布者不在运行时,订阅者也可以发出订阅请求;发布者不用理会订阅者是否在家,就可以发布通知;

n 过滤或者截取。订阅者可以选择订阅事件中哪些他更感兴趣,比如,一个订户订阅了出版社的新书通知,但是他还可以告诉出版社只有当国外作家的新书到达时才给他通知,或者只有当价格低于50元的新书到达时候才通知他。

更多细节

发布者的事件方法执行情况:

当一个事件的方法最终返回时,

非QC的订阅者中:

临时订阅者的情况:订阅者对象已经被调用,而且方法已经返回!

永久订阅者的情况:订阅者对象已经被创建、调用、返回,而且已经被释放!

QC订阅者的情况:

所有对QC订阅者的调用已经被记录下来;

对于永久订阅者,这些记录已经被送到队列准备传送出去。

所以非QC订阅者的执行情况会影响到发布者,而QC不会。比如非QC的订阅者中如果在接收到事件通知的方法中Sleep个一分钟,那发布者的事件方法就必须老老实实等1分钟,然后再调用下一个订阅者对象。

订阅者的疑问一:

提问:

如果我的订阅者程序已经在处理一个事件了,这时候又来了一个事件通知,那么这第二个事件会被谁接收呢?

是新创建一个订阅者对象呢?还是等着当前这个事件处理完?

回答:

我认为是后者。

发布者的疑问一:

提问:

发布者可不可以位于不同的机器?

回答:

发布者分布到远程服务器上,但是事件通知仍然在中心服务器上。这种情况可以通过下面两种方法做到:

u 将EventClass所在的COM+应用导出为应用程序代理。在远程服务器上安装这个代理。

u 在远程服务器上调用该EventClass发布事件时,调用代码改为:CreateObject(“%YourEventClassProgID%”, “\\%YourCenterServerName%”)。

这样,在远程服务器上的事件发布行为,都会被转到中心服务器上的EventClass应用。

订阅者的疑问二:

提问:

订阅者是否可以位于不同的机器呢?

回答:

下面的文字是引用MSDN的《COM+ Events Architecture》:

Note This version of COM+ Events does not support a distributed event store. A subscriber must subscribe to an event on each computer from which it wants to receive notification. As an alternative, you can register the EventClass and subscriptions on a central computer and instantiate this EventClass from the remote computers on which you will publish events. Delivery of events is provided either by DCOM or queued components. For more information on using queued components, see Composing Events with Queued Components.

曾经有人做过下面的步骤试图远程订阅:

ü 远程订阅者创建一个“COMAdmin.COMAdminCatalog”的实例;

ü 远程订阅者调用COMAdmin.COMAdminCatalog的Connect方法连结至中心服务器;

ü 远程订阅者通过向中心服务器的临时订阅数据库中添加一条记录来订阅;

但是,结果是中心服务器的其他本地订阅者都接收到了事件通知,而远程订阅者却没有。

建议如果真的想远程订阅的话,可以自己实现DCOM,或者用QC。

EventClass组件的调试:

如果在VC IDE或者VB IDE中设断点调试EventClass组件,那么当事件发布时,订阅者将接收不到事件通知。

这是由于在COM+应用中EventClass组件的注册地址已经被更改为:

D:\Program Files\Microsoft Visual Studio\VB98\VB6DEBUG.DLL了!

虽然,EventCalss组件的CLSID没有变,但是不是和订阅数据库中记录的不一样了呢,所以没有通知订阅者。

制作实录:

第一步,先做一个EventClass组件:

新建一个VB DLL,Project Name为TomoTrace,Class Module Name为Trace。

代码极其简单,为:

Public Function Publish(ByVal strAuthor As String, _

ByVal strTraceType As String, _

ByVal strEventCategory As String, _

ByVal nEventID As Integer, _

ByVal nOther As Integer, _

ByVal strTraceContent As String) As Integer

' Do Nothing

End Function

在组件服务中新建一个COM+应用,在该应用下新建组件TomoTrace.Trace,注意要选择安装为新的事件类。

记录下这个接口的CLSID。

第二步,做一个订阅者:

新建一个VB EXE,Project Name为Trace2File。

首先要引用TomoTrace组件,并实现它的Trace接口:

Implements Trace

声明一些全局变量:

‘ g_oAdmin将是COMAdmin.COMAdminCatalog的实例对象:

Dim g_oAdmin As Object

‘ 使用ICatalogObject接口将允许读写COM+ Catalog中的对象暴露出来的属性:

Dim SubObj As ICatalogObject

Const TransientSubscription = "Transient Subscription"

‘ 这是TomoTrace.Trace事件接口的ClassID:

Const EVENTCLSID = "{8EDBE260-A7C7-4000-BF95-CA4CC8FCA6C2}"

Dim g_CascadeApp, g_TransID

‘ 你可以用ICatalogCollection接口枚举、添加、删除和获得Collection中的条目:

Dim Subcoll As ICatalogCollection

在Form初始化时,提交订阅请求:

Private Sub Form_Load()

' Create COMAdmin object

Set g_oAdmin = CreateObject("COMAdmin.COMAdminCatalog.1")

' Get the TRANSIENTSUBSCRIPTIONS collection

Set Subcoll = g_oAdmin.GetCollection("TransientSubscriptions")

' Add a new subscription

Set SubObj = Subcoll.Add

‘ 将我们的EventClass的CLSID加进去

SubObj.Value("EventCLSID") = EVENTCLSID

‘ 临时订阅时,这个Name条目的值一定是“Transient Subscription”

SubObj.Value("Name") = TransientSubscription

SubObj.Value("SubscriberInterface") = Me

‘ 将所做的改变存入COM+ Catalog Data Store中:

Subcoll.SaveChanges

‘ 实际计算中g_TransID的值将为

’ {ADA4AFA1-6B54-4C4B-A74A-9EFFF4F7DC3F},这就是这次订阅的唯一标识

‘ 我们将在取消订阅时用到这个标识

g_TransID = SubObj.Value("ID")

End Sub

Form退出时,取消临时订阅:

Private Sub Form_Unload(Cancel As Integer)

On Error Resume Next

‘ 对于Collection中的所有对象,读取数据

Subcoll.Populate

' Remove the subscription

Dim k

For k = 0 To Subcoll.Count - 1

Dim oObject

Set oObject = Subcoll.Item(k)

‘ 如果Collection中的条目的ID和我们先前保存的ID一样,则删除

If oObject.Value("ID") = g_TransID Then

Subcoll.Remove (k)

Subcoll.SaveChanges

End If

Next

On Error GoTo 0

End Sub

实现事件的方法:

Private Function Trace_Publish(ByVal strAuthor As String, _

ByVal strTraceType As String, _

ByVal strEventCategory As String, _

ByVal nEventID As Integer, _

ByVal nOther As Integer, _

ByVal strTraceContent As String) As Integer

‘ 将Trace的内容添加到listbox中:

Dim lCount As Long

listTrace.AddItem Now & " :: " & strTraceType

If (Len(strTraceContent) < 60) Then

listTrace.AddItem "--------" & strTraceContent

Else

listTrace.AddItem "--------" & Left(strTraceContent, 60) & "..."

End If

lCount = listTrace.ListCount - 1

listTrace.ListIndex = lCount

If lCount > 20 Then

listTrace.RemoveItem 0

End If

End Function

第三步,做一个发布者:

新建一个VBScript脚本,它将调用EventClass组件TomoTrace.Trace:

Dim obj

Set obj = CreateObject("TomoTrace.Trace")

strAuthor = "TomoEvent"

strTraceType= "Information"

strEventCategory = "Application"

nEventID = 0

nOther = 0

strTraceContent = "这里我们的例子中,EventClass就是TomoTrace.DLL组件,订阅者是Trace2File.EXE。发布者就是本脚本。"

obj.Publish strAuthor, strTraceType, strEventCategory, nEventID, nOther, strTraceContent

PublisheràDistributoràSubscriber:

先启动几个Trace2File.EXE,然后运行VBScript脚本。你就会看到这几个Trace2File上显示出发布的Trace内容。

然后将这个脚本放置在远程机器上,修改一下脚本:CreateObject(“TomoTrace.Trace”) àCreateObject(“TomoTrace.Trace”,”\\zhengyun”)。这样就可以在其他机器上向中心服务器发布事件通知了。

Written by zhengyun (at) tomosoft.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有