.NET Remoting中的事件处理

来源:互联网 发布:上网监控软件破解版 编辑:程序博客网 时间:2024/05/16 06:06

好多人都对Remoting中的事件处理很疑惑,现将完整实现Remoting中事件处理的过程写出来,并对容易犯错误的地方进行总结,希望能给大家一些帮助。
现假设有一个留言板程序:
以下代码中,MsgBoard为以Singleton模式存活于服务器端的共享留言板实例,AddMessage是客户端添加留言的接口,MsgBoard定义如下:

    public class MsgBoard:MarshalByRefObject 
    
{
        
public delegate void EventDelegate(string info);
        
public event EventDelegate OnInfoAdded;
        
public void AddMessage(string info)
        
{
            Console.WriteLine(info);
            if(OnInfoAdded!=null)
                      OnInfoAdded(info);
        }

    }


在有客户端添加留言时,激发一个事件,我们的客户端去订阅该事件来得到留言板更新的通知。
服务器端代码如下:

Using directives

namespace ConsoleServer
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            RemotingConfiguration.RegisterWellKnownServiceType(
typeof(MyLibrary.MsgBoard), "MyUri", WellKnownObjectMode.

Singleton);
            HttpChannel myChannel 
= new HttpChannel(1080);
            ChannelServices.RegisterChannel(myChannel);

            
//////
            IServerChannelSink sc = myChannel.ChannelSinkChain;
            
while (sc != null)
            
{
                
if (sc is BinaryServerFormatterSink)
                
{
                    ((BinaryServerFormatterSink)sc).TypeFilterLevel 
= TypeFilterLevel.Full;
                    
//break;
                }

                
if (sc is SoapServerFormatterSink)
                
{
                    ((SoapServerFormatterSink)sc).TypeFilterLevel 
= TypeFilterLevel.Full;
                    
//break;
                }

                sc 
= sc.NextChannelSink;
            }

            Console.WriteLine("Server Started");
            Console.ReadLine();
        }

    }

}


我们可以不要详细去关心服务器端程序的代码,我们只需要知道:
1,服务器注册了远程服务的类型
2,TypeFilterLevel = TypeFilterLevel.Full
   由于从.NET Framework 1.1起,缺省情况下DelegateSerializationHolder不允许被反序列化,(即FormatterSink.TypeFilterLevel = TypeFilterLevel.low)。为了实现远程事件处理,我们必须解除该约束,使ServerFormatterSink.TypeFilterLevel = TypeFilterLevel.Full

我们更加需要关心的是我们的客户端代码:

Using directives


namespace ConsoleClient
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            
try
            
{
                RemotingConfiguration.RegisterWellKnownClientType(
typeof(MyLibrary.MsgBoard), "Http://localhost:1080/MyUri

");
                HttpChannel myChannel = new HttpChannel(1000);
                ChannelServices.RegisterChannel(myChannel);
                IServerChannelSink sc 
= myChannel.ChannelSinkChain;
                Console.WriteLine(
"Client Started");
                MyLibrary.MsgBoard msgbd 
= new MyLibrary.MsgBoard();
                
///msgbd.OnInfoAdded += new MyLibrary.MsgBoard.EventDelegate(msgbd_OnInfoAdded);
                MyLibrary.eventClass evclass = new MyLibrary.eventClass();
                msgbd.OnInfoAdded 
+= new MyLibrary.MsgBoard.EventDelegate(evclass.msgbd_OnInfoAdded);///instead
                msgbd.AddMessage("Hello all");
                Console.ReadLine();
            }

            
catch (Exception exc)
            
{
                Console.WriteLine(exc.StackTrace);
                Console.ReadLine();
            }

        }


        
public static void msgbd_OnInfoAdded(string info)
        
{
            Console.WriteLine(
"info on server event:{0}", info);
        }

    }


}



请注意:此处我们使用一个实例方法去订阅服务器组件的事件,该实例类型定义如下:

    public class eventClass:MarshalByRefObject 
    
{
        
public void msgbd_OnInfoAdded(string info)
        
{
            Console.WriteLine(
"info from server event:{0}", info);
        }

    }


为什么要这么做?
.NET Framework要求,事件的发布者必须拥有事件订阅者的元数据,而提供元数据的简单方法,就是让服务器程序添加对客户端程序的引用,但事实上我们不需要这么做,我们将订阅者声明在远程类的程序集中,而该程序集的元数据原本就是服务器和客户端共有的。此时我们要注意到,订阅事件的类,也被申明成MarshalByRefObject,这是.NET Framework 2.0出现的一个限制,委派在序列化信息中包含了函数对应实例的地址,在服务器端回掉时,可以寻址到客户端订阅的对象实例并执行相应的成员方法,既然能被服务器寻址,则该订阅对象要求是MarshalByRefObject,这不难理解。在.NET Framework 2.0之前,我们可以使用一个包含静态函数的委派去订阅服务器组件的事件,但2.0以后,如果用一个静态成员去订阅,该响应会在服务器空间内被执行,所以我们要记住,远程处理总是处理某种形式的实例成员,而静态成员不能。
总结一下:
要实现Remoting事件远程处理,要记住以下几个原则:
1,缺省情况下DelegateSerializationHolder不允许被反序列化
2,事件发起者必须拥有订阅者的元数据
3,远程处理总是处理实例成员,且该实例必须是MarshalByReference

附加:

由于HttpChannel将ChannelSinkChain作为公开的属性所以我们能够直接修改TypeFilterLevel,而队TcpChannel,ChannelSinkChain是无法直接访问的,我们可以在监视窗口看到SinkProvider,我们只能在构造TcpChannel时去干涉它,HttpChannel和TcpChannel都可以使用配置文件的方法,但代码有助于理解。
以下是HttpChannel修改TypeFilterLevel的示例:
BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["port"] = 1080;

// HttpChannel chan = new HttpChannel(props, clientProv, provider);
// ChannelServices.RegisterChannel(chan);

RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyLibrary.MsgBoard), "MyUri", WellKnownObjectMode.Singleton);
TcpChannel myChannel = new TcpChannel(props, clientProv, serverProv);
ChannelServices.RegisterChannel(myChannel);

 


 

  Tuesday, November 09, 2004 12:05 AM




原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 邵东一中校花张娇娇图 中图法 空客320中座位分布图 楼中楼装修效果图 阿中哥哥红旗图 中图 图书 中国旧书网 中国图书 书籍 中华图书网 图书网站 图书购买网站 图书网 中国图书网 满城尽带金甲中抓胸图 朝花夕拾二十四孝图主要内容 圄怎么读 囵圄 囵圄怎么读 学习强圄 中土世界 中土世界战争之影 中土世界暗影魔多 我从秽土转生中复活 中土集团 中土 沙中土 土狗中狗王胡须图片 中土世界战争之影套装 中土世界战争之影兽人培养 中土世界战争之影攻略 中土纪元手游 中土大厦酒店 中土世界暗影魔多攻略 中土纪元好玩吗 中土物业管理集团有限公司 中土世界战争之影好玩吗 孔圣枕中丹 中江蜀地翔圣赛鸽公棚