.NET Remoting技术是构建企业级分布式应用的很好选择,(个人感觉随.Net Framework 3.0推出的WCF更加强大和易用),我们的项目采用服务端SingleCall方式来激活远程对象,在这种方式下最大的特点是当你new一个对象出来的时候并不会调用相应类型的构造函数,只有当你使用该类型的方法时才会调用构造函数,为换句话说就是SingleCall方式下不保存对象状态,这样做的好处是客户端不会长时间占用服务器资源,但是也就造成不能共享状态。
最近让我苦恼的一件事是:我想在客户端生成远程对象的时候传一个参数进去,但是服务端激活方式Singleton和SingleCall在生成远程对象时只支持调用无参的默认构造函数,所以在调用带参数的构造函数上我就死了心(不知道各位高手能不能搞定),下面我还原一下我的场景:
项目采用多层架构,将各个base基类组织起来实现了这个架构,它相当于一个基础框架,以后的应用开发以这个架构为基础,在应用开发时假设框架是稳定的不可变的。
客户端中生成远程对象的层可以叫做CustomUip,它有个base基类BaseUip,服务端中最接近客户端的层可以叫做ServiceLayer,它也有个base基类BaseService,和一个对外接口IService,客户端通过该接口来获取远程对象,通过ServiceLayer可以使用业务逻辑层ServiceLogic,可以用下面的伪码来说明:
1、客户端CustomUip
/// 完成对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 BaseUip();
// 提供一系列方法
// ..
protected virtual object GetInterface()
{
}
}
3、服务端ServiceLayer
/// 完成对ServiceLayer对象的封装
/// </summary>
public class ServiceLayer: ServiceBase, IService
{
/// <summary>
/// Initializes a new instance of the <see cref="MascyrLoadMbr"/> class.
/// </summary>
public ServiceLayer()
{
}
}
4、 服务端ServiceLayer的基类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
/// 完成对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
/// 完成对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
/// 完成对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。
运行程序后,执行结果完全正确,送了一口气,呵呵。
如果还有其它更好的方法希望各位高人指点。