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; } } |