.NET Remoting技术是构建企业级分布式应用的很好选择,(个人感觉随.Net Framework 3.0推出的WPF更加强大和易用),我们的项目采用服务端SingleCall方式来激活远程对象,在这种方式下最大的特点是当你new一个对象出来的时候并不会调用相应类型的构造函数,只有当你使用该类型的方法时才会调用构造函数,为换句话说就是SingleCall方式下不保存对象状态,这样做的好处是客户端不会长时间占用服务器资源,但是也就造成不能共享状态。

      最近让我苦恼的一件事是:我想在客户端生成远程对象的时候传一个参数进去,但是服务端激活方式Singleton和SingleCall在生成远程对象时只支持调用无参的默认构造函数,所以在调用带参数的构造函数上我就死了心(不知道各位高手能不能搞定),下面我还原一下我的场景:

      项目采用多层架构,将各个base基类组织起来实现了这个架构,它相当于一个基础框架,以后的应用开发以这个架构为基础,在应用开发时假设框架是稳定的不可变的。

      客户端中生成远程对象的层可以叫做CustomUip,它有个base基类BaseUip,服务端中最接近客户端的层可以叫做ServiceLayer,它也有个base基类BaseService,和一个对外接口IService,客户端通过该接口来获取远程对象,通过ServiceLayer可以使用业务逻辑层ServiceLogic,可以用下面的伪码来说明:

1、客户端CustomUip
  1.     /// <summary>
  2.     /// 完成对CustomUip对象的封装
  3.     /// </summary>
  4.     public class CustomUip: BaseUip
  5.     {
  6.         /// <summary>
  7.         /// Initializes a new instance of the <see cref="MascyrLoadUip"/> class.
  8.         /// </summary>
  9.         /// <param name="loadingType">Type of the loading.</param>
  10.         public CustomUip()
  11.         {
  12.         }

  13.         /// <summary>
  14.         /// Override the function of GetInterface
  15.         /// </summary>
  16.         /// <returns>the interface</returns>
  17.         protected override object GetInterface()
  18.         {
  19.             IService interfaceService = (IService )Activator.GetObject(typeof(IService), base.ServerUrl + "ServiceLayer");

  20.             return (IService) interfaceService ;
  21.         }
  22.     }
复制代码
2、 客户端CustomUip的基类BaseUip(位于框架中)
  1.     public class BaseUip
  2.     {
  3.         public BaseUip();

  4.         //提供一系列方法
  5.         //..

  6.         protected virtual object GetInterface()
  7.         {
  8.         }
  9.     }
复制代码
3、服务端ServiceLayer
  1.   /// <summary>
  2.     /// 完成对ServiceLayer对象的封装
  3.     /// </summary>
  4.     public class ServiceLayer: ServiceBase, IService
  5.     {
  6.         /// <summary>
  7.         /// Initializes a new instance of the <see cref="MascyrLoadMbr"/> class.
  8.         /// </summary>
  9.         public ServiceLayer()
  10.         {
  11.         }
  12.     }
复制代码
4、 服务端ServiceLayer的基类ServiceBase(位于框架中)
  1. public class ServiceBase
  2. {
  3.     // Fields
  4.     private BaseLogic logic = new BaseLogic(new DefaultManager());

  5.     //一系列其他方法和属性
  6.     // Methods
  7.     public ServiceBase()
  8.     {
  9.         this.set_Logic(this.logic);
  10.     }   

  11.     // Properties
  12.     public BaseLogic Logic
  13.     {
  14.         get
  15.         {
  16.             return this.logic;
  17.         }
  18.         set
  19.         {
  20.             this.logic = value;
  21.         }
  22.     }
  23. }
