.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。
运行程序后,执行结果完全正确,送了一口气,呵呵。
如果还有其它更好的方法希望各位高人指点。