watch = (IBroadCast)Activator.GetObject( typeof(IBroadCast),"http://localhost:8080/BroadCastMessage.soap"); EventWrapper wrapper = new EventWrapper(); wrapper.LocalBroadCastEvent += new BroadCastEventHandler(BroadCastingMessage); watch.BroadCastEvent += new BroadCastEventHandler(wrapper.BroadCasting);
为什么这样做就可以了呢?也许画一幅图就很容易说明,可惜我的艺术天分实在很糟糕,我希望以后可以改进这一点。还是用文字来说明吧。
前面说,委托要装载client程序集。现在我们把远程对象委托装载的权利移交给EventWrapper。因为这个类对象是放在客户端的,所以它要装载client程序集丝毫没有问题。语句:
EventWrapper wrapper = new EventWrapper(); wrapper.LocalBroadCastEvent += new BroadCastEventHandler(BroadCastingMessage);
实现了这个功能。
不过此时虽然订阅了事件,但事件还是客户端的,没有与服务端联系起来。而服务端的事件是放到远程对象中的,所以,还要订阅事件,这个任务由远程对象watch来完成。但此时它订阅的不再是BroadCastingMessage了,而是EventWrapper的触发事件方法BroadCasting。那么此时委托同样要装载程序集,但此时装载的就是BroadCasting所在的程序集了。由于装载发生的地点是在服务端。呵呵,高兴的是,BroadCasting所在的程序集正是公共程序集(前面已说过,EventWrapper应放到公共程序集Common.dll中),而公共程序集在服务端和客户端都已经部署了。自然就不会出现找不到程序集的问题了。
注意:EventWrapper因为要重写InitializeLifetimeService()方法,所以仍然要继承MarshalByRefObject类。
现在再来运行程序。首先运行服务端;然后运行客户端,OK,客户端窗体出现了:
然后我们在服务端单击“BroadCast”按钮,发送广播消息:
单击“Send”发送,再来看看客户端,会是怎样?Fine,I got it!
怎么样,很酷吧!你也可以同时打开多个客户端,它们都将收到这个广播信息。如果你觉得这个广播声音太吵,那就请你在客户端取消广播吧。在Cancle按钮中:
private void btnCancle_Click(object sender, System.EventArgs e) { watch.BroadCastEvent -= new BroadCastEventHandler(wrapper.BroadCasting); MessageBox.Show("取消订阅广播成功!"); }
当然这个时候wrapper对象应该被申明为private对象了:
private EventWrapper wrapper = null;
取消后,你试着再广播一下,恭喜你,你不会听到噪音了!
三、 客户端订阅客户端事件
有了前面的基础,再来看客户端订阅客户端事件,就简单多了。而本文写到这里,我也很累了,你也被我啰嗦得不耐烦了。你心里在喊,“饶了我吧!”其实,我又何尝不是如此。所以我只提供一个思路,有兴趣的朋友,可以自己写一个程序。
其实方法很简单,和第二种情况类似。发送信息的客户端,只需要获得远程对象后,发送消息就可以了。而接收信息的客户端,负责订阅该事件。由于事件都是放到远程对象中,因此订阅的方法和第二种情况没有什么区别!
特殊的情况是,我们可以用第三种情况来代替第二种。只要你把发送信息的客户端放到服务端就可以了。当然需要做一些额外的工作,有兴趣的朋友可以去实现一下。在我的示例程序中,已经用这种方法模拟实现了服务端的广播,大家可以去看看。
四、 一点补充
我在前面的事件处理中,使用的都是默认的EventArgs。如果要定义自己的EventArgs,就不相同了。因为该信息是传值序列化,因此必须加上[Serializable],且必须放到公共程序集中,部署到服务端和客户端。例如:
[Serializable] public class BroadcastEventArgs:EventArgs { private string msg = null; public BroadcastEventArgs(string message) { msg = message; } public string Message { get {return msg;} } }
五、持续改进(经Beta的提醒,我改进了我的程序,并对文章进行了修改 2004年12月13日)