Microsoft .Net Remoting系列教程之三:Remoting事件处理全(4)

private void btnBC_Click(object sender, System.EventArgs e) { BroadCastForm bcForm = new BroadCastForm(); bcForm.StartPosition = FormStartPosition.CenterParent; bcForm.ShowDialog(); }

在对话框中,最主要的就是Send按钮:

if (txtInfo.Text != string.Empty) { ServerForm.Obj.BroadCastingInfo(txtInfo.Text); } else { MessageBox.Show("请输入信息!"); }


但是很简单,就是调用远程对象的发送消息方法而已。

现在该实现客户端了。我们可以参照前面的例子,只是把服务端改为客户端而已。另外考虑到序列化安全级别的问题,所以代码会是这样:

private void ClientForm_Load(object sender, System.EventArgs e) { BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); serverProvider.TypeFilterLevel = TypeFilterLevel.Full; IDictionary props = new Hashtable(); props["port"] = 0; HttpChannel channel = new HttpChannel(props,clientProvider,serverProvider); ChannelServices.RegisterChannel(channel); watch = (IBroadCast)Activator.GetObject( typeof(IBroadCast),"http://localhost:8080/BroadCastMessage.soap"); watch.BroadCastEvent += new BroadCastEventHandler(BroadCastingMessage); }

注意客户端通道的端口号应设置为0,这表示客户端自动选择可用的端口号。如果要设置为指定的端口号,则必须保证与服务端通道的端口号不相同。
然后是,BroadCastEventHandler委托的方法:

public void BroadCastingMessage(string message) { txtMessage.Text += "I got it:" + message; txtMessage.Text += System.Environment.NewLine; }

客户端界面如图:

/uploads/allimg/200612/1G6445418_0.gif

好,下面让我们满怀期盼,来运行这段程序。首先启动服务端应用程序,然后启动客户端。哎呀,糟糕,居然出现了错误信息!

/uploads/allimg/200612/1G640W36_0.gif

  “人之不如意事,十常居八九。”不用沮丧,让我们分析原因。首先看看错误信息,它报告我们没有找到Client程序集。然而事实上,Client程序集当然是有的。那么再来调试一下,是哪一步出现的问题呢?设置好断点,进行逐语句跟踪。前面注册通道一切正常,当运行到watch.BroadCastEvent += new BroadCastEventHandler(BroadCastingMessage)语句时,错误出现了!

  也就是说,远程对象的创建是成功的,但在订阅事件的时候失败了。原因是什么呢?原来,客户端的委托是通过序列化后获得的,在订阅事件的时候,委托试图装载包含与签名相同的方法的程序集,也就是BroadCastingMessage方法所在的程序集Client。然而这个装载的过程发生在服务端,而在服务端,并没有Client程序集存在,自然就发生了上面的异常。

  原因清楚了,怎么解决?首先BroadCastingMessage方法肯定是在客户端中,所以不可避免,委托装载Client程序集的过程也必须在客户端完成。而服务端事件又是由远程对象来捕获的,因此,在客户端注册的也就必须是远程对象事件了。一个要求必须在客户端,一个又要求必须在服务端,事情出现了自相矛盾的地方。

那么,让我们先想想这样一个例子。假设我们要交换x和y的值,该这样完成?很简单,引入一个中间变量就可以了。

int x=1,y=2,z; z = x; x = y; y = z;

这个游戏相信大家都会玩吧,那么好的,我们也需要引入这样一个“中间”对象。这个中间对象和原来的远程对象在事件处理方面,代码完全一致:

public class EventWrapper:MarshalByRefObject { public event BroadCastEventHandler LocalBroadCastEvent; //[OneWay] public void BroadCasting(string message) { LocalBroadCastEvent(message); } public override object InitializeLifetimeService() { return null; } }

不过不同之处在于:这个Wrapper类必须在客户端和服务端上都要部署,所以,这个类应该放在公共程序集Common.dll中。

现在再来修改原来的客户端代码:

watch = (IBroadCast)Activator.GetObject( typeof(IBroadCast),"http://localhost:8080/BroadCastMessage.soap"); watch.BroadCastEvent += new BroadCastEventHandler(BroadCastingMessage);

修改为:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wjypdf.html