C/S架构的应用程序,将一些复杂的计算逻辑由客户端转移到服务器端可以改善性能,同时也为了其它方面的控制。.NET Remoting在局域网内调用的性能相当不错。ERP系统中基于.NET Remoting和WCF构建一个应用程序服务器(Application Server)。

分布式应用设计目标:

1  客户端的连接,服务器要能控制。服务器根据授权许可文件的内容,控制客户端并发数。

2  服务器崩溃,客户端要得到通知,挂起当前数据输入操作,当服务器可用时,客户端可自动重新连接 。

3  支持数据加密,对敏感的数据可用加密的端口和通道传输。

4  支持数据压缩,改善数据传输效率,因为要做一个压缩与解压缩动作,性能有所降低。

5 安全控制,应用程序服务器阻止未授权的或未签名的应用程序的连接。

6 客户端向服务器传送大文件,传送图片需要时性能优化

7 服务器端发现错误时,支持堆栈传回客户端以诊断原因。

8 开发和部署简单方便。

先设计服务器与客户端通信的接口,一个简单销售合同数据表的访问接口代码如下所示。

 public interface ISalesContractManager
{
SalesContractEntity GetSalesContract(Guid sessionId, String ContractNo);
SalesContractEntity GetSalesContract(Guid sessionId, String ContractNo, IPrefetchPath2 prefetchPath);
SalesContractEntity GetSalesContract(Guid sessionId, String ContractNo, IPrefetchPath2 prefetchPath, ExcludeIncludeFieldsList fieldList); EntityCollection GetSalesContractCollection(Guid sessionId, IRelationPredicateBucket filterBucket);
EntityCollection GetSalesContractCollection(Guid sessionId, IRelationPredicateBucket filterBucket, ISortExpression sortExpression);
EntityCollection GetSalesContractCollection(Guid sessionId, IRelationPredicateBucket filterBucket, ISortExpression sortExpression, IPrefetchPath2 prefetchPath);
EntityCollection GetSalesContractCollection(Guid sessionId, IRelationPredicateBucket filterBucket, ISortExpression sortExpression, IPrefetchPath2 prefetchPath, ExcludeIncludeFieldsList fieldList); SalesContractEntity SaveSalesContract(Guid sessionId, SalesContractEntity salesContractEntity);
SalesContractEntity SaveSalesContract(Guid sessionId, SalesContractEntity salesContractEntity, EntityCollection entitiesToDelete);
SalesContractEntity SaveSalesContract(Guid sessionId, SalesContractEntity salesContractEntity, EntityCollection entitiesToDelete, string seriesCode); void DeleteSalesContract(Guid sessionId, SalesContractEntity salesContractEntity); bool IsSalesContractExist(Guid sessionId, String ContractNo);
bool IsSalesContractExist(Guid sessionId, IRelationPredicateBucket filterBucket);
int GetSalesContractCount(Guid sessionId, IRelationPredicateBucket filterBucket); SalesContractEntity CloneSalesContract(Guid sessionId, String ContractNo);
void PostSalesContract(Guid sessionId, String ContractNo);
void PostSalesContract(Guid sessionId, SalesContractEntity salesContractEntity);
}

再设计服务实现SalesContractManager,实现上面的接口。

 [CommunicationService("SalesContractManager")]
public class SalesContractManager : ManagerBase, ISalesContractManager
{
public SalesContractEntity GetSalesContract(Guid sessionId, String ContractNo)
{
return GetSalesContract(sessionId, ContractNo, null);
} public SalesContractEntity GetSalesContract(Guid sessionId, String ContractNo, IPrefetchPath2 prefetchPath)
{
return GetSalesContract(sessionId, ContractNo, prefetchPath, null);
}

注意到上面给上面的实现类添加了CommunicationService特性,也就是声明实现类是一个服务。

先来回顾一下最简单的.NET Remoting 客户端与服务器端代码设计模式。

服务器端的设计:

int port = Convert.ToInt32(ConfigurationManager.AppSettings["Port"]);
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = TypeFilterLevel.Full;
IDictionary props = new Hashtable();
props["port"] = port;
TcpChannel channel = new TcpChannel(props, null, provider);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(ERP.BusinessLogic.SalesContractManager), "RemotingService", WellKnownObjectMode.SingleCall);

这里是用代码写死服务类,可以用配置文件增加服务类,也可用以反射的方法增加服务类。

客户端调用的代码如下:

ISalesContractManager  salesContractManager =(IPdmServer)Activator.GetObject(typeof(ISalesContractManager),string.Format("{0}RemotingService", ApplicationServerUrl));
if (salesContractManager == null)
throw new AppException("Sever configuration error");
salesContractManager.SaveSalesContract(guid, salesContract);
 

