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

.NET Remoting中的事件处理(.NET Framework 2.0)(一)    public class MsgBoard:MarshalByRefObject 
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)        
public delegate void EventDelegate(string info);
.NET Remoting中的事件处理(.NET Framework 2.0)(一)        
public event EventDelegate OnInfoAdded;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)        
public void AddMessage(string info)
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            Console.WriteLine(info);
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            OnInfoAdded(info);
.NET Remoting中的事件处理(.NET Framework 2.0)(一)        }

.NET Remoting中的事件处理(.NET Framework 2.0)(一)    }


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


.NET Remoting中的事件处理(.NET Framework 2.0)(一)
.NET Remoting中的事件处理(.NET Framework 2.0)(一)using System;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
using System.Collections.Generic;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
using System.Text;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
using System.Runtime.Remoting;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
using System.Runtime.Remoting.Channels;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
using System.Runtime.Remoting.Channels.Http;

.NET Remoting中的事件处理(.NET Framework 2.0)(一)#endregion
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
namespace ConsoleServer
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)    
class Program
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)        
static void Main(string[] args)
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            RemotingConfiguration.RegisterWellKnownServiceType(
typeof(MyLibrary.MsgBoard), "MyUri", WellKnownObjectMode.
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
.NET Remoting中的事件处理(.NET Framework 2.0)(一)Singleton);
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            HttpChannel myChannel 
= new HttpChannel(1080);
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            ChannelServices.RegisterChannel(myChannel);
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
//////

.NET Remoting中的事件处理(.NET Framework 2.0)(一)            IServerChannelSink sc = myChannel.ChannelSinkChain;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            
while (sc != null)
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                
if (sc is BinaryServerFormatterSink)
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                    ((BinaryServerFormatterSink)sc).TypeFilterLevel 
= TypeFilterLevel.Full;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                    
//break;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
                }
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                
if (sc is SoapServerFormatterSink)
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                    ((SoapServerFormatterSink)sc).TypeFilterLevel 
= TypeFilterLevel.Full;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                    
//break;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
                }
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                sc 
= sc.NextChannelSink;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            }

.NET Remoting中的事件处理(.NET Framework 2.0)(一)            Console.WriteLine("Server Started");
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            Console.ReadLine();
.NET Remoting中的事件处理(.NET Framework 2.0)(一)        }

.NET Remoting中的事件处理(.NET Framework 2.0)(一)    }

.NET Remoting中的事件处理(.NET Framework 2.0)(一)}

.NET Remoting中的事件处理(.NET Framework 2.0)(一)
.NET Remoting中的事件处理(.NET Framework 2.0)(一)

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

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


.NET Remoting中的事件处理(.NET Framework 2.0)(一)
.NET Remoting中的事件处理(.NET Framework 2.0)(一)using System;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
using System.Collections.Generic;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
using System.Text;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
using System.Runtime.Remoting;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
using System.Runtime.Remoting.Channels;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
using System.Runtime.Remoting.Channels.Http;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
using System.Runtime.Serialization.Formatters;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
#endregion
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
namespace ConsoleClient
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)    
class Program
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)        
static void Main(string[] args)
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            
try
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                RemotingConfiguration.RegisterWellKnownClientType(
typeof(MyLibrary.MsgBoard), "Http://localhost:1080/MyUri
.NET Remoting中的事件处理(.NET Framework 2.0)(一)

.NET Remoting中的事件处理(.NET Framework 2.0)(一)
");
.NET Remoting中的事件处理(.NET Framework 2.0)(一)
                HttpChannel myChannel = new HttpChannel(1000);
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                ChannelServices.RegisterChannel(myChannel);
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                IServerChannelSink sc 
= myChannel.ChannelSinkChain;
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                Console.WriteLine(
"Client Started");
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                MyLibrary.MsgBoard msgbd 
= new MyLibrary.MsgBoard();

.NET Remoting中的事件处理(.NET Framework 2.0)(一)                MyLibrary.eventClass evclass = new MyLibrary.eventClass();

.NET Remoting中的事件处理(.NET Framework 2.0)(一)                msgbd.AddMessage("Hello all");
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                Console.ReadLine();
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            }

.NET Remoting中的事件处理(.NET Framework 2.0)(一)            
catch (Exception exc)
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                Console.WriteLine(exc.StackTrace);
.NET Remoting中的事件处理(.NET Framework 2.0)(一)                Console.ReadLine();
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            }

.NET Remoting中的事件处理(.NET Framework 2.0)(一)        }

.NET Remoting中的事件处理(.NET Framework 2.0)(一)
.NET Remoting中的事件处理(.NET Framework 2.0)(一)        
public static void msgbd_OnInfoAdded(string info)
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            Console.WriteLine(
"info on server event:{0}", info);
.NET Remoting中的事件处理(.NET Framework 2.0)(一)        }

.NET Remoting中的事件处理(.NET Framework 2.0)(一)    }

.NET Remoting中的事件处理(.NET Framework 2.0)(一)
.NET Remoting中的事件处理(.NET Framework 2.0)(一)}

.NET Remoting中的事件处理(.NET Framework 2.0)(一)
.NET Remoting中的事件处理(.NET Framework 2.0)(一)


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

.NET Remoting中的事件处理(.NET Framework 2.0)(一)    public class eventClass:MarshalByRefObject 
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)        
public void msgbd_OnInfoAdded(string info)
{
.NET Remoting中的事件处理(.NET Framework 2.0)(一)            Console.WriteLine(
"info from server event:{0}", info);
.NET Remoting中的事件处理(.NET Framework 2.0)(一)        }

.NET Remoting中的事件处理(.NET Framework 2.0)(一)    }


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

例子在:https://files.cnblogs.com/dahuaidan410/Event2.rar

 


 

相关文章: