• .NET Remoting程序开发入门篇(四)


    五、Remoting基础的补充

      通过上面的描述,基本上已经完成了一个最简单的Remoting程序。这是一个标准的创建Remoting程序的方法,但在实际开发过程中,我们遇到的情况也许千奇百怪,如果只掌握一种所谓的“标准”,就妄想可以“一招鲜、吃遍天”,是不可能的。

      1、注册多个通道

      在Remoting中,允许同时创建多个通道,即根据不同的端口创建不同的通道。但是,Remoting要求通道的名字必须不同,因为它要用来作为通道的唯一标识符。虽然IChannel有ChannelName属性,但这个属性是只读的。因此前面所述的创建通道的方法无法实现同时注册多个通道的要求。

      这个时候,我们必须用到System.Collection中的IDictionary接口:

      注册Tcp通道:

    IDictionary tcpProp = new Hashtable();
    tcpProp["name"] = "tcp9090";
    tcpProp["port"] = 9090;
    IChannel channel = new TcpChannel(tcpProp,
    new BinaryClientFormatterSinkProvider(),
    new BinaryServerFormatterSinkProvider());
    ChannelServices.RegisterChannel(channel);


      注册Http通道:

    IDictionary httpProp = new Hashtable();
    httpProp["name"] = "http8080";
    httpProp["port"] = 8080;
    IChannel channel = new HttpChannel(httpProp,
    new SoapClientFormatterSinkProvider(),
    new SoapServerFormatterSinkProvider());
    ChannelServices.RegisterChannel(channel);


      在name属性中,定义不同的通道名称就可以了。

      2、远程对象元数据相关性

      由于服务器端和客户端都要用到远程对象,通常的方式是生成两份完全相同的对象Dll,分别添加引用。不过为了代码的安全性,且降低客户端对远程对象元数据的相关性,我们有必要对这种方式进行改动。即在服务器端实现远程对象,而在客户端则删除这些实现的元数据。

      由于激活模式的不同,在客户端创建对象的方法也不同,所以要分离元数据的相关性,也应分为两种情况。

      (1) WellKnown激活模式:

      通过接口来实现。在服务器端,提供接口和具体类的实现,而在客户端仅提供接口:

    public interface IServerObject
    {
     Person GetPersonInfo(string name,string sex,int age);
    }

    public class ServerObject:MarshalByRefObject,IServerObject
    { ......}


      注意:两边生成该对象程序集的名字必须相同,严格地说,是命名空间的名字必须相同。

      (2) 客户端激活模式:

      如前所述,对于客户端激活模式,不管是使用静态方法,还是使用CreateInstance()方法,都必须在客户端调用构造函数实例化对象。所以,在客户端我们提供的远程对象,就不能只提供接口,而没有类的实现。实际上,要做到与远程对象元数据的分离,可以由两种方法供选择:

      a、利用WellKnown激活模式模拟客户端激活模式:

      方法是利用设计模式中的“抽象工厂”,下面的类图表描述了总体解决方案:




    我们在服务器端的远程对象中加上抽象工厂的接口和实现类:

    public interface IServerObject
    {
     Person GetPersonInfo(string name,string sex,int age);
    }

    public interface IServerObjFactory
    {
     IServerObject CreateInstance();
    }

    public class ServerObject:MarshalByRefObject,IServerObject
    {
     public Person GetPersonInfo(string name,string sex,int age)
     {
      Person person = new Person();
      person.Name = name;
      person.Sex = sex;
      person.Age = age;
      return person;
     }
    }

    public class ServerObjFactory:MarshalByRefObject,IServerObjFactory
    {
     public IServerObject CreateInstance()
     {
      return new ServerObject();
     }
    }


      然后再客户端的远程对象中只提供工厂接口和原来的对象接口:

    public interface IServerObject
    {
     Person GetPersonInfo(string name,string sex,int age);
    }

    public interface IServerObjFactory
    {
     IServerObject CreateInstance();
    }


      我们用WellKnown激活模式注册远程对象,在服务器端:

    //传递对象;
    RemotingConfiguration.RegisterWellKnownServiceType(
    typeof(ServerRemoteObject.ServerObjFactory),
    "ServiceMessage",WellKnownObjectMode.SingleCall);


      注意这里注册的不是ServerObject类对象,而是ServerObjFactory类对象。

      客户端:

    ServerRemoteObject.IServerObjFactory serverFactory =
    (ServerRemoteObject.IServerObjFactory) Activator.GetObject(
    typeof(ServerRemoteObject.IServerObjFactory),
    "tcp://localhost:8080/ServiceMessage");

    ServerRemoteObject.IServerObject serverObj = serverFactory.CreateInstance();


      为什么说这是一种客户端激活模式的模拟呢?从激活的方法来看,我们是使用了SingleCall模式来激活对象,但此时激活的并非我们要传递的远程对象,而是工厂对象。如果客户端要创建远程对象,还应该通过工厂对象的CreateInstance()方法来获得。而这个方法正是在客户端调用的。因此它的实现方式就等同于客户端激活模式。

      b、利用替代类来取代远程对象的元数据

      实际上,我们可以用一个trick,来欺骗Remoting。这里所说的替代类就是这个trick了。既然是提供服务,Remoting传递的远程对象其实现的细节当然是放在服务器端。而要在客户端放对象的副本,不过是因为客户端必须调用构造函数,而采取的无奈之举。既然具体的实现是在服务器端,又为了能在客户端实例化,那么在客户端就实现这些好了。至于实现的细节,就不用管了。

      如果远程对象有方法,服务器端则提供方法实现,而客户端就提供这个方法就OK了,至于里面的实现,你可以是抛出一个异常,或者return 一个null值;如果方法返回void,那么里面可以是空。关键是这个客户端类对象要有这个方法。这个方法的实现,其实和方法的声明差不多,所以我说是一个trick。方法如是,构造函数也如此。

      还是用代码来说明这种“阴谋”,更直观:

      服务器端:

    public class ServerObject:MarshalByRefObject
    {
    public ServerObject()
    {}

    public Person GetPersonInfo(string name,string sex,int age)
    {
     Person person = new Person();
     person.Name = name;
     person.Sex = sex;
     person.Age = age;
     return person;
    }
    }

  • 相关阅读:
    Mysql 常用函数(15)- upper 函数
    Mysql 常用函数(14)- lower 函数
    Mysql 常用函数(13)- right 函数
    Mysql 常用函数(12)- left 函数
    Mysql 常用函数(11)- trim 函数
    Mysql 常用函数(10)- strcmp 函数
    Mysql 常用函数(9)- reverse 函数
    Mysql 常用函数(8)- concat 函数
    Mysql 常用函数(7)- length 函数
    影评1|发个以前写的影评《情书》
  • 原文地址:https://www.cnblogs.com/goody9807/p/800307.html
Copyright © 2020-2023  润新知