改善服务器端代码,让服务器主动搜索系统中打上CommunicationService特性的服务类。当新增加服务类型时,框架可自动识别并加载服务类型:

Assembly assembly = typeof(Manager).Assembly;
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
if (type.Namespace == "ERP.BusinessLogic.Managers")
{
string serviceName = string.Empty;
object[] attributes = type.GetCustomAttributes(typeof(CommunicationService), true); if (attributes.Length > 0)
serviceName = type.Name; if (!string.IsNullOrEmpty(serviceName))
{
if (clientActivatedServices.Contains(serviceName))
{
RemotingConfiguration.RegisterActivatedServiceType(type);
}
else if (singletonServices.Contains(serviceName))
{
RemotingConfiguration.RegisterWellKnownServiceType(type, serviceName + ".rem", WellKnownObjectMode.Singleton);
}
else
{
RemotingConfiguration.RegisterWellKnownServiceType(type, serviceName + ".rem", WellKnownObjectMode.SingleCall);
}
}

这样节省了开发人员的服务发布时间。客户端主要方法如下:

instance = ReflectionHelper.CreateObjectInstance<T>(type);

.NET Remoting可识别当前服务类型是否注册过,如果有则会创建一个远程代理,实现向服务器发送请求。

控制客户端并发数:

.NET Remoting支持单件调用模式,客户端不论调用次数,服务器端都只会是相同的一份对象,这样可实现会话Session控制。ERP系统用户登入时,检查服务器登入会话表(Session,本质上是一个DataTable),判断是否已经登入。同时也可以实现并发用户控制,当登入的用户数超过授权许可规定的用户数,可阻止登入。

服务器崩溃,客户端要得到通知,挂起当前数据输入操作,当服务器可用时,客户端可自动重新连接:

.NET Remoting支持客户端服务器订阅模式,服务器端可向客户端发送消息。当服务器进程崩溃,或是无法连接到数据库等原因发生时,需要及时向订阅过的客户端发送消息通知,客户端界面收到通知后需要立即挂起ERP主界面,不允许任何操作。这样可避免用户辛苦的输入数据后,点击保存却连接不上服务器,只好关闭重新输入。

安全控制,应用程序服务器阻止未授权的或未签名的应用程序的连接:

服务器控制客户端的连接调用,在客户端登入时,需要传入当前客户端程序集的版本,签名标识Token,还有系统参数等,服务器端会将这些参数整合在一起,用MD5计算出一个哈希值。只有客户端传入的参数值经过MD5运算后,与服务器中这些相同的参数值MD5运算之后的值,完全相同。服务器端才允许客户端继续登入。

服务器端发现错误时,支持堆栈传回客户端以诊断原因:

上面创建服务器端的代码中,有以下两句是为了实现服务器端堆栈回传到客户端的,参考下面的代码:

BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = TypeFilterLevel.Full;

支持数据加密和数据压缩:

使用自定义的GTCP信道(Channel)通信,此通道支持加密传输和数据压缩传输。

开发和部署简单方便:

Code Smith 6.5的模板会帮助生成ISalesContractManager和SalesContractManager两个类型的源代码,通过上面的讲解知道,只需要给SalesContractManager加上CommunicationService特性即实现服务类的部署。

客户端向服务器传送大文件性能:

为了改善性能,对于文件传输类服务,单独开放一个端口用于文件传输。

解析大型.NET ERP系统 分布式应用模式设计与实现的更多相关文章

  1. 解析大型.NET ERP系统 权限模块设计与实现

    权限模块是ERP系统的核心模块之一,完善的权限控制机制给系统增色不少.总结我接触过的权限模块,以享读者. 1 权限的简明定义 ERP权限管理用一句简单的话来说就是:谁 能否 做 那些 事. 文句 含义 ...

  2. 解析大型.NET ERP系统 业务逻辑设计与实现

    根据近几年的制造业软件开发经验,以我开发人员的理解角度,简要说明功能(Feature)是如何设计与实现的,供参考. 因架构的不同,技术实现上会有所差异,我的经验仅限定于Windows Form程序. ...

  3. 解析大型.NET ERP系统 十三种界面设计模式

    成熟的ERP系统的界面应该都是从模板中拷贝出来的,各类功能的界面有规律可遵循.软件界面设计模式化或是艺术性的创作,我认可前者,模式化的界面客户容易举一反三,降低学习门槛.除了一些小部分的功能界面设计特 ...

  4. 解析大型.NET ERP系统核心组件 查询设计器 报表设计器 窗体设计器 工作流设计器 任务计划设计器

    企业管理软件包含一些公共的组件,这些基础的组件在每个新项目立项阶段就必须考虑.核心的稳定不变功能,方便系统开发与维护,也为系统二次开发提供了诸多便利.比如通用权限管理系统,通用附件管理,通用查询等组件 ...

  5. 解析大型.NET ERP系统架构设计 Framework+ Application 设计模式

    我对大型系统的理解,从数量上面来讲,源代码超过百万行以上,系统有超过300个以上的功能,从质量上来讲系统应该具备良好的可扩展性和可维护性,系统中的功能紧密关联.除去业务上的复杂性,如何设计这样的一个协 ...

  6. 解析大型.NET ERP系统 设计异常处理模块

    异常处理模块是大型系统必备的一个组件,精心设计的异常处理模块可提高系统的健壮性.下面从我理解的角度,谈谈异常处理的方方面面.我的设计仅仅限定于Windows Forms,供参考. 1 定义异常类型 . ...

  7. 解析大型.NET ERP系统 数据审计功能

    数据审计,英语表达是Audit,是追踪数据变化的过程,记录数据变化前后的值,供参考分析.通过设置,ERP可以追踪一个表的所有字段的变化,也可以只记录指定的字段的值变化.欧美企业每年都有独立的审计部门, ...

  8. 解析大型.NET ERP系统 通用附件管理功能

    大型系统具备一个通用的附件管理功能,对于单据中无法清晰表达的字段,用一个附件图片或附件文档表示是最好的方法了.比如物料清单附加一张CAD图纸,销售订单评审功能中附加客户的各种表格,通用附件功能对系统起 ...

  9. 解析大型.NET ERP系统 高质量.NET代码设计模式

    1 缓存 Cache 系统中大量的用到缓存设计模式,对系统登入之后不变的数据进行缓存,不从数据库中直接读取.耗费一些内存,相比从SQL Server中再次读取数据要划算得多.缓存的基本设计模式参考下面 ...

随机推荐

  1. 恋爱虽易,相处不易:当EntityFramework爱上AutoMapper

    剧情开始 为何相爱? 相处的问题? 女人的伟大? 剧情收尾? 有时候相识即是一种缘分,相爱也不需要太多的理由,一个眼神足矣,当EntityFramework遇上AutoMapper,就是如此,恋爱虽易 ...

  2. Python-Jenkins API使用 —— 在后端代码中操控Jenkins

    最近在工作中需要用到在后台代码中触发Jenkins任务的构建,于是想到Jenkins是否有一些已经封装好的API类库提供,用于处理跟Jenkins相关的操作.下面就简单介绍下我的发现. Linux C ...

  3. ASP.NET MVC5+EF6+EasyUI 后台管理系统(68)-微信公众平台开发- 资源环境准备

    系列目录 前言: 本次将学习扩展企业微信公众号功能,微信公众号也是企业流量及品牌推广的主要途径,所谓工欲善其事必先利其器,调试微信必须把程序发布外网环境,导致调试速度太慢,太麻烦! 我们需要准备妥当才 ...

  4. 一起学微软Power BI系列-使用技巧(1)连接Oracle与Mysql数据库

    说起Oracle数据库,以前没用过Oracle不知道,但是这1年用Oracle后,发现真的是想狂吐槽,特别是那个.NET驱动和链接字符串,特别奇葩.总归是和其他数据库不一样,标新立异,不知道为何.另外 ...

  5. 从零开始编写自己的C#框架(28)——建模、架构与框架

    文章写到这里,我一直在犹豫是继续写针对中小型框架的设计还是写些框架设计上的进阶方面的内容?对于中小型系统来说,只要将前面的内容进行一下细化,写上二三十章具体开发上的细节,来说明这个通用框架怎么开发的就 ...

  6. 做一个gulp+webpack+vue的单页应用开发架子

    1.目标 最近项目上的事情不多,根据我自己的开发习惯,决定开发一些简单的开发架子,方便以后事情多的时候直接套用.本文讲的一个gulp+webpack+vue的单页应用架子,想要达到的目的: 可以通过命 ...

  7. Mac OS、Ubuntu 安装及使用 Consul

    Consul 概念(摘录): Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置.与其他分布式服务注册与发现的方案,比如 Airbnb 的 SmartStac ...

  8. Expression Blend创建自定义按钮

    在 Expression Blend 中,我们可以在美工板上绘制形状.路径和控件,然后修改其外观和行为,从而直观地设计应用程序.Button按钮也是Expression Blend最常用的控件之一,在 ...

  9. 使用mybatis-generator在自动生成Model类和Mapper文件

    使用mybatis-generator插件可以很轻松的实现mybatis的逆向工程,即,能通过表结构自动生成对应的java类及mapper文件,可以大大提高工作效率,并且它提供了很多自定义的设置可以应 ...

  10. 简记用ArcGIS处理某项目需求中数据的步骤

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1. 背景 项目需求涉及如下几个步骤: a.矢量化 b.获取范围内要素 ...