复制代码
5、服务端ServiceLogic
  1.     /// <summary>
  2.     /// 完成对ServiceLogic对象的封装
  3.     /// </summary>
  4.     public class ServiceLogic: BaseLogic
  5.     {
  6.         /// <summary>
  7.         /// The type of loading data.
  8.         /// </summary>
  9.         private LoadingType loadingType = LoadingType.NONE;     
  10.        
  11.         /// <summary>
  12.         /// Initializes a new instance of the ServiceLogic class.
  13.         /// </summary>
  14.         public ServiceLogic()
  15.         {
  16.           //一些初始化操作
  17.         }

  18.         /// <summary>
  19.         /// Initializes a new instance of the <see cref="ServiceLogic"/> class.
  20.         /// </summary>
  21.         /// <param name="loadingType">Type of the loading.</param>
  22.         public ServiceLogic(LoadingType loadingType)
  23.             : this()
  24.         {
  25.             this.loadingType = loadingType;
  26.         }

  27.         //一系列方法和属性
  28.     }
复制代码
可以看到在 ServiceLogic 有一个含参构造函数:public ServiceLogic(LoadingType loadingType),这个参数是由客户端传来的控制信息,在代码2中使用Activator.GetObject方法获取对象,当使用该对象方法时只会调用ServiceLayer的无参构造函数,那么ServiceLogic的构造函数无法得到LoadingType参数,所以修改代码如下:

6、在IService接口中增加方法 void Register(LoadingType loadingType);

7、 修改CustomUip
  1.     /// <summary>
  2.     /// 完成对CustomUip对象的封装
  3.     /// </summary>
  4.     public class CustomUip: BaseUip
  5.     {
  6.         /// <summary>
  7.         /// Initializes a new instance of the <see cref="CustomUip"/> class.
  8.         /// </summary>
  9.         /// <param name="loadingType">Type of the loading.</param>
  10.         public CustomUip(LoadingType loadingType)
  11.         {
  12.             this.loadingType = loadingType;
  13.         }

  14.         /// <summary>
  15.         /// The loading type.
  16.         /// </summary>
  17.         private LoadingType loadingType = LoadingType.NONE;

  18.         /// <summary>
  19.         /// Override the function of GetInterface
  20.         /// </summary>
  21.         /// <returns>the interface</returns>
  22.         protected override object GetInterface()
  23.         {
  24.             IService interfaceService = (IService )Activator.GetObject(typeof(IService ), base.ServerUrl + "ServiceLayer");            interfaceService .Register(this.loadingType);
  25.             return (IService ) interfaceService ;
  26.         }
  27.     }
复制代码
8、修改ServiceLayer
  1.     /// <summary>
  2.     /// 完成对ServiceLayer 对象的封装
  3.     /// </summary>
  4.     public class ServiceLayer : ServiceBase,IService
  5.     {
  6.         /// <summary>
  7.         /// To store loading type.
  8.         /// </summary>
  9.         private static LoadingType StaticType = LoadingType.NONE;

  10.         /// <summary>
  11.         /// Initializes a new instance of the <see cref="MascyrLoadMbr"/> class.
  12.         /// </summary>
  13.         public ServiceLayer ()
  14.         {
  15.             this.Logic = new ServiceLogic (ServiceLayer.StaticType);
  16.         }

  17.         /// <summary>
  18.         /// Registers the specified loading type.
  19.         /// </summary>
  20.         /// <param name="loadingType">Type of the loading.</param>
  21.         public void Register(LoadingType loadingType)
  22.         {
  23.             ServiceLayer .StaticType = loadingType;
  24.         }
  25.     }
复制代码
通过上述修改可以实现客户端向服务端的参数传递, 在代码8中将LoadingType 声明为Static是因为每当客户端在CustomUip中调用远程对象ServiceLayer的方法时都会初始化 loadingType = LoadingType.NONE;这就导致Register失效,换句话说就是不能保证在new一个对象的同时能执行Register操作,因此声明loadingType 为Static 则能保证只在第一次使用ServiceLayer类型时初始化loadingType 一次,以后不管调用多少次构造函数都不会再去初始化loadingType。

    运行程序后,执行结果完全正确,松了一口气,呵呵。



文/Leo Zhang
TOP