.NET Remoting中的事件处理

news/2024/6/16 13:10:18

好多人都对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
href="http://blog.joycode.com/joe/Services/Pingback.aspx" rel="pingback"/>





http://www.niftyadmin.cn/n/3657321.html

相关文章

DataList嵌套,分页,点击父DataList标题在子DataList显示相关的内容,点击子DataList标题显示主要内容.

这里例子结合了DataList的分页和嵌套&#xff0c;还有点击显示相对内容的关联。HTML代码&#xff1a;<% Page language"c#" Codebehind"DataListNews.aspx.cs" AutoEventWireup"false" Inherits"DataListNesting.DataListNews" %&g…

驱动程序中的并发与控制(一)

驱动程序中的并发与控制&#xff08;一&#xff09; 驱动程序中的并发与控制&#xff08;二&#xff09; 驱动程序中的并发与控制&#xff08;三&#xff09; 并发与竟态 并发指的是多个执行单元同时、并行被执行&#xff0c;而并发的执行单元对共享资源&#xff08;硬件资源…

DataGrid单元格移动变色,点击变色,双击取消颜色,排序.

实现:1.当鼠标移动到DataGrid的单元格时,单元格变色,并且单元格里的字体同时变色,鼠标变为手的形状.鼠标移出单元格,恢复原样.2.当鼠标点击DataGrid的单元格时,单元格变色,单元格上的显示字体变色;当点击另一个单元格时,前一个单元格以及字体颜色恢复原样,此时的单元格变色,字体…

驱动程序中的并发与控制(二)

驱动程序中的并发与控制&#xff08;一&#xff09; 驱动程序中的并发与控制&#xff08;二&#xff09; 驱动程序中的并发与控制&#xff08;三&#xff09; 自旋锁spin_lock 说明&#xff1a;下面的源码分析来自内核版本4.9.88 设计自旋锁的最初目的是在多处理器系统中提供…

驱动程序中的并发与控制(三)

驱动程序中的并发与控制&#xff08;一&#xff09; 驱动程序中的并发与控制&#xff08;二&#xff09; 驱动程序中的并发与控制&#xff08;三&#xff09; 信号量(semaphore) 相对于自旋锁&#xff0c;信号量的最大特点是允许调用它的线程进入睡眠状态。 信号量的定义与初…

Asp.net 2.0的异常处理需要考虑的问题

在.NET 1.1, 只有主线程中未处理的异常才会终止应用程序的运行,其他的线程的异常.CLR会处理,因此你的应用程序可以正常运行.在 .NET 2.0, 任何线程上的未处理的异常都可能终止应用程序的运行 (具体信息参看Exceptions In Managed Threads ). 这对于Asp.net开发者来说,特别在将1…

Linux i2c驱动框架分析 (一)

Linux i2c驱动框架分析 &#xff08;一&#xff09; Linux i2c驱动框架分析 &#xff08;二&#xff09; Linux i2c驱动框架分析 &#xff08;三&#xff09; 通用i2c设备驱动分析 Linux的i2c体系结构 Linux的i2c体系结构分为3个组成部分。 (1) i2c核心 i2c核心提供了i2c总线…

Linux i2c驱动框架分析 (二)

Linux i2c驱动框架分析 &#xff08;一&#xff09; Linux i2c驱动框架分析 &#xff08;二&#xff09; Linux i2c驱动框架分析 &#xff08;三&#xff09; 通用i2c设备驱动分析 i2c core i2c核心&#xff08;drivers/i2c/i2c-core.c&#xff09;中提供了一组不依赖于硬件平…