Leo Zhang

A simple man with my own ideal

使用.NET Remoting 技术并采用服务端SingleCall激活方式下如何实现客户端向服务端传递参数

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

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

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

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

 1、客户端CustomUip

    /// <summary>
    
/// 完成对CustomUip对象的封装
    
/// </summary>
    public class CustomUip: BaseUip
    {
        
/// <summary>
        
/// Initializes a new instance of the <see cref="MascyrLoadUip"/> class.
        
/// </summary>
        
/// <param name="loadingType">Type of the loading.</param>
        public CustomUip()
        {
        }

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

            
return (IService) interfaceService ;
        }
    }

 

2、 客户端CustomUip的基类BaseUip(位于框架中)

 

    public class BaseUip
    {
        
public BaseUip();

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

        
protected virtual object GetInterface()
        {
        }
    }  

 

 3、服务端ServiceLayer

 

    /// <summary>
    
/// 完成对ServiceLayer对象的封装
    
/// </summary>
    public class ServiceLayer: ServiceBase, IService
    {
        
/// <summary>
        
/// Initializes a new instance of the <see cref="MascyrLoadMbr"/> class.
        
/// </summary>
        public ServiceLayer()
        {
        }
    }

 

 

4、 服务端ServiceLayer的基类ServiceBase(位于框架中)

 

public class ServiceBase
{
    
// Fields
    private BaseLogic logic = new BaseLogic(new DefaultManager());

    
//一系列其他方法和属性
    
// Methods
    public ServiceBase()
    {
        
this.set_Logic(this.logic);
    }    

    
// Properties
    public BaseLogic Logic
    {
        
get
        {
            
return this.logic;
        }
        
set
        {
            
this.logic = value;
        }
    }
}

 

5、服务端ServiceLogic     

    /// <summary>
    
/// 完成对ServiceLogic对象的封装
    
/// </summary>
    public class ServiceLogic: BaseLogic
    {
        
/// <summary>
        
/// The type of loading data.
        
/// </summary>
        private LoadingType loadingType = LoadingType.NONE;      
        
        
/// <summary>
        
/// Initializes a new instance of the ServiceLogic class. 
        
/// </summary>
        public ServiceLogic()
        {
           
//一些初始化操作
        }

        
/// <summary>
        
/// Initializes a new instance of the <see cref="ServiceLogic"/> class.
        
/// </summary>
        
/// <param name="loadingType">Type of the loading.</param>
        public ServiceLogic(LoadingType loadingType)
            : 
this()
        {
            
this.loadingType = loadingType;
        }

        
//一系列方法和属性
    }

 

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

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

7、 修改CustomUip

    /// <summary>
    
/// 完成对CustomUip对象的封装
    
/// </summary>
    public class CustomUip: BaseUip
    {
        
/// <summary>
        
/// Initializes a new instance of the <see cref="CustomUip"/> class.
        
/// </summary>
        
/// <param name="loadingType">Type of the loading.</param>
        public CustomUip(LoadingType loadingType)
        {
            
this.loadingType = loadingType;
        }

        
/// <summary>
        
/// The loading type.
        
/// </summary>
        private LoadingType loadingType = LoadingType.NONE;

        
/// <summary>
        
/// Override the function of GetInterface
        
/// </summary>
        
/// <returns>the interface</returns>
        protected override object GetInterface()
        {
            IService interfaceService 
= (IService )Activator.GetObject(typeof(IService ), base.ServerUrl + "ServiceLayer");            interfaceService .Register(this.loadingType);
            
return (IService ) interfaceService ;
        }
    }

 

8、修改ServiceLayer    

    /// <summary>
    
/// 完成对ServiceLayer 对象的封装
    
/// </summary>
    public class ServiceLayer : ServiceBase,IService
    {
        
/// <summary>
        
/// To store loading type.
        
/// </summary>
        private static LoadingType StaticType = LoadingType.NONE;

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

        
/// <summary>
        
/// Registers the specified loading type.
        
/// </summary>
        
/// <param name="loadingType">Type of the loading.</param>
        public void Register(LoadingType loadingType)
        {
            ServiceLayer .StaticType 
= loadingType;
        }
    }


     通过上述修改可以实现客户端向服务端的参数传递, 在代码8中将LoadingType 声明为Static是因为每当客户端在CustomUip中调用远程对象ServiceLayer的方法时都会初始化 loadingType = LoadingType.NONE;这就导致Register失效,换句话说就是不能保证在new一个对象的同时能执行Register操作,因此声明loadingType 为Static 则能保证只在第一次使用ServiceLayer类型时初始化loadingType 一次,以后不管调用多少次构造函数都不会再去初始化loadingType。

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

    如果还有其它更好的方法希望各位高人指点。 

 

 


posted on 2009-07-02 15:21  Leo Zhang  阅读(3230)  评论(11编辑  收藏  举报

导航