基于.Net Remoting的项目总结报告
Based on .Net Remoting Project Summary Report
任务:将一个Windows forms的Client/Server程序改写为基于.Net Remoting的程序,由IIS承载Remote Objects。
1,Windows form的Client/Server系统架构:
包含5个主要的子系统:WinUI(用户界面部分),BusinessRules(业务逻辑部分),DataAccess(数据访问部分),ApplicaitonFrameworks(负责系统参数配置和一些通用class),ExceptionManagement(负责所有系统的异常处理及log)
2,转换为基于.Net Remoting系统的若干思路
本来准备将BusinessRules子系统部署为Remote Objects,标示为SAO(SingleCall/Singleton),但立即发现了一个问题。
因为Business Class几乎都是Fileds成员变量+Public方法组成的,也符合对象技术的基本定义:将数据和操作行为(方法)包装在一起。
如果将Remote Objects部署为SAO-SingleCall,任何对Remote Objects的Public Accessors赋值/调用都会产生新的对象实例,也就是说Remote Objects是无状态的。
如果将Remote Objects部署为SAO-Singleton,显然这样也行不通,因为共享一个Remote Object实例,Fields成员变量会混乱。
虽然可以通过将方法参数直接传入,完全不使用Fileds成员变量,这样就可以解决上述问题,但是这样存在很多问题:
(1)首先,程序修改工作量巨大,我最讨厌这种没有创造性的重复工作。
(2)在Class中不使用Fileds成员变量,我觉得这样违背了对象技术的基本定义:将数据和操作行为(方法)包装在一起。另外,也丧失了使用Fileds成员变量的好处,使程序的可读性及可维护性下降。
(3)设想方法中包括N多的参数,并且多个方法都是类似的参数列表,显然不能接受。或许有人提出可以采用参数类/Entity Class来传参数,这样会产生很多的参数类,并且也违背对象技术的基本定义。
***
这样,可以考虑将Remote Objects部署为CAO(Client-Activated Object),CAO对象基本上和正常的.Net Object一样。当在Client端发出创建实例对象的请求(通过Activator.CreateInstance() or new关键字),一个激活消息将发送到Server端,然后Client端的Proxy Object并获取一个指向Remote Object的objRef对象。
CAO对象是有状态对象(stateful object),Client端对Remote Object的属性赋值后,可以在下一次正确读取,并且CAO对象在每一次方法调用都保持状态信息。
为了减少对WinUI/BusinessRules子系统的修改,显然采用CAO对象的Direct/Transparent Creation方法,具体可以参考《MarshalByRefObjects远程对象及其调用方法》,其中也有一些drawback需要注意。
我认为采用CAO来部署Remote Objects应该是可行的,不过我具体没有测试过。如果有人测试过,希望能share这方面的体会。
***
具体项目中,因为DataAccess子系统基于SqlHelper.cs类(Microsoft Data Access Application Block v2.0),无法直接将SqlHelper.cs部署为Remote Objects,前面的posting《尝试RemotingSqlHelper的若干问题》有详细的讨论。
虽然可以将SqlHelper.cs改写为可以部署为Remote Objects对象,我也的确做了一些尝试。正是由于《尝试RemotingSqlHelper的若干问题》提及的一些局限,同时也避免对BusinessRules子系统的大量修改。
最终尝试了如下的方法,并且在实际系统中验证是可行的。
3,基于.Net Remoting 的系统架构:
具体思路是这样的:
(1)将原来的DataAccess子系统部署为Remote Server,并改为RemoteDataAccess子系统,由于SqlHelper.cs不能直接部署为Remote Object,因此在外面包装一个RemotingSqlHelper Class,将RemotingSqlHelper部署为Remote Object。
(2)增加新的DataAccess子系统,该子系统负责接受来自BusinessRules子系统的调用,因此需要伪装为SqlHelper.cs的模样,否则BusinessRules子系统需要修改的地方就多了。
(3)并且新的DataAccess子系统并不直接访问SQL Server Database,而是访问RemotingDataAccess子系统中的RemotingSqlHelper Class。
其中需要注意的问题:
(1)SqlConnection对象以connection string代替,我一直习惯使用connection string,因此这个也省事了。
(2)SqlParameter对象-我定义了一个可序列化的Class,在DataAccess端,将SqlParameter对象转为可序列化的Class。然后在RemotingSqlHelper class中还原为SqlParameter对象,并调用真正的SqlHelper class。
这样,整个转换过程就大功告成了。其中BusinessRules子系统需要修改的地方很少,几乎不用改。
不过,当有大量数据记录从Server端传递到Client端时,比较明显感觉到性能受到影响。Remote Server为IIS,Channel为HTTP(IIS不支持TCP Channel),Formatter为Binary。
在此,也感谢一些friends对上述Posts的回复/评论,对我有不少启发。
当然,如果设计一个全新的基于.Net Remoting的系统,就不要费这么多周折了。