.NET Romoting 学习总结(三)—— Remoting技术之设计模式实现代码安全

 此文章转载自Sharping's Nonsense的http://www.sharping.net/PermaLink,guid,9cf3f46f-a590-40a8-933d-7179e473c91d.aspx

引言 : 如果说结构化的设计是软件工程里的里程碑、面向对象的分析设计是软件工程新纪元的话,那么敏捷开发、极限编程、驱动编程可以说是软件工程里的新大陆,结构化的程序设计对软件危机进行了最大限度的缓和,面向对象编程适应了需求的易变性,那么敏捷开发则是把软件复用技术体现的淋漓尽致。本篇我主要讲述Remoting中的代码分离存放问题,为什么引出这么一段软件工程的理论,主要是为了说明敏捷开发的价值,本人恰恰是敏捷开发的信徒,而设计模式正是敏捷开发的精髓所在,在看本篇内容以前,你需要具备以下前置知识:
      1、软件设计模式之工厂模式
      2、抽象、接口的概念

 OK,开始正题,首先引出问题(由于今天时间充裕,我讲解尽可能详尽点,当然这也是为了整理清爽自己的思路,考试复习的差不多了,嘿嘿),如果细心的读者会发现前面两篇中有一点小问题,那就是我们所讲的远程对象在客户端进行调用时必须有个类型申明,看代码:

      a、WellKnown激活模式:
      

ServerRemoteObject.ServerObject serverObj = (ServerRemoteObject.ServerObject)
Activator.GetObject(
typeof(ServerRemoteObject.ServerObject), "tcp://localhost:8080/ServiceMessage");


      b、客户端激活模式:
     

RemotingConfiguration.RegisterActivatedClientType(
typeof(ServerRemoteObject.ServerObject),
"tcp://localhost:8080/ServiceMessage");
ServerRemoteObject.ServerObject serverObj = new ServerRemoteObject.ServerObject();

ServerRemoteObject.ServerObject serverObj = Activator.CreateInstance(
typeof(ServerRemoteObject.ServerObject),objs,attrs);


       看到了吧,三种获得远程对象方式有一个共同点,那就是ServerRemoteObject.ServerObject serverObj =...... 这个有什么问题呢?这样的语句必须是知道ServerRemoteObject.ServerObject类型的前提下才能通过编译,换句话说就是本地要有ServerObject 这个一个类,那就注定远程对象在客户端也必须保存ServerObject 类的代码,假如ServerObject 类的代码文件被编译成DLL文件的话,这个DLL在客户端和服务端都是同时要有的,这样就就造成了代码元数据的的紧密耦合和安全隐患,为了消除这种不利的因素,我们必须想办法删除客户端的这个DLL,也就客户端不保存ServerObject 类的代码。这就是今天要探讨的主题。
      问题如何解决呢?学过设计模式的同学大概和我一样吧,似乎有点什么主意又似乎不好实现,刚开始我也这样,后来在高手的指点下有了头绪,设计模式中有个工厂模式吧,用他来解决这个问题最合适不过(关于设计模式请自己查阅相关资料),不过这个方法稍微要绕点弯,我们继续,先以SingleCall模式为例。
      首先我们给ServerObject 类加个工厂类,代码如下

     

public class ServerObjFactory:MarshalByRefObject,IServerObjFactory
{
public IServerObject CreateInstance()
{
return new ServerObject();
}
}

      为了代码的扩展性,我们把这个工厂抽象成接口:
       

public interface IServerObjFactory
{
ServerObject CreateInstance();
}

      这样我们在注册远程对象的时候不再注册ServerObject类,而是注册ServerObjFactory类(代码略,参阅第一篇)客户端我们保存这个工厂接口,这样在客户端获得这个工厂类:

      

ServerRemoteObject.IServerObjFactory ijFactory = (ServerRemoteObject.IServerObject)
Activator.GetObject(
typeof ServerRemoteObject.IServerObjFactory), "tcp://localhost:8080/ServiceMessage");


   
      然后:  ServerRemoteObject.ServerObjFactory serverObj = ijFactory.CreateInstance()
      哎呀,注意这里“ServerRemoteObject.ServerObjFactory”,还是要有ServerObjFactory类,这样客户端还是要存放ServerObjFactory 类代码呀,不过似乎快成功了,开动你的大脑,怎么消除这个该死ServerObjFactory呢?有了,我们再来一次抽象,在服务端为ServerObjFactory抽象一个接口:
    

public interface IServerObject
{
Person GetPersonInfo(string name,string sex,int age);
}

    稍微改一下IServerObjFactory接口:
     

public interface IServerObjFactory
{
IServerObject CreateInstance();
}

      把他们编译成DLL放在客户端和服务端,这样客户端这样获取对象:
      先获得工厂接口:
      

ServerRemoteObject.IServerObjFactory serverFactory =
(ServerRemoteObject.IServerObjFactory) Activator.GetObject(
typeof(ServerRemoteObject.IServerObjFactory),
"tcp://localhost:8080/ServiceMessage");


      然后:ServerRemoteObject.IServerObject serverObj = serverFactory.CreateInstance();
      哈哈,小样的,消除ServerObjFactory了吧,客户端完全没有ServerObject类了,只有两个接口,“阴谋”成功完成。其实上面这种双层抽象是针对客户端激活模式使用的,他虽然代码中采用SingleCall模式激活,但是每次获得的对象是一个工厂,也就是说每次服务端为客户端创建的都是不同的实例,他从逻辑上实现的客户端的激活模式。可以说是一种客户端激活模拟。

      而对于WellKnown模式,方法就简单了一些,服务端如下(原理不做解释,比上面的简单多了):

      

public interface IServerObject
{
Person GetPersonInfo(string name,string sex,int age);
}

public class ServerObject:MarshalByRefObject,IServerObject
{ ......}


      客户端仅存放接口就OK,要注意的是接口的名字空间和服务端对象的名字空间必须一致,原理不做阐述,可查阅MSDN。
      WellKnown和客户端激活的抽象为什么会有这样差异呢其实是他们的实现原理不一样,如果你自己阅读第一篇文章就因该知道,WellKnown是为每个客户端创建相同的实例,客户端模式是创建不同的实例,关于这个就说这么多,不理解可以回顾我的第一篇文章。

      今天就问题我觉得写的很清楚了,最后提一点,上面说的阴谋其实实现方式还有一些,可以到网上找,篇幅有限,这里就介绍个人觉得比较使用的两种。

      篇外:有句话叫做:工欲善其事,必先利其器。虽然前两篇已经对Rmoting技术做了充分讲述,但是单单掌握最基本的实现方法在实际应用中是远远不够的,一些细节问题才是最值得我们思索的。启发式的思维历练才能使你成为真正的高手,文章讲到这里相信你对Remoting的感觉应该是"芙蓉出水"了,当然我还没打算收笔,接下来是一些更细节的问题研究,如果你认为“一招鲜能吃遍天”的话你不用再继续看下去了,后面所写的只是本人实际应用中遇到的问题。

你可能感兴趣的:(技术文章)