
魏琼东,系统分析师、系统架构师、高级项目经理。有17年开发和管理经验,擅长企业软件过程改进、系统分析与架构设计、.NET平台架构技术、SQL Server/ORACLE数据库技术、分布式架构体系及高性能并行计算,尤其对中小软件企业的企业级软件研发管理体系有着深入的研究与应用。
我的博客即将入驻“云栖社区”,诚邀技术同仁一同入驻。
一、平台简介 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、账号加密、验证算法的替换 AgileEAS.NET SOA 中间件平台一直使用内置的密码加密算法,随着很多使用者提出,为了系统的安全需要,希望能提供一策略,用自己的加密算法算法替换AgileEAS.NET SOA 中间件平台内置的密码加密算法。 为了实现这种需求,我们定义了密码提供者接口IPasswordProvider: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace EAS.Explorer { /// <summary> /// 用户密码提供者接口。 /// </summary> public interface IPasswordProvider { /// <summary> /// 加密指定的密码。 /// </summary> /// <param name="password">要加密的密码。</param> ///<returns>加载后的密码。</returns> byte[] Encrypt(string password); /// <summary> /// 验证给定的密码是否和指定的密钥匹配。 /// </summary> /// <param name="password">要验证的密码。</param> /// <param name="key">要验证的密钥。密钥的长度为64个字节。</param> /// <returns>如果可以通过指定的密钥生成和key相匹配的密钥,则返回true;否则返回false。</returns> bool Verify(string password, byte[] key); } } IPasswordProvider接口之中定义一个两个方法,Encrypt方法用于生成密码对应的加算后的密码,Verify方法用于对明文密码和加密后的密码进行比对。 三、实现和配置 下面我就以某一个朋友的实现为例,他想把密码加密算法换成md5,咱们来看看具体的做法。 首先要建一个类库项目,并且引用EAS.Explorer、EAS.MicroKernel、EAS.Explorer程序集,建立一个类并实现IPasswordProvider接口,项目代码结构如下: MD5Password代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Web; using EAS.Explorer; using System.Security.Cryptography; using System.Text; using System.IO; using System.Text; namespace My.Passwords { public class MD5Password : IPasswordProvider { #region IPasswordProvider 成员 public byte[] Encrypt(string password) { byte[] result = Encoding.Default.GetBytes(password.Trim()); MD5 md5 = new MD5CryptoServiceProvider(); byte[] output = md5.ComputeHash(result); byte[] buffer = new byte[64]; Buffer.BlockCopy(output, 0, buffer, 0, 16); return buffer; } public bool Verify(string password, byte[] key) { byte[] result = Encoding.Default.GetBytes(password.Trim()); MD5 md5 = new MD5CryptoServiceProvider(); byte[] output = md5.ComputeHash(result); byte[] buffer = new byte[64]; Buffer.BlockCopy(output, 0, buffer, 0, 16); return EAS.Security.Bytes.Equals(buffer, key); } #endregion } } 编译代码得到My.Passwords.dll,然后修改相关的配置文件,如EAS.SOA.Server.exe.config、Web.Config,加入如下配置: <!--密码算法--> <object name="PasswordProvider" assembly="My.Passwords" type="My.Passwords.MD5Password" LifestyleType="Singleton" /> 结束配置。 四、例子代码下载 本文涉及的领域模型设计器代码插件例子,源代码已经一并放在了AgileEAS.NET SOA 中间件的最新版之中,请大请通过AgileEAS.NET SOA 中间件平台官方网站下载,或者通过以下方式下载: 直接下载:AgileEAS.NET SOA 5.2 下载,http://112.74.66.105/downloads/eas/agileeas.net.5.rar。 SVN更新:https://112.74.66.105/svn/eas/5.0,登录用户:eas,密码eas. AgileEAS.NET SOA 中间件平台管理员:Administrator,登录密码sa。 直接下载的压缩包可能会有一定的时间差,即有可能不一定是最新版本,建议大家都通过SVN下载最新版本。 五、联系我们 为了完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台了开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 技术团队成员都是合作多年的老朋友,因为这个平台是免费的,我们的营运开支主要靠为客户提供咨询服务所得,我们都是因为程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友和一直支持我们工作的客户、朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381 AgileEAS.NET QQ群: 113723486(AgileEAS SOA 平台)/上限2000人 199463175(AgileEAS SOA 交流)/上限2000人 116773358(AgileEAS.NET SOA 平台)/上限2000人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。 我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan
一、Java安装 1、安装包准备: 首先到官网下载jdk,http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html,我下载jdk-7u79-linux-x64.tar.gz,下载到主目录 2、解压安装包 通过终端在/usr/local目录下新建java文件夹,命令行: sudo mkdir /usr/local/java 然后将下载到压缩包拷贝到java文件夹中,命令行: 进入jdk压缩包所在目录 cp jdk-7u79-linux-x64.tar.gz /usr/local/java 然后进入java目录,命令行: cd /usr/local/java 解压压缩包,命令行: sudo tar xvf jdk-7u79-linux-x64.tar.gz 然后可以把压缩包删除,命令行: sudo rm jdk-7u79-linux-x64.tar.gz 3、设置jdk环境变量 这里采用全局设置方法,就是修改etc/profile,它是是所有用户的共用的环境变量 sudo vi /etc/profile 打开之后在末尾添加 export JAVA_HOME=/usr/local/java/jdk1.7.0_79 export JRE_HOME=/usr/local/java/jdk1.7.0_79/jre export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH export PATH=$JAVA_HOME/bin: $PATH 使profile生效 source /etc/profile 4、检验是否安装成功 在终端 java -version 显示如下 java version "1.7.0_79"Java(TM) SE Runtime Environment (build 1.7.0_79-b15)Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode) PS:后来发现直接rpm包jdk-7u79-linux-x64.rpm桌面双击安装也OK,^_^ 二、scala2.11.4安装 1、安装包准备: 首先到官网下载scala,http://www.scala-lang.org/,下载scala-2.11.4.tgz,并复制到/usr/bib 2、解压安装包 tar -zxf scala-2.11.4.tgz 3、设置scala环境变量 这里采用全局设置方法,就是修改etc/profile,它是是所有用户的共用的环境变量 sudo vi /etc/profile 打开之后在末尾添加 export SCALA_HOME=/usr/lib/scala-2.11.4export PATH=$SCALA_HOME/bin:$PATH 使profile生效 source /etc/profile 4、检验是否安装成功 在终端 scala -version 显示如下 Scala code runner version 2.11.4 -- Copyright 2002-2013, LAMP/EPFL 三、hadoop2.3安装 1、安装包准备: hadoop版本有点混乱,除了http://hadoop.apache.org/有众多版本之外,还有Cloudera公司的CDH版本,请从观望下载hadoop-2.3.0.tar.gz或者下载CDH版本hadoop-2.3.0-cdh5.0.0.tar.gz,本文环境是在hadoop-2.3.0-cdh5.0.0.tar.gz之上建立。 2、解压安装包 下载安装包之后复制到/usr目录。 tar -zxf hadoop-2.3.0-cdh5.0.0.tar.gz 解压后生成hadoop-2.3.0-cdh5.0.0,重命名为hadoop-2.3.0。 3、配置环境 这里采用全局设置方法,就是修改etc/profile,它是是所有用户的共用的环境变量 sudo vi /etc/profile 打开之后在末尾添加 export HADOOP_HOME=/home/zero/hadoop/hadoop-2.3.0 export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin 使profile生效 source /etc/profile 3、建立hadoop用户 useradd hadoop passwd hadoop 3、配置SSH免登录 su hadoop //切换到hadoop用户目录下 ssh-keygen-t rsa(一路回车 生成密钥) cd/home/hadoop/.ssh/ scp id_rsa.pub hadoop@slave1:/home/hadoop/.ssh/ mv id_rsa.pub authorized_keys 四、spark1.3.1安装 1、安装包准备: spark官网下载spark-1.3.1-bin-hadoop2.3.tgz。 2、解压安装包 下载安装包之后复制到/usr目录。 tar -zxf spark-1.3.1-bin-hadoop2.3.tgz 解压后生成spark-1.3.1-bin-hadoop2.3,重命名为spark-1.3.1-hadoop2.3。 3、配置环境 这里采用全局设置方法,就是修改etc/profile,它是是所有用户的共用的环境变量 sudo vi /etc/profile 打开之后在末尾添加 export SPARK_HOME=/usr/spark-1.3.1-hadoop2.3export PATH=$SPARK_HOME/bin:$PATH 使profile生效 source /etc/profile 4、配置环境 这里采用全局设置方法,就是修改etc/profile,它是是所有用户的共用的环境变量 sudo vi /etc/profile 打开之后在末尾添加 export SPARK_HOME=/usr/spark-1.3.1-hadoop2.3export PATH=$SPARK_HOME/bin:$PATH 使profile生效 source /etc/profile 配置Spark环境变量 cd $SPARK_HOME/confcp spark-env.sh.template spark-env.sh vi spark-env.sh 添加以下内容: export JAVA_HOME=/usr/local/java-1.7.0_79 export HADOOP_HOME=/usr/hadoop-2.3.0 export HADOOP_CONF_DIR=/etc/hadoop/conf export SCALA_HOME=/usr/lib/scala-2.11.4 export SPARK_HOME=/usr/spark-1.3.1-hadoop2.3 export SPARK_MASTER_IP=127.0.0.1 export SPARK_MASTER_PORT=7077 export SPARK_MASTER_WEBUI_PORT=8099 export SPARK_WORKER_CORES=3 //每个Worker使用的CPU核数 export SPARK_WORKER_INSTANCES=1 //每个Slave中启动几个Worker实例 export SPARK_WORKER_MEMORY=10G //每个Worker使用多大的内存 export SPARK_WORKER_WEBUI_PORT=8081 //Worker的WebUI端口号 export SPARK_EXECUTOR_CORES=1 //每个Executor使用使用的核数 export SPARK_EXECUTOR_MEMORY=1G //每个Executor使用的内存 export SPARK_CLASSPATH=/usr/spark-1.3.1-hadoop2.3/lib/sequoiadb-driver-1.12.jar:/usr/spark-1.3.1-hadoop2.3/lib/spark-sequoiadb_2.11.2-1.12.jar //使用巨衫数据库export SPARK_CLASSPATH=$SPARK_CLASSPATH:$CLASSPATHexport LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$HADOOP_HOME/lib/nativ 配置Slave cp slaves.template slavesvi slaves 添加以下内容:localhost 5、启动Spark Master cd $SPARK_HOME/sbin/./start-master.sh 6、启动Spark Slave cd $SPARK_HOME/sbin/./start-slaves.sh
一、关于NoSQL的项目需求 这些年在做AgileEAS.NET SOA 中间件平台的推广、技术咨询服务过程之中,特别是针对我们最熟悉的医疗行业应用之中,针对大数据分析,大并发性能的需求,我们也在慢慢的引用NoSQL技术来满足数据分析与性能等多方面的需要,也进一步完善我们的SOA基石架构风格: 在早些年,对NoSQL不是很了解这前,后端数据存储都是存储的单一的关系数据库之上,但是在很多时间,这并不是最优的,比如在医疗用户之中针对一个病人的相关数据展示,及相关性分析,关于数据库就不是最优的,另外一个,电子病历系统的之中的结构化/半结构化病历文档的存储、检索,以及更高级的应用,结构化病历数据挖掘,之前使用关系数据库存储或者使用文件存储,很难发挥病历数据的科研和统计、分析需求。 在目前我们的医疗信息化应用之中,我们针对这两部分数据都引入了NoSQL存储,针对住院患者的领域相关性数据==》即病人聚合根对象相关数据,我们即在关系数据库以多表存储病人数据以及病人相关的医嘱、费用、检验、检查、护理等相关信息,同时我们也在NoSQL数据库存储患者的聚合根对象: 在NoSQL数据库之中的存储: 另外在电子病历应用之中,病历文档也是直接存入NoSQL之中。 在接触巨杉数据库之前,我们一直使用MongoDB这款NoSQL产品,这是一款广为人知的NoSQL产品,使用者众多,C#的驱动也非常完善,案例也比比皆时。 三、关于巨杉(sequoiadb)数据库 巨杉数据库是国人开发的一款企业级NoSQL数据库,目前已开源,官网http://www.sequoiadb.com/。 初次了解到巨杉(sequoiadb)数据还是源于一个客户,因为我们项目一直使用MongoDB,客户就向我们提到巨杉(sequoiadb)数据库,说国内有人开发了这么一个NoSQL数据库,并且在平安银行有过成功应用,并且因为是国人开发,所以应该相比较MongoDB,应该能得到官方的支持,客户也和巨杉(sequoiadb)官方的人有过接触,官方也答应可以做一些支持。 根据网上所公开的一些信息,巨杉(sequoiadb)数据库和MongoDB非常的接近,都是文档型数据库,同样的设计思路,集合和文档,同样的文档格式,Json/Bson。 根据最近一段时间的了解和完善C#驱动的过程来说,相对MongoDB,巨杉(sequoiadb)提供了更加方便的图形化部署和简单的Web管理界面: 以下是SequoiaDB与MongoDB及其他NoSQL数据的功能对比: 比较特别是的SequoiaDB支持事务和SQL语法,当然了,这两点在目前情况下我们都使用使用过。 四、关于SequoiaDB的C#驱动 SequoiaDB官方提供C、C++、JAVA、C#、php、Python驱动以及REST架构风格的接口,据官方的说法是Java的驱动很成熟,但是C#的驱动很简单,只能支持最基本的Bson格式的接口,如下代码: // Insert BsonDocument insertor = new BsonDocument(); insertor.Add("Last Name", "Lin"); insertor.Add("First Name", "Hetiu"); insertor.Add("Address", "SYSU"); BsonDocument sInsertor = new BsonDocument(); sInsertor.Add("Phone", "10086"); sInsertor.Add("EMail", "hetiu@yahoo.com.cn"); insertor.Add("Contact", sInsertor); ObjectId insertID = (ObjectId)coll.Insert(insertor); Assert.IsNotNull(insertID); // Update DBQuery query = new DBQuery(); BsonDocument updater = new BsonDocument(); BsonDocument matcher = new BsonDocument(); BsonDocument modifier = new BsonDocument(); updater.Add("Age", 25); modifier.Add("$set", updater); matcher.Add("First Name", "Hetiu"); query.Matcher = matcher; query.Modifier = modifier; coll.Update(query); // Query DBCursor cursor = coll.Query(query); Assert.IsNotNull(cursor); BsonDocument bson = cursor.Next(); Assert.IsNotNull(bson); Assert.IsTrue(bson["First Name"].AsString.Equals("Hetiu")); Assert.IsTrue(bson["Age"].AsInt32.Equals(25)); // Delete BsonDocument drop = new BsonDocument(); drop.Add("Last Name", "Lin"); coll.Delete(drop); query.Matcher = drop; cursor = coll.Query(query); Assert.IsNotNull(cursor); bson = cursor.Next(); Assert.IsNull(bson); 集合查询: for (int i = 0; i < 10; ++i) { string date = DateTime.Now.ToString(); BsonDocument insertor = new BsonDocument(); insertor.Add("operation", "Query"); insertor.Add("date", date); coll.Insert(insertor); } BsonDocument matcher = new BsonDocument(); DBQuery query = new DBQuery(); matcher.Add("operation", "Query"); query.Matcher = matcher; query.ReturnRowsCount = 5; query.SkipRowsCount = 5; DBCursor cursor = coll.Query(query); Assert.IsNotNull(cursor); int count = 0; while (cursor.Next() != null) { ++count; BsonDocument bson = cursor.Current(); Assert.IsNotNull(bson); } Assert.IsTrue(count == 5); 官方的代码有点简单,这不符合我们写代码的风格,目前业务系统大量的使用对象操作和Linq处理,原始的Bson接口,这个不科学。 五、完善改造SequoiaDB的C#驱动 即然官方的驱动太简单,不支持对象处理,也不支持Linq,很不科学,那么应该怎么办呢,其实第一个观点当然是放弃,我们原本使用MongoDB跑的好好的,为什么要给自己找事呢,但是出于项目运维的观点,以及支持国人产品的想法,最终决定自己完善和写一个。 那么如何来写呢,当然是他山之石,可以攻玉,因为之前做MongoDB开发,原始的驱动配置我们的ORM跑起来也有一些问题,最早我们使用的非MongoDB的官方驱动,而是第三方驱动samus,不支持Decimal类型,但是我们项目之中有大量的Decimal类型,那么办呢,修改驱动,后来我们又换成了MongoDB的官方驱动,因为XmlIgnore标签和Id映射的问题也认真的读过MongoDB的官方驱动,对MongoDB的C#驱动比较熟悉。 所以完善SequoiaDB的C#的思路就变成了结合SequoiaDB的原始驱动和MongoDB的官方驱动,提供一个类似于MongoDB驱动的操作风格的驱动,在SequoiaDB驱动的基础上提供了,直接操作C#对象的方案和支持Linq进行查询、修改、删除的功能。 经本人完善修改之后的驱动的操作风格如下: Sequoiadb sdb = new Sequoiadb("192.168.23.57:50000"); sdb.Connect("", ""); //求集合空间。 var cs = sdb.GetCollecitonSpace("dbo"); //求集合。 var coll = cs.GetCollection<HFareDetail>(); //执行数据插入。 List<HFareDetail> vList =null; using (AgileHIS.Entities.DbEntities db = new AgileHIS.Entities.DbEntities()) { vList = db.HFareDetails.ToList(); //插入。 foreach (var item in vList) { coll.Insert(item); } System.Console.WriteLine(string.Format("insert {0} records", vList.Count)); System.Console.ReadLine(); } //按条件修改某一条数据的几个属性值。 var v1 = vList.FirstOrDefault(); v1.Name = string.Empty; v1.Cash = decimal.Zero; coll.Update(v1, p => p.ID == v1.ID); //按条件指量修改,指定某几个必,其他属性全部置空。 coll.Update(p => new HFareDetail { Cash = decimal.Zero, Name = string.Empty, Price = decimal.Zero }, p => p.ChargeTime >DateTime.Now.AddDays(-1)); //依据条件删除 coll.Delete(p => p.ChargeTime > DateTime.Now.AddDays(-1)); //求Count int count = coll.AsQueryable<HFareDetail>() .Where(p => p.SourceID==0) .Count(); //Linq查询Take\Skip。 var vList2 = coll.AsQueryable<HFareDetail>() .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .Skip(10).Take(1000) .ToList(); System.Console.WriteLine(string.Format("query {0} records", vList.Count)); //Linq查询过。 var vFare = coll.AsQueryable<HFareDetail>() .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .FirstOrDefault(); System.Console.WriteLine(vFare); //Linq\聚合运算,目前因为测试驱动报错,暂未实现 var sum = coll.AsQueryable<HFareDetail>() .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .Sum(p => p.Cash); System.Console.ReadLine(); 看看,代码是不是很清爽,很方便了呢,没有了bson,只有对象,Linq。 六、SequoiaDB、MongoDB与AgileEAS.NET SOA整合 AgileEAS.NET SOA之前只支持MongoDB,最近要支持SequoiaDB,我们就得考虑对原有代码的兼容,或者说,更希望自己的医疗系统能够在业务上同时支持MongoDB和SequoiaDB,达到使用环境之中不管是选择MongoDB还是选择SequoiaDB都是同样的代码,为此,我们在AgileEAS.NET SOA中间件之中定义了一个IStructDbProvider接口: using System; using System.Collections.Generic; using System.Linq.Expressions; namespace EAS.Data { /// <summary> /// 结构化数据库提供者接口定义。 /// </summary> /// <remarks> /// 为AgileEAS.NET SOA 中间件NoSQL数据访问提供标准接口定义。 /// </remarks> public interface IStructDbProvider { /// <summary> /// 打开连接。 /// </summary> void Connect(); /// <summary> /// 关闭连接。 /// </summary> void Close(); /// <summary> /// 连接是否打开。 /// </summary> bool IsOpen { get; } /// <summary> /// 对象插入。 /// </summary> /// <typeparam name="T">对象类型。</typeparam> /// <param name="item">对象实例。</param> void Insert<T>(T item) where T : class; /// <summary> /// 对象批量插入。 /// </summary> /// <typeparam name="T">对象类型。</typeparam> /// <param name="items">对象实例。</param> void InsertBatch<T>(System.Collections.Generic.IEnumerable<T> items) where T : class; /// <summary> /// 根据条件执行更新操作。 /// </summary> /// <typeparam name="T">对象类型。</typeparam> /// <param name="updater">更新表达式。</param> /// <param name="func">查询条件。</param> void Update<T>(Expression<Func<T, T>> updater, Expression<Func<T, bool>> func) where T : class; /// <summary> /// 根据条件执行更新操作。 /// </summary> /// <typeparam name="T">对象类型。</typeparam> /// <param name="item">更新对象。</param> /// <param name="func">查询条件。</param> void Update<T>(T item, System.Linq.Expressions.Expression<Func<T, bool>> func) where T : class; /// <summary> /// 根据条件删除对象。 /// </summary> /// <typeparam name="T">对象类型。</typeparam> /// <param name="func">条件表达式。</param> void Delete<T>(Expression<Func<T, bool>> func) where T : class; /// <summary> /// 求出Linq查询表达式。 /// </summary> /// <typeparam name="T">对象类型。</typeparam> /// <returns>对象表达式包装。</returns> IQueryableWarp<T> Linq<T>() where T : class; /// <summary> /// 根据条件查询数制。 /// </summary> /// <typeparam name="T">对象类型。</typeparam> /// <param name="where">条件。</param> /// <param name="skip">跳过记录数。</param> /// <param name="take">取记录数。</param> /// <returns>查询结构。</returns> List<T> List<T>(Expression<Func<T, bool>> where, int skip, int take) where T : class; /// <summary> /// 根据条件求单条记录。 /// </summary> /// <typeparam name="T">对象类型。</typeparam> /// <param name="where">条件。</param> /// <returns>对象实例。</returns> T Single<T>(Expression<Func<T, bool>> where) where T : class; } } IStructDbProvider字面意思即为结构化数据访问提供者接口,本接口定义在EAS.MicroKernel.dll程序集之中,AgileEAS.NET SOA中间件同时提供了针对SequoiaDB和MongoDB数据库的IStructDbProvider实现,EAS.Data.MongoDbProvider和EAS.Data.SequoiaDbProvider,这两个实现类定义在EAS.Data.NoSQL.dll程序集之中。 因为统计使用了IStructDbProvider接口,我们针对SequoiaDB和MongoDB的操作处理就统计成了如下代码: var vContainer = EAS.Context.ContextHelper.GetContext().Container; var dbProvider = vContainer.GetComponentInstance("StructDbProvider") as IStructDbProvider; //执行数据插入。 List<HFareDetail> vList = null; using (AgileHIS.Entities.DbEntities db = new AgileHIS.Entities.DbEntities()) { vList = db.HFareDetails.ToList(); //插入。 foreach (var item in vList) { dbProvider.Insert<HFareDetail>(item); } System.Console.WriteLine(string.Format("insert {0} records", vList.Count)); System.Console.ReadLine(); } //按条件修改某一条数据的几个属性值。 var v1 = vList.FirstOrDefault(); v1.Name = string.Empty; v1.Cash = decimal.Zero; dbProvider.Update<HFareDetail>(v1, p => p.ID == v1.ID); //按条件指量修改,指定某几个必,其他属性全部置空。 dbProvider.Update<HFareDetail>(p => new HFareDetail { Cash = decimal.Zero, Name = string.Empty, Price = decimal.Zero }, p => p.ChargeTime > DateTime.Now.AddDays(-1)); //依据条件删除 dbProvider.Delete<HFareDetail>(p => p.ChargeTime > DateTime.Now.AddDays(-1)); //求Count using (var queryWarp = dbProvider.Linq<HFareDetail>()) { int count = queryWarp.Queryable .Where(p => p.SourceID == 0) .Count(); //Linq查询Take\Skip。 var vList2 = queryWarp.Queryable .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .Skip(10).Take(1000) .ToList(); System.Console.WriteLine(string.Format("query {0} records", vList.Count)); //Linq查询过。 var vFare = queryWarp.Queryable .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .FirstOrDefault(); System.Console.WriteLine(vFare); //Linq\聚合运算,目前因为测试驱动报错,暂未实现 var sum = queryWarp.Queryable .Where(p => p.CreateTime > DateTime.Now.Date.AddMonths(-12)) .Sum(p => p.Cash); } System.Console.ReadLine(); 具体是使用SequoiaDB还是使用MongoDB由系统配置文件来决定,使用SequoiaDB: <!--StructDb/SequoiaDb--> <object name="StructDbProvider" assembly="EAS.Data.NoSQL" type="EAS.Data.SequoiaDbProvider" LifestyleType="Thread"> <property name="ConnectionString" type="string" value="192.168.23.57:50000"/> <property name="UserName" type="string" value=""/> <property name="Password" type="string" value=""/> <property name="CollectionSpace" type="string" value="his"/> </object> 使用MongoDB。 <!--StructDb/MongoDb--> <object name="StructDbProvider" assembly="EAS.Data.NoSQL" type="EAS.Data.MongoDbProvider" LifestyleType="Thread"> <property name="ConnectionString" type="string" value="mongodb://sa:sa@127.0.0.1:2222/his"/> <property name="DbName" type="string" value="his"/> </object> 七、SequoiaDB的C#驱动源代码托管、下载 本人为SequoiaDB所写的C#驱动,已提交托管到github,项目地址https://github.com/agilelab/SequoiaDB.Charp,欢迎大家下载,也欢迎大家和本人一道完善本驱动。 八、联系我们 敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET SOA中间件平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、2015-04-28更新日志 1.调整Socket通信框架的某些细节设计,调整消息/消息处理器注册机制: /// <summary> /// 注册消息。 /// </summary> /// <typeparam name="TMessage">消息类型。</typeparam> void AddMessage<TMessage>() where TMessage : IMessage; /// <summary> /// 注册消息。 /// </summary> /// <typeparam name="TMessage">消息类型。</typeparam> /// <typeparam name="THandler">消息处理器类型。</typeparam> void AddMessage<TMessage, THandler>() where TMessage : IMessage where THandler : IMessageHandler<TMessage>, new(); /// <summary> /// 注册消息处理器。 /// </summary> /// <typeparam name="TMessage">消息类型。</typeparam> /// <param name="hander">消息处理器。</param> [Obsolete("5.0之后不在支持,请使用AddMessage。")] void AddHander<TMessage>(IMessageHandler<TMessage> hander) where TMessage : IMessage; 原有AddHander<TMessage>方法调整为两个新的方法AddMessage<TMessage>,调用更为优雅。 2.修复Socket在服务器环境下长时间大并发运行会无端找不到IP地址的Bug。 3.修改Socket消息总线,增加总线是否在线等功能。 4.WinClient集成消息通信功能,增加程序集EAS.Communications.dll,将即时通信与WinClient容器进行深度整合。 5.WinClient增加单一位置登录功能,即某一个账号只能在某一个终端登录,如果在其他终端登录,将会剔出原有登录终端: #region 程序集 EAS.WinClient.dll, v4.0.30319 // E:\AgileLab\AgileEAS.NET\5.0\Complete\4.0\EAS.WinClient.dll #endregion using EAS.Explorer; using System; namespace EAS.WinClient { // 摘要: // AgileEAS.NET平台WinClient程序对外接口。 public class Application { public Application(); // 摘要: // 允许使用即时通讯。 public static bool AllowIM { get; set; } // // 摘要: // 是否允许踢人。 public static bool AllowKicking { get; set; } // 摘要: // 缓存预热。 public static void CachePrepare(); // // 摘要: // 配置系统资源。 // // 参数: // resource: // 资源实例。 public static void ConfigResource(IResource resource); // // 摘要: // 配置系统时间函数。 // // 参数: // timeFunc: // 时间函数。 public static void ConfigTimeFunc(Func<DateTime> timeFunc); // // 摘要: // 正常启动。 public static void Start(); // // 摘要: // 启动平台。 // // 参数: // assemblyName: // 调试启动。 public static void Start(string assemblyName); // // 摘要: // 启动平台。 // // 参数: // assemblyName: // 调试启动。 // // needLogin: // 需要登录。 public static void Start(string assemblyName, bool needLogin); // // 摘要: // 启动平台。 // // 参数: // assemblyName: // 调试启动。 // // needLogin: // 需要登录。 // // LoginID: // 登录ID。 // // Password: // 密码。 public static void Start(string assemblyName, bool needLogin, string LoginID, string Password); // // 摘要: // 启动平台。 // // 参数: // assemblyName: // 调试启动。 // // needLogin: // 需要登录。 // // organization: // 组织机构。 // // LoginID: // 登录ID。 // // Password: // 密码。 public static void Start(string assemblyName, bool needLogin, string organization, string LoginID, string Password); // // 摘要: // 启动升级。 public static void Upgrade(); } } 请在自己的主启动程序之中决定是否要启用剔除登录功能: System.Windows.Forms.Application.EnableVisualStyles(); System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false); WaitCallback updateCallBack = (s) => { EAS.Windows.Application.Upgrade(); }; System.Threading.ThreadPool.QueueUserWorkItem(updateCallBack); DllRegisterServer(); EAS.WinClient.Application.AllowKicking = true; EAS.WinClient.Application.Start(); 同时,要求必须在配置文件之中配置好Socket消息总线: <!--消息总线--> <object name="MessageBus" assembly="EAS.MicroKernel" type="EAS.Sockets.Bus.SocketBus" LifestyleType="Singleton"> <property name="Url" type="string" value="socket.tcp://127.0.0.1:6636/"/> </object> 消息总线的Socket链接地址和端口必须为AgileEAS.NET SOA 中间件SOA服务器,并且开启Socket服务功能。 5.调整了领域模型设计器的代码插件展示细节。 6.调整了领域模型设计器插件管理功能。 7.领域模型设计器增加了界面设计插件机制,充许开发者制作自己的设计器插件,完成特别的功能: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace EAS.Design { /// <summary> /// 元数据设计器插件。 /// </summary> public interface IDesignAddIn { /// <summary> /// 插件名称。 /// </summary> string Name { get; } /// <summary> /// 执行插件。 /// </summary> /// <param name="workProject">当前项目。</param> void Start(Project workProject); } } 实现自己的插件,必须实现IDesignAddIn接口,必须要引用EAS.Metadata.dll,在Start方法里面写自己的插件逻辑,领域设计器传入当前进行设计的项目,开发好自己的插件之后,打开插件管理功能进行加载: 8.GR报表设计器增加了退出设计器时的保存提醒功能。 9.调整完善了计划任务功能(计划任务引擎和管理UI)。 10.解决Lua脚本在没有安装VC11运行库环境不能运行的Bug。 11.账户管理增加了在线状态以及在线位置功能。 12.账号表增加了LINESTATE字段: ALTER TABLE EAS_ACCOUNTS ADD LINESTATE INT DEFAULT(0) 四、联系我们 为完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET SOA中间件平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、分布式消息总线以及基于Socket的实现 在前面的分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载一文之中给大家分享和介绍了一个极其简单也非常容易上的基于.NET Socket Tcp 技术实现的分布消息总线,也是一个简单的发布订阅框架: 并且以案例的形式为大家演示了如何使用这个分布式消息总线架构发布订阅架构模式的应用程序,在得到各位同仁的反馈的同时,大家也非常想了解订阅者离线的情况,即支持离线构发布订阅框架。 二、离线架构 不同于订阅者、发布者都同时在线的情况,支持订阅者离线,架构将有所变化,如下图所示: 也会比原先的结构将更加复杂,其中需要处理以下两个关键点: 1)订阅者的持久化存储。 2)订阅者离线之后其所订阅消息的持久存储。 三、解决方案 为解决消息总线的离线支持机制,我们在Socket 框架之中增加了一个接口ISubscribeStorager: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: 6: namespace EAS.Messages 7: { 8: /// <summary> 9: /// 消息订阅存储接口。 10: /// </summary> 11: public interface ISubscribeStorager 12: { 13: /// <summary> 14: /// 持久化订阅。 15: /// </summary> 16: /// <param name="subscriber">订阅者。</param> 17: /// <param name="topic">消息主题。</param> 18: void Subscribe(string subscriber, string topic); 19: 20: /// <summary> 21: /// 持久化退订。 22: /// </summary> 23: /// <param name="subscriber">订阅者。</param> 24: /// <param name="topic">消息主题。</param> 25: void Unsubscribe(string subscriber, string topic); 26: 27: /// <summary> 28: /// 装载订阅信息。 29: /// </summary> 30: /// <returns>系统之中的订阅清单。</returns> 31: List<SubscribeItem> LoadSubscribes(); 32: 33: /// <summary> 34: /// 写入消息。 35: /// </summary> 36: /// <param name="subscriber">订阅者。</param> 37: /// <param name="message">消息对象。</param> 38: void Write(string subscriber, QueueMessage message); 39: 40: /// <summary> 41: /// 读消息。 42: /// </summary> 43: /// <param name="subscriber">订阅者。</param> 44: /// <param name="message">消息对象。</param> 45: /// <returns>成功读取返回true,否则返回false。</returns> 46: bool Read(string subscriber, out QueueMessage message); 47: } 48: } ISubscribeStorager共提供持久化订阅持久化消息存储共五个函数,其中: LoadSubscribes:服务端初始化时读取所有的离线订阅关系,即那个订阅都订阅那那个主题。 Subscribe:持久化订阅者,当订阅才上线订阅消息时,持久化订阅关系,供离线检测之用。 Unsubscribe:持久化取消订阅,当订阅者退订消息时,从持久化订阅关系之中删除。 Write:当订阅者离线时,把订阅消息写入持久化存储。 Read:当离线订阅者上线时,从持久存储之中读取一条消息向其发送。 ISubscribeStorager:可以选择自己实现这个接口,以建立满足自己规则的离线存储机制,当然在AgileEAS.NET SOA 中间件之中提供了两种离线存储机制,存储于数据库和存储于MSMQ,下面向大家介绍一下这两种内置实现。 四、两种内置离线存储机制 在AgileEAS.NET SOA 中间件平台之中提供了两个ISubscribeStorager的实现,基于数据库的离线订阅存储实现EAS.Messages.DbSubscribeStorager和基于MSMQ的离线订阅存储实现EAS.Messages.MsmqSubscribeStorager。 EAS.Messages.DbSubscribeStorager:存储订阅关系在messageSubscribe.Config文件之中,消息存储在关系数据库SOA_SUBSCRIBEEVENTS表之中,使用前必须要建立相应的表结构,以下是SQL Server的DDL脚本: 1: CREATE TABLE [SOA_SUBSCRIBEEVENT]( 2: [GUID] [varchar](36) NOT NULL, 3: [SUBSCRIBER] [nvarchar](128) NOT NULL, 4: [TOPIC] [nvarchar](128) NOT NULL, 5: [BODY] [image] NULL, 6: [FCTIME] [datetime] NOT NULL, 7: CONSTRAINT [PK_SOA_SUBSCRIBEEVENT] PRIMARY KEY CLUSTERED 8: ( 9: [GUID] ASC 10: ) 11: ) 目前理论上支持SQLServer 、Mysql、ORACLE、Sqlite四种数据库结构,具体建表脚本请自行参考相应资料书写,也可以使用AgileEAS.NET SOA中间件所提供的数据库初始化工具创建。 EAS.Messages.MsmqSubscribeStorager:存储订阅关系在messageSubscribe.Config文件之中,消息存储Msmq消息队列之中,使用之前请确保机器上安装了MSMQ消息对列。 五、关于自定义实现ISubscribeStorager 有兴趣的朋友可以自定义实现接口ISubscribeStorager,这样就可以按自己的规则进行存储,比如把离线消息存储到mongodb、Redis、或者直接存储在文件之中,或者其他更多的实现规则,在此就不一一介绍,如有相关兴趣,请联系作者,如确有必要需要给在家介绍一下如何实现,将会另开一文本介绍如何自定义实现ISubscribeStorager接口。 六、改进在线例子支持离线 还是跟上次一样,以案例为在家展示一下怎么进行离线消息,就不重新开始例子,对原有例子做一些改进,改进后例子如下: 其中在原有项目的基础上增加了:Demo.Subscriber1和Demo.Subscriber2项目,其项目配置代码、配置文件基本上同Demo.Subscriber一样,其中唯一的差别在于,Demo.Subscriber1和Demo.Subscriber2向服务器提交订阅的时候都增加一个另friendName参数,其使用IMessageBus接口的以下订阅函数: 1: /// <summary> 2: /// 订阅消息。 3: /// </summary> 4: /// <param name="subscriber">订阅者。</param> 5: /// <param name="friendName">订阅者名称,用于处理离线订阅。</param> 6: /// <param name="topic">主题。</param> 7: /// <param name="notifyHandler">订阅通知。</param> 8: void Subscribe(object subscriber,string friendName ,string topic, MessageNotifyHandler notifyHandler); Demo.Publisher项目为发布者代码。 Demo.Subscriber项目为订阅者代码。 Demo.Server项目为服务端代码。 Demo.Subscriber1项目之中,其Program.cs代码如下: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Windows.Forms; 5: using EAS.Messages; 6: 7: namespace Demo.Subscriber1 8: { 9: class Program 10: { 11: static void Main(string[] args) 12: { 13: var container = EAS.Objects.ContainerBuilder.BuilderDefault(); 14: var bus = container.GetComponentInstance("MessageBus") as IMessageBus; 15: System.Console.WriteLine("Subscriber1"); 16: 17: bus.Subscribe(new Program(), "Subscriber1", Demo.Messages.Topics.DEMO_TOPIC, MessageNotify); 18: System.Console.ReadLine(); 19: } 20: 21: static void MessageNotify(object m) 22: { 23: Demo.Messages.Message message = m as Demo.Messages.Message; 24: System.Console.WriteLine(string.Format("Subscribe:{0}", message.ID)); 25: } 26: } 27: } 其中bus.Subscribe(new Program(), "Subscriber1", Demo.Messages.Topics.DEMO_TOPIC, MessageNotify);在订阅消息的时候给了一个friendName为Subscriber1,Demo.Subscriber2与Demo.Subscriber1项目的唯一的差别就是此处为Subscriber2. 我们使用内置的EAS.Messages.DbSubscribeStorager,则不需要修改服务端的代码,只需要修改服务端的配置文件如下: 1: <?xml version="1.0" encoding="utf-8"?> 2: <configuration> 3: <configSections> 4: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel" /> 5: </configSections> 6: <startup useLegacyV2RuntimeActivationPolicy="true"> 7: <supportedRuntime version="v4.0"/> 8: </startup> 9: <eas> 10: <objects> 11: <!--数据库连接--> 12: <object name="DbProvider" assembly="EAS.Data" type="EAS.Data.Access.SqlClientDbProvider" LifestyleType="Thread"> 13: <property name="ConnectionString" type="string" value="Data Source=.;Initial Catalog=eas_db;Integrated Security=SSPI;Connect Timeout=30" /> 14: </object> 15: <!--数据访问器--> 16: <object name="DataAccessor" assembly="EAS.Data" type="EAS.Data.Access.DataAccessor" LifestyleType="Thread"> 17: <property name="DbProvider" type="object" value="DbProvider"/> 18: <property name="Language" type="object" value="TSqlLanguage"/> 19: </object> 20: <!--ORM访问器--> 21: <object name="OrmAccessor" assembly="EAS.Data" type="EAS.Data.ORM.OrmAccessor" LifestyleType="Thread"> 22: <property name="DataAccessor" type="object" value="DataAccessor"/> 23: </object> 24: <!--查询语言--> 25: <object name="TSqlLanguage" assembly="EAS.Data" type="EAS.Data.Linq.TSqlLanguage" LifestyleType="Thread"/> 26: <!--消息持久化--> 27: <object name="SubscribeStorager" assembly="EAS.SOA.BootStrap" type="EAS.Messages.DbSubscribeStorager" LifestyleType="Singleton"/> 28: <!--日志管理--> 29: <object name="Logger" assembly="EAS.MicroKernel" type="EAS.Loggers.TextLogger" LifestyleType="Singleton"> 30: <property name="RootPath" type="string" value="G:\App.Work\Pub_Sub\Offline\Publish\logs" /> 31: </object> 32: </objects> 33: </eas> 34: </configuration> 在配置文件的IOC配置之中我们配置了消息存储对象以及其所依赖的数据库访问对象、Linq查询语言表达式,另外需要说明的是,我们需要把配置文件之中所涉及的EAS.Data.dll、EAS.SOA.BootStrap.dll复制到编译输出Publish,这两个文件可以从AgileEAS.NET SOA 中间件平台发布包之中寻找,本案例的下载压碎包之中会包括这两个文件。 有关于基于Msmq的配置,只需要修改配置文件如下: 1: <?xml version="1.0" encoding="utf-8"?> 2: <configuration> 3: <configSections> 4: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel" /> 5: </configSections> 6: <startup useLegacyV2RuntimeActivationPolicy="true"> 7: <supportedRuntime version="v4.0"/> 8: </startup> 9: <eas> 10: <objects> 11: <!--消息持久化--> 12: <object name="SubscribeStorager" assembly="EAS.SOA.BootStrap" type="EAS.Messages.MsmqSubscribeStorager" LifestyleType="Singleton"/> 13: <!--日志管理--> 14: <object name="Logger" assembly="EAS.MicroKernel" type="EAS.Loggers.TextLogger" LifestyleType="Singleton"> 15: <property name="RootPath" type="string" value="G:\App.Work\Pub_Sub\Offline\Publish\logs" /> 16: </object> 17: </objects> 18: </eas> 19: </configuration> 到此为止,所有代码均已完成,是不是很简单,接下来,我们跑起来验证一下效果。 七、验证效果 我们在编译输入目录Publish下先启动Demo.Server.exe,再各启动Demo.Subscriber.exe、Demo.Subscriber1.exe、Demo.Subscriber2.exe,再启动一个Demo.Publisher.exe,在Demo.Publisher.exe控制台按回车键: 目前程序三个订阅者都是在线的,Demo.Publisher发布了三条消息,三个订阅者都收到了三条消息,那么我们关闭Demo.Subscriber2之后再由Demo.Publisher发布两条消息: 然后我们再启动Demo.Subscriber2,看是否还能收到其离线之后由Demo.Publisher发布的两条消息: OK,到此为止。 八、源代码下载 本程序的源代码已上传到服务器,请通过http://112.74.65.50/downloads/eas/Demo.Pub_Sub_Offline.rar进行下载,如果在开发过程之中想要了解更多有关Socket通信框架以及更多AgileEAS.NET SOA中间件平台的技术资源,请通过AgileEAS.NET SOA 网站:http://www.smarteas.net的最新下载栏目进行下载。 九、问题反馈 麻烦大家在通过视频进行学习的时候能及时把问题反馈给楼主,或者有什么需要改进的一些建议都请向楼主直接反馈,以下是联系方式: AgileEAS.NET SOA 网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com 楼主QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、分布式消息总线 在很多MIS项目之中都有这样的需求,需要一个及时、高效的的通知机制,即比如当使用者A完成了任务X,就需要立即告知使用者B任务X已经完成,在通常的情况下,开发人中都是在使用者B所使用的程序之中写数据库轮循代码,这样就会产品一个很严重的两个问题,第一个问题是延迟,轮循机制要定时执行,必须会引起延迟,第二个问题是数据库压力过大,当进行高频度的轮循会生产大量的数据库查询,并且如果有大量的使用者进行轮循,那数据库的压力就更大了。 那么在这个时间,就需要一套能支持发布-订阅模式的分布式消息总线,那这个问题就可以很好的解决了,比如采用一些成熟的消息总线进行实现,比如MSMQ或者采用比如开源的NServiceBus的发布订阅机制就可以实现处理这种需求,其系统结构就会变成如下所示: 本分布式消息总线,目前广泛的被应用于分布式缓存的更新通知,当在N百台客户短在使用缓存的过程之中,某个操作修改了缓存的数据,必须会导致其他终端缓存的失效,那么使用基于Socket的分布式消息总线之后,我们可以做了修改了即可实时通知,做到缓存数据保持最新,再比如医疗应用之中的危急值管理,当发现检验、检查危急值之后,需要及时通知病区启动声光报警系统等,提醒医护工作人员及相关领导做出相应的措施,再比如应用于异构系统整合,当检验系统做出检验报告,通过消息总线进行发布,HIS系统则即时会收到检验报告数据而实现系统的整合。 二、基于Socket的实现 目前能够实现发布订阅模式的开源产品非常之多,为什么还要制造轮子呢,其主要原因有以下几点 1)像NServiceBus这种东西基于MSMQ,在大量的发布者-订阅者的情况下性能不佳。 2)此类东西太过于庞大、不易使用和配置。 3)学习成本过高。 那为什么要使用Socket技术进行实现呢,其主要原因是有以下几点: 1)使用高效的Socket通信技术,高效、支持更多的客户端。 2)使用简单,不需要定义太多额外的东西,只需要定义主题和消息即可使用。 目前本发布订阅框架是基于AgileEAS.NET SOA中间件平台Socket框架实现的,有关于些Socket框架的技术细节请参考AgileEAS.NET SOA 中间件平台.Net Socket通信框架-介绍、AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答、AgileEAS.NET SOA 中间件平台.Net Socket通信框架-完整应用例子-在线聊天室系统-下载配置、AgileEAS.NET SOA 中间件平台.Net Socket通信框架-完整应用例子-在线聊天室系统-代码解析文章进行了解和学习。 目前本发布订阅框架并直接集成于AgileEAS.NET SOA Socket通信框架之中并且随其一并发布,下面简单介绍一下其API: 在本框架之中定义了一个消息总线接口IMessageBus: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Collections; 6: 7: namespace EAS.Messages 8: { 9: /// <summary> 10: /// 消息总线接口定义。 11: /// </summary> 12: public interface IMessageBus : IDisposable 13: { 14: /// <summary> 15: /// 注册发布者。 16: /// </summary> 17: /// <param name="publisher">发布者。</param> 18: void AddPublisher(string publisher); 19: 20: /// <summary> 21: /// 注册发布者。 22: /// </summary> 23: /// <param name="publisher">发布者。</param> 24: /// <param name="topic">主题。</param> 25: void AddPublisher(string publisher, string topic); 26: 27: /// <summary> 28: /// 发布一条消息到总线。 29: /// </summary> 30: /// <param name="topic">主题。</param> 31: /// <param name="message">发布的消息。</param> 32: void Publish(string topic, object message); 33: 34: /// <summary> 35: /// 订阅消息。 36: /// </summary> 37: /// <param name="subscriber">订阅者。</param> 38: /// <param name="topic">主题。</param> 39: /// <param name="notifyHandler">订阅通知。</param> 40: void Subscribe(object subscriber, string topic, MessageNotifyHandler notifyHandler); 41: 42: /// <summary> 43: /// 订阅消息。 44: /// </summary> 45: /// <param name="subscriber">订阅者。</param> 46: /// <param name="friendName">订阅者名称,用于处理离线订阅。</param> 47: /// <param name="topic">主题。</param> 48: /// <param name="notifyHandler">订阅通知。</param> 49: void Subscribe(object subscriber,string friendName ,string topic, MessageNotifyHandler notifyHandler); 50: 51: /// <summary> 52: /// 订阅消息。 53: /// </summary> 54: /// <param name="subscriber">订阅者。</param> 55: /// <param name="friendName">订阅者名称,用于处理离线订阅。</param> 56: /// <param name="topic">主题。</param> 57: /// <param name="notifyHandler">订阅通知。</param> 58: /// <param name="changedHandler">发布者状态变化委托。</param> 59: void Subscribe(object subscriber, string friendName, string topic, MessageNotifyHandler notifyHandler,PublisherSstatusChangedHandler changedHandler); 60: 61: /// <summary> 62: /// 退订消息。 63: /// </summary> 64: /// <param name="subscriber">订阅者。</param> 65: void Unsubscribe(object subscriber); 66: 67: /// <summary> 68: /// 退订消息。 69: /// </summary> 70: /// <param name="subscriber">订阅者。</param> 71: /// <param name="topic">主题。</param> 72: void Unsubscribe(object subscriber, string topic); 73: 74: /// <summary> 75: /// 退订消息。 76: /// </summary> 77: /// <param name="subscriber">订阅者。</param> 78: /// <param name="friendName">订阅者名称,用于处理离线订阅。</param> 79: /// <param name="topic">主题。</param> 80: void Unsubscribe(object subscriber, string friendName, string topic); 81: } 82: } IMessageBus就基于Socket发布订阅消息总线的灵魂接口,也是基唯一的发布者调用者功能入口,也就是说不管你是发布者还是订阅者都需要调用这个接口,如果你是发布者请调用IMessageBus接口的Publish方法向消息总线发布消息,如果是你订阅者请通过IMessageBus的订阅方法进行订阅,当你订阅了某个主题之后,有发布者发布该主题的消息,你即可以收到消息并调用订阅回调函数进行处理。 三、实现一个简单的例子 现在我们开始一个简单的应用消息总线的例子,本例子代码解决方案由下图4个项目组成: 其中:Demo.Messages项目定义发布者、订阅者所使用的消息对象和消息主题。 Demo.Publisher项目为发布者代码。 Demo.Subscriber项目为订阅者代码。 Demo.Server项目为服务端代码。 在Demo.Messages项目之中,我们定义了一个消息Message: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Xml.Serialization; 6: 7: namespace Demo.Messages 8: { 9: [Serializable] 10: public class Message 11: { 12: [XmlElement] 13: public Guid ID 14: { 15: get; 16: set; 17: } 18: } 19: } 消息Message很简单,只有一个属性ID,同时 还需要定义一个消息主题: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: 6: namespace Demo.Messages 7: { 8: public class Topics 9: { 10: public static readonly string DEMO_TOPIC = "演示消息"; 11: } 12: } 我们定义了一个消息主题为“演示消息”。 在Demo.Publisher项目之中,没有太多额外的代码,只有在Program.cs写了以下简单的调用代码: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using EAS.Messages; 6: 7: namespace Demo.Publisher 8: { 9: class Program 10: { 11: static void Main(string[] args) 12: { 13: var container = EAS.Objects.ContainerBuilder.BuilderDefault(); 14: var bus = container.GetComponentInstance("MessageBus") as IMessageBus; 15: System.Console.WriteLine("Publisher"); 16: 17: while (System.Console.ReadLine()!="exit") 18: { 19: var m = new Messages.Message { ID = Guid.NewGuid() }; 20: bus.Publish(Demo.Messages.Topics.DEMO_TOPIC, m); 21: System.Console.WriteLine(string.Format("Publish:{0}", m.ID)); 22: } 23: } 24: } 25: } 从IOC容器获取一个消息总线IMessageBus对象,并调用Publish函数发布消息”bus.Publish(Demo.Messages.Topics.DEMO_TOPIC, m);“。 当然了,使用了IOC容器,就离来开配置文件了,其App.config文件内容如下: 1: <?xml version="1.0" encoding="utf-8"?> 2: <configuration> 3: <configSections> 4: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel" /> 5: </configSections> 6: <eas> 7: <objects> 8: <!--消息总线--> 9: <object name="MessageBus" assembly="EAS.MicroKernel" type="EAS.Sockets.Bus.SocketBus" LifestyleType="Singleton"> 10: <property name="Url" type="string" value="socket.tcp://127.0.0.1:6606/"/> 11: </object> 12: </objects> 13: </eas> 14: </configuration> 在Demo.Subscriber项目之中,使用与Demo.Publisher一模一样的配置文件,其Program.cs代码如下: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using EAS.Messages; 6: 7: namespace Demo.Subscriber 8: { 9: class Program 10: { 11: static void Main(string[] args) 12: { 13: var container = EAS.Objects.ContainerBuilder.BuilderDefault(); 14: var bus = container.GetComponentInstance("MessageBus") as IMessageBus; 15: System.Console.WriteLine("Subscriber"); 16: 17: bus.Subscribe(new Program(), "Subscriber1", Demo.Messages.Topics.DEMO_TOPIC, MessageNotify); 18: System.Console.ReadLine(); 19: } 20: 21: static void MessageNotify(object m) 22: { 23: Demo.Messages.Message message = m as Demo.Messages.Message; 24: System.Console.WriteLine(string.Format("Subscribe:{0}", message.ID)); 25: } 26: } 27: } 其中代码bus.Subscribe(new Program(), "Subscriber1", Demo.Messages.Topics.DEMO_TOPIC, MessageNotify);:完成把消息订阅到MessageNotify通知函数之中。 在Demo.Server项目之中,启动服务器并且开始接收订阅和发布: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using EAS.Sockets; 6: 7: namespace Demo.Server 8: { 9: class Program 10: { 11: static void Main(string[] args) 12: { 13: SocketServer socketServer = new SocketServer(128); 14: socketServer.Port = 6606; 15: socketServer.Logger = new EAS.Loggers.ConsoleLogger(); 16: socketServer.Initialize(); 17: System.Console.WriteLine("Server Starting..."); 18: socketServer.StartServer(); 19: System.Console.WriteLine("Server Startup!"); 20: System.Console.ReadLine(); 21: } 22: } 23: } 到此为止,所有代码均已完成,是不是很简单,接下来,我们跑起来验证一下效果。 四、验证效果 我们在编译输入目录Publish下先启动Demo.Server.exe,再启动两个Demo.Subscriber.exe,再启动一个Demo.Publisher.exe,在Demo.Publisher.exe控制台按回车键: OK,搞定。 五、源代码下载 本程序的源代码已上传到服务器,请通过http://112.74.65.50/downloads/eas/Demo.Pub_Sub.rar进行下载,如果在开发过程之中想要了解更多有关Socket通信框架以及更多AgileEAS.NET SOA中间件平台的技术资源,请通过AgileEAS.NET SOA 网站:http://www.smarteas.net的最新下载栏目进行下载。 六、问题反馈 麻烦大家在通过视频进行学习的时候能及时把问题反馈给楼主,或者有什么需要改进的一些建议都请向楼主直接反馈,以下是联系方式: AgileEAS.NET SOA 网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com 楼主QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、关于按钮级权限 在AgileEAS.NET SOA5.0版本之中,AgileEAS.NET SOA平台仅提供了基于模块的权限管理体系,也没有提供按钮/子功能级别的权限控制体系。 有很多很多的使用者基于AgileEAS.NET SOA 中间件平台进行应用开发的过程之中都提到这个问题,我们也给大家提供了一些解决思路和方案,但是一直没有在平台之中集成和实现一套标准的按钮/子功能权限管理功能和标准的API。 在AgileEAS.NET SOA5.0版本发布之前我们实现一套按钮/子功能级别的权限控制体系,提供了一个用于实现按钮级权限管理功能的管理模块及一给API接口。 三、按钮级权限管理 在AgileEAS.NET SOA5.0版本之中,AgileEAS.NET SOA平台仅提供了基于模块的权限管理体系,也没有提供按钮/子功能级别的权限控制体系。 使用管理员登录AgileEAS.NET SOA平台WinClient容器,就会在系统管理导航组之中看到有一个“函数管理”模块: 列表之中是所有的按钮权限项目,存储在模块信息表之中,如果需要增加一个新的“按钮/函数/权限项目”,使用添加功能,打开添加界面: 以上界面的操作会增加一个名称为“药品字典打印”字的按钮级别的权限,其权限ID为“6a185217-34de-4fe7-9ed5-c2cc49ba432c”。 双击选中的按钮级别的权限项,会打开“函数属性”对话框可以针对此函数/权限项进行授权: 授权方式同模块级权限一模一样,你也可以通过账号管理和角色管理模块进行授权。 四、API及如何使用 光提供一个管理功能还是不够的,还必须要提供一组API以供开发人员使用,AgileEAS.NET SOA中间件平台在应用程序对象(EAS.Application类的单例对象EAS.Application.Instance)上定义一个验证权限的API: 1: // 2: // 摘要: 3: // 验证权限,验证当前系统登录人员是否具有某个构件的访问权限。 4: // 5: // 参数: 6: // component: 7: // 构件Guid。 8: // 9: // 返回结果: 10: // 验证通过返回True,否则返回False。 11: bool Demand(Guid component); Demand方法需要传入按钮级别权限项/函数的定义ID,其他由交由平台完成。 接下来我们在DrugShop案例案例之中的药品字典模块之中增加对“打印”按钮的权限控制,Visual Studio打开DrugShop解决方案打开“药品字典”模块插件的代码文件DrugDictList.cs,修改打印按钮的事件如下: 1: private void tsbPrint_Click(object sender, EventArgs e) 2: { 3: //验证按钮级别权限。 4: if (!EAS.Application.Instance.Demand(new Guid("6a185217-34de-4fe7-9ed5-c2cc49ba432c"))) 5: return; 6: 7: if (this.dictList != null) 8: { 9: EAS.GReport.Controls.PrintViewDialog ViewDialog = new EAS.GReport.Controls.PrintViewDialog(); 10: ViewDialog.ReportID = new Guid("F29C4C91-0791-4116-BE26-3A2A88F30A2A"); 11: ViewDialog.DataObject = this.dictList; 12: ViewDialog.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 13: ViewDialog.WindowState = System.Windows.Forms.FormWindowState.Maximized; 14: ViewDialog.ShowDialog(); 15: } 16: } 这样就完成了对本权限项的调用验证。 四、执行验证 我们编译并且启动DrugShop.Main.exe,使用0001密码sa登录,打开“药品字典”模块,查询数据之后点击“打印”按钮: 0001不具有这个按钮级权限项的权限,所以会提供没有权限,我们换0002登录并且执行同样的操作: OK,可以正常使用了,按钮级权限演示完成。 DrugShop案例之中同步提供了本例子的权限定义和调用代码,请大家通过AgileEAS.NET SOA中间件官方网站的最新下载栏目进行下载。 五、联系我们 为完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET SOA中间件平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、关于Lua语言 Lua 是一个小巧的脚本语言。是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所组成并于1993年开发。 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。 Lua语言目前应用最广泛的领域是游戏编程领域,最早接触和认识Lua也是因为在2008年玩金山的剑网3,通过解包读过其中的一些游戏脚本,慢慢也看过一些其他游戏的Lua脚本,在我们开发自己的电子病历系统的过程之中,引入了Lua脚本语言实现那些可变性非常高的场景。 .NET通过LuaInterface开源项目类库实现对Lua的脚本调用以及Lua与C#的相互绑定,有关于这此方面的内容请大家搜索相关文章以获得帮助。 在AgileEAS.NET SOA5.0版本之中,我们决定把在开发过程之中形成的Lua脚本引擎一并集成入AgileEAS.NET SOA中间件平台,目前Lua脚本语言被我们广泛的应用电子病历系统这中的病案自动评分、短信系统之中的交互式应答、和一些计划任系统之中的计划任务定义。 三、AgileEAS.NET SOA平台Lua引擎 AgileEAS.NET SOA5.0平台目前使用的是Lua5.1版本,使用LuaInterface实现C#与Lua的相互绑定处理,平台已经对其进行了二次封装以提供统一的API支持,目前由EAS.LuaScript.dll程序集承载所有业务。 AgileEAS.NET SOA平台Lua引擎提供了以下接口或类型的API: ILuaEngine,定义为一个Lua脚本引擎: 1: using System; 2: 3: namespace EAS.LuaScript 4: { 5: /// <summary> 6: /// Lua脚本解析引擎。 7: /// </summary> 8: /// <remarks> 9: /// 用于完成程序之中嵌入的动态Lua脚本,Lua脚本在AgileEAS.NET SOA 中间件之中主要用于环境的各种参数的动态解析处理之中。 10: /// </remarks> 11: public interface ILuaEngine:IDisposable 12: { 13: /// <summary> 14: /// 脚本路径。 15: /// </summary> 16: string ScriptDirectory 17: { 18: get; 19: set; 20: } 21: 22: /// <summary> 23: /// 输出重定向方法/用于调试。 24: /// </summary> 25: Action<object> OutAction 26: { 27: get; 28: set; 29: } 30: 31: /// <summary> 32: /// 注册lua函数,实现Lua绑定。 33: /// </summary> 34: /// <param name="luaAPIClass">lua函数类</param> 35: void BindLuaFunctions(object luaAPIClass); 36: 37: /// <summary> 38: /// 执行lua脚本文件。 39: /// </summary> 40: /// <param name="luaFileName">脚本文件名。</param> 41: /// <returns>lua脚本执行结果。</returns> 42: object[] DoFile(string luaFileName); 43: 44: /// <summary> 45: /// 执行lua脚本文本。 46: /// </summary> 47: /// <param name="chunk">lua指令。</param> 48: /// <returns>lua脚本执行结果。</returns> 49: object[] DoString(string chunk); 50: 51: /// <summary> 52: /// 调用Lua函数。 53: /// </summary> 54: /// <param name="luaFunction">函数名称。</param> 55: /// <param name="args">调用参数。</param> 56: /// <returns>lua脚本执行结果。</returns> 57: object[] Invoke(string luaFunction, params object[] args); 58: } 59: } 其中脚本路径ScriptDirectory指示Lua脚本文件的存储位置,在DoFile执行脚本文过程之中如果传入为相关路径则可以自动在ScriptDirectory之中寻址,ScriptDirectory默认为当前程序目录。 DoFile:执行脚本文件并且返回执行结果。 DoString:执行脚本代码并且返回执行结果。 Invoke:执行指定的脚本函数。 LuaFunctionAttribute,Lua脚本函数特性: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: 6: namespace EAS.LuaScript 7: { 8: /// <summary> 9: /// Lua函数描述特性。 10: /// </summary> 11: /// <remarks> 12: /// 用于标记Lua接口方法。 13: /// </remarks> 14: [AttributeUsage(AttributeTargets.Method, 15: Inherited = false, AllowMultiple = false)] 16: [Serializable] 17: public class LuaFunctionAttribute : Attribute 18: { 19: /// <summary> 20: /// 初始化LuaFunctionAttribute对象实例。 21: /// </summary> 22: /// <param name="name">函数名称。</param> 23: public LuaFunctionAttribute(string name) 24: : this(name, string.Empty) 25: { 26: 27: } 28: 29: /// <summary> 30: /// 初始化LuaFunctionAttribute对象实例。 31: /// </summary> 32: /// <param name="name">函数名称。</param> 33: /// <param name="description">函数描述。</param> 34: public LuaFunctionAttribute(string name, string description) 35: : this(name, description,null) 36: { 37: 38: } 39: 40: /// <summary> 41: /// 初始化LuaFunctionAttribute对象实例。 42: /// </summary> 43: /// <param name="name">函数名称。</param> 44: /// <param name="description">函数描述。</param> 45: /// <param name="funcParams">参数说明。</param> 46: public LuaFunctionAttribute(string name, string description, params string[] funcParams) 47: { 48: this.Name = name; 49: this.Description = description; 50: this.Params = funcParams; 51: } 52: 53: /// <summary> 54: /// 函数名称。 55: /// </summary> 56: public string Name 57: { 58: get; 59: internal set; 60: } 61: 62: /// <summary> 63: /// 函数描述。 64: /// </summary> 65: public string Description 66: { 67: get; 68: internal set; 69: } 70: 71: /// <summary> 72: /// 参数说明。 73: /// </summary> 74: public string[] Params 75: { 76: get; 77: internal set; 78: } 79: } 80: } 用于C#向Lua暴露函数接口,实现C#方法与Lua脚本函数的绑定,也可以实现为把C#的方法暴露给Lua脚本调用,如以下代码: 1: /// <summary> 2: /// 执行指定的非查询命令。 3: /// </summary> 4: /// <param name="commandText">要执行的命令语句。该语句必须是标准的数据库语句。</param> 5: /// <returns>返回命令影响的行数。</returns> 6: [LuaFunction("ExecuteSql", "执行指定的非查询命令,返回执行所影响的行数。", "要执行的SQL语句")] 7: public int Execute(string commandText) 8: { 9: IDataAccessor da = this.GetComponent(); 10: if (da != null) 11: { 12: return da.Execute(commandText); 13: } 14: else 15: { 16: return -1; 17: } 18: } 其目标早实现C#方法Execute与Lua脚本函数ExecuteSql之间的绑定,当在Lua教本之中调用ExecuteSql,即会执行Execute方法。 LuaFramework,Lua框架,为Lua脚本引用最重要的API: 1: #region 程序集 EAS.LuaScript.dll, v4.0.30319 2: // G:\Health.Work\AgileEMR4.0\Publish\EAS.LuaScript.dll 3: #endregion 4: 5: using System; 6: 7: namespace EAS.LuaScript 8: { 9: // 摘要: 10: // Lua脚本执行框架/上下文。 11: // 12: // 备注: 13: // 应用系统之中调用Lua脚本的入口。 14: public sealed class LuaFramework 15: { 16: // 摘要: 17: // LuaFramework对象的唯一实例。 18: public static LuaFramework Instance { get; } 19: 20: // 摘要: 21: // 注册lua函数,实现Lua绑定。 22: // 23: // 参数: 24: // luaAPIClass: 25: // lua函数类 26: public static void BindLuaFunctions(object luaAPIClass); 27: // 28: // 摘要: 29: // 从应用程序上下文环境之中获取指定名称的对象实例。 30: // 31: // 参数: 32: // componentKey: 33: // 组件名称。 34: // 35: // 返回结果: 36: // 对象实例。 37: public object GetComponent(string componentKey); 38: // 39: // 摘要: 40: // Lua脚本引擎。 41: public static ILuaEngine GetLuaEngine(); 42: // 43: // 摘要: 44: // Lua脚本引擎。 45: public static ILuaEngine GetLuaEngine(string scriptDirectory); 46: // 47: // 摘要: 48: // 取系统时间。 49: [LuaFunction("GetTime", "取系统时间")] 50: public DateTime GetTime(); 51: } 52: } 其中BindLuaFunctions方法实现C#方法与Lua函数的绑定注册,调用时传入需要注册方法所在的C#类对象实例即可。 GetLuaEngine获取一个ILuaEngine,为之后的执行脚本作准备,调用GetLuaEngine可选传入scriptDirectory参数,scriptDirectory为Lua脚本存储目录。 AgileEAS.NET SOA中间件已经为大家提供了少数的几个预定义API绑定: 1: helpcmd(cmdName) - Show help for a given command or package 2: help() - List available commands. 3: Include(luaFileName) - 预加载指定的脚本文件 4: echo(message) - 显示Lua调试信息,用于Lua的动态调试。 5: Echo(message) - 显示Lua调试信息,用于Lua的动态调试。 6: WriteLog(message) - 写日志记录,用于Lua脚本的动态调试。 7: GetTime() - 取系统时间 8: GetComponent(componentKey) - 从应用程序上下文环境之中获取指定名称的对象实例 9: GetAccount() - 求当前账户信息 10: ExecuteSql(commandText) - 执行指定的非查询命令,返回执行所影响的行数。 11: QuerySql(commandText, resultType) - 执行给定的数据库查询命令,返回执行结果,返回结果由resultType参数决定。 12: QuerySqlScalar(commandText) - 执行给定的数据库查询命令,仅返回第一行第一列结果 13: QuerySqlMatrix(commandText) - 执行给定的数据库查询命令,返回第一个查询结果Matrix 14: QuerySqlDictionary(commandText) - 执行给定的数据库查询命令,返回第一行的Key-Value 15: QuerySqlList(commandText) - 执行给定的数据库查询命令,返回第一行的Key-Value 16: QuerySqlDataSet(commandText) - 执行给定的数据库查询命令,返回查询结果集 17: QuerySqlDataTable(commandText) - 执行给定的数据库查询命令,返回查询结果集的第一个DataTable 18: GetDataSet() - 求当前系统的帐套信息 大家也可以基于AgileEAS.NET SOA 平台Lua引擎扩展自己的LuaAPI。 四、AgileEAS.NET SOA平台Lua引擎应用案例 在我12年的医疗行业开发之中,做过多年的电子病历,开发、指导开发过多套电子病历系统,在电子病历系统之中,有以下几个问题一直得不到好的解决方案: 在电子病历质控之中有一个自动质控评分,其由程序自动的预先为某个病案打出一个得分: 在没有使用Lua教本之前呢,也是能实现这种自动评分,但是为了实现这样的功能,系统设计之中就会要增加一些辅助的表和大量的辅助设计以帮助完成这样的功能,因为毕竟不存在统一的评分规则,所以这个设计会极其的复杂,以致于很难把这样的功能做好,或者说在成本和效益估量之中,得不偿失。 另外还有比较简单的例子就是电子病历之间的宏替换问题,在书写电子病历的过程之中需要动态的插入如病人基本信息、医院名称这样的东西进入病历,但是因为其数据源并不是唯一确定的,如果不使用动态脚本设计,那么其程序这中就会存在大量的硬编码,并且如果想要在后期实施阶段增加宏,那么则必须要修改程序才能完成。 下面我们就以自动评分案例向大家讲解一下是如何实现功能的呢: 首先,系统之中必须管理和维护用于自动评分的所有评分规则: 这里与其他很多开发者的做法不一样的是,对于每个缺陷项目,我们都为其提供了一个评分规则的脚本的设计,例如对于缺陷“*缺入院记录”的评分脚本如下: 1: ----------------------------------------------------------------------------------------------- 2: -- 创建人 : 魏琼东 3: -- 创建时间 : 2013-09-05 4: -- 效果备注 : *缺入院记录评分脚本。 5: -- GetErrorNumber,求缺陷数量,由脚本计算出本缺陷数量 6: ---------------------------------------------------------------------------------------------- 7: ------------------------不怎么华丽的分割线-------------------------------------- 8: function GetErrorNumber(patient,errorItem) 9: 10: --调用C#,求监控项目 11: local monitorItem = GetMonitorItem("B01") 12: --监控表达式,无表达式返回0 13: local script = monitorItem.Expression 14: if script == nil then 15: return 0 16: elseif script == "" then 17: return 0 18: end 19: 20: --加载监控脚本 21: ExecuteScript(script) 22: --执行监控函数NeedWrite,如果需要写则预标存在此缺陷 23: local need = NeedWrite(patient,monitorItem) 24: 25: if need == 1 then 26: return 1 27: else 28: return 0 29: end 30: 31: end 这样的设计的目标是将缺陷的评分动作都由Lua脚本实现,而在应用程序之中并不存在针对缺陷制定不同的评分规则的情况,只有调用脚本进行评分的代码: 1: /// <summary> 2: /// 求指定患者、指定缺陷的缺陷数。 3: /// </summary> 4: /// <param name="pRoot"></param> 5: /// <param name="errorItem"></param> 6: /// <returns></returns> 7: public static int GetErrorNumber(ILuaEngine m_Lua, PatientRoot pRoot, ErrorDict errorItem) 8: { 9: if (string.IsNullOrEmpty(errorItem.Expression)) //无评分脚本 10: { 11: return 0; 12: } 13: 14: string m_file = System.IO.Path.Combine(LuaEx.ScriptDirectory, string.Format("emr\\error\\{0}.lua", errorItem.ErrorCode)); 15: if (!System.IO.File.Exists(m_file)) 16: { 17: return 0; 18: } 19: 20: try 21: { 22: m_Lua.DoFile(m_file); //加载脚本 23: 24: object[] vs = m_Lua.Invoke("GetErrorNumber", pRoot, errorItem); //执行函数。 25: if (vs != null && vs.Length > 0) 26: { 27: return int.Parse(vs[0].ToString()); 28: } 29: else 30: { 31: return 0; 32: } 33: } 34: catch 35: { 36: return 0; 37: } 38: } 这样的好处在于,主体程序变的极其的简单一致,不需要各种判断和各种规则,并且灵活自动,可以做到政策变化或者客户需求变化导到的各种评分规则的修改,则会灵活自如。 实践证明,使用动态脚本语言扩展现在系统的系统是一种低投入高产出的工作,对于应对这种高扩展性和高定制性的项目是一个非常好的选择,这个可以解释游戏编程之中大量使用Lua语言的事实,针对NPC、剧情书写相关的处理脚本,让游戏的后期变更,调整变得简单可行。 四、联系我们 为完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET SOA中间件平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、关于AgileEAS.NET SOA中间件的分布式结构 AgileEAS.NET SOA中间件平台吸吸引人的一个特色就是其分布式架构体系,其可以基于高层的WCF协议和底层的.NET Socket通信建设统一一致的分布式通信服务,如下图所示的分布式结构: 系统中所有的客户端业务处理请求都经由AppServer处理之后返回结果给客户端,这个一个极其经典的SOA架构的分布式结构。 当系统的业务运行量大到一台AppServer无法满足情况下,那么我们就要考虑纵向扩展或者横向扩展以满足系统性能和业务响应的问题,最常用的选择是横向扩展,使用负载均衡机制以确保业务请求由多台AppServer完成;以及对系统的可靠性要求很高的时候,因为只有一台AppServer如果AppServer宕机了,那么整个系统都无法运行。我们就必须的考虑整个系统的故障切换能力,以确定系统的高可用性,系统的架构就会衍生为以下结构: 可以对比发布,前面架构图之中的AppServer已经由一台NlbServer和多台AppServer组成的服务器组合替换,系统之中不再存在当AppServer宕机之后系统无法服务的问题,也解决了随着业务量增加动态扩容的问题。 三、AgileEAS.NET SOA平台NLB支持 AgileEAS.NET SOA中间件平台的AppServer支持程序为EAS.SOA.Server.exe或EAS.SOA.Server.x64.exe,其中EAS.SOA.Server.exe为32位服务程序,EAS.SOA.Server.x64.exe为64位服务程序。 AppServer能在同一个进程之内同时支持Socket通信和WCF通信,即能同样的业务同步提供Socket和WCF通信方式,WCF通信提供http和net.tcp通道的访问,客户端应用使用何种通信方式由客户段程序决定。 AgileEAS.NET SOA中间件平台的在5.0版本之后增加了一个应用负载均衡服务程序EAS.NLB.Server,也同样提供了32位与64位的服务应用程序EAS.NLB.Server.exe或EAS.NLB.Server.x64.exe。 在AgileEAS.NET SOA中间件平台5.0版本之中为AppServer、NLB.Server提供了运行监控程序,NLB.Server的服务监控程序同时提供了NLB.Server的配置管理功能: 负载节点监控,会监控NLBServer后挂接的所有AppServer清单以及各个AppServer服务器的工作状态,是在线还是离线,在线的则能向客户端提供服务,如果离线了则表示不能向客户端提供服务了,在NLBServer负载过程之中,只会在在线的AppServr之间进行负载。 四、AgileEAS.NET NLBServer配置案例 在第三节我们已经对NLB做过一些简单的介绍,接下来我们以DrugShop案例环境为基础实例演示一下如何在应用环境之中启用NLBServer支持: 首先我们简单规划一下测试环境: 接下为我们一一配置,首先,我们参考AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(二):配置WinClient分布式运行环境一文配置好一个AppServer实例AppServer1,端口号设置Socket:6706,Wcf-tcp:6707,Wcf-http:6708: 1: <appserver> 2: <channel> 3: <wcf enable="true"> 4: <config tcpPort="6707" httpPort="6708"/> 5: <serviceThrottling maxConcurrentCalls="128" maxConcurrentInstances="128" maxConcurrentSessions="256"/> 6: <wcfServices> 7: <wcfService key="Key" type="TValue"/> 8: </wcfServices> 9: </wcf> 10: <socket enable ="true"> 11: <config tcpPort="6706"/> 12: <serviceThrottling maxConcurrence="1024"/> 13: <socketServices> 14: <socketService key="IMSocketService" type="AgileIM.Service.IMSocketService,AgileIM.Service"/> 15: </socketServices> 16: </socket> 17: </channel> 18: <appServices> 19: <appService key="Key" type="TValue"/> 20: </appServices> 21: </appserver> 然后复制配置好的AppServer目录到其他地方建立AppSerer2,端口信息修改为Socket:6706,Wcf-tcp:6707,Wcf-http:6708: 1: <channel> 2: <wcf enable="true"> 3: <config tcpPort="6807" httpPort="6808"/> 4: <serviceThrottling maxConcurrentCalls="128" maxConcurrentInstances="128" maxConcurrentSessions="256"/> 5: <wcfServices> 6: <wcfService key="Key" type="TValue"/> 7: </wcfServices> 8: </wcf> 9: <socket enable ="true"> 10: <config tcpPort="6806"/> 11: <serviceThrottling maxConcurrence="1024"/> 12: <socketServices> 13: <socketService key="IMSocketService" type="AgileIM.Service.IMSocketService,AgileIM.Service"/> 14: </socketServices> 15: </socket> 16: </channel> 17: <appServices> 18: <appService key="Key" type="TValue"/> 19: </appServices> 20: appserver> 同样复制AppServer目录配置NlbServer,NlbServer服务目前没有配置工具,只能自己修改配置文件EAS.NLB.Server.exe.config或者EAS.NLB.Server.x64.exe.config: 1: <?xml version="1.0"?> 2: <configuration> 3: <configSections> 4: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel"/> 5: </configSections> 6: <!--支持混合程序集--> 7: <startup useLegacyV2RuntimeActivationPolicy="true"> 8: <supportedRuntime version="v4.0"/> 9: </startup> 10: <eas> 11: <configurations> 12: <item name="Key" value="Value"/> 13: </configurations> 14: <nlbserver> 15: <config> 16: <keepAlive timeSpan="6" chnanel="WCF"/> 17: </config> 18: <channel> 19: <wcf enable="true"> 20: <config tcpPort="6607" httpPort="6608"/> 21: <serviceThrottling maxConcurrentCalls="128" maxConcurrentInstances="128" maxConcurrentSessions="256"/> 22: <wcfServices> 23: <wcfService key="Key" type="TValue"/> 24: </wcfServices> 25: </wcf> 26: <socket enable ="true"> 27: <config tcpPort="6606" gatewayStyle="NetPacket"/> 28: <serviceThrottling maxConcurrence="10000"/> 29: </socket> 30: </channel> 31: </nlbserver> 32: <objects> 33: <!--NLB日志记录--> 34: <object name="Logger" assembly="EAS.MicroKernel" type="EAS.Loggers.TextLogger" LifestyleType="Singleton"> 35: <property name="Path" type="string" value="..\logs" /> 36: </object> 37: </objects> 38: </eas> 39: <startup> 40: <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> 41: </startup> 42: </configuration> 配置其端口号为6606,Wcf-tcp:6607,Wcf-http:6608,配置完成后参考AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(二):配置WinClient分布式运行环境一文编写AppServer服务的安装、卸载和控制台启动脚本。 NLBServer的安装卸载和控制台启动脚本类似,都是由EAS.NLB.Server.exe -参数组成,只不过,EAS.NLB.Server只能支持在一台服务器安装一个实例,即同一台服务不充许像AppServer一样安装多个实现,以下是脚本示例: 1: @rem 安装NLB服务 2: EAS.NLB.Server.x64.exe -i 3: 4: @rem 卸载NLB服务 5: EAS.NLB.Server.x64.exe -u 6: 7: @rem 控制台启动NLB服务 8: EAS.NLB.Server.x64.exe -run 9: pause OK,我们启动NLBServer和AppServer1、AppServer2: 接下来我们在客户端文件夹之中启动“负载均衡监控”程序EAS.NLB.Monitor.exe配置负载均衡服务的负载节点: 在服务连接之中选择新建连接,弹出新建连接对话框: 修改连接名为nlbServer,服务器为127.0.0.1,即连接本机nlbserver,实际情况之中请根据实际情况配置,端口号填入前面配置的NlbServer端口参数,我们此处选择以wcf-tcp连接,端口配置为6607,然后确定保存配置,并且进入“负载均衡监控”主界面: “负载均衡监控”第一个界面为负载均衡服务器的CPU、内存、网络、磁盘等各种资源参数,供管理人员参考,我们切换到负载节点监控: 在空白区域右键打开快捷菜单点=>"添加节点": 根据AppServer参数添加负载节点信息,确定后保存负载节点信息,使用同样的方法添加AppSever2节点,完成后如下图: 也可以选择直接修改配置配置负载节点信息,负载节点信息存储在NlbServer工作目录中的“NLB.config”文件: 1: <?xml version="1.0" encoding="utf-16"?> 2: <NLB xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 3: <items> 4: <NlbWorkItem> 5: <host>127.0.0.1</host> 6: <wcfChannel> 7: <HttpPort>6708</HttpPort> 8: <TcpPort>6707</TcpPort> 9: </wcfChannel> 10: <socketChannel> 11: <TcpPort>6706</TcpPort> 12: </socketChannel> 13: <enabled>true</enabled> 14: <runing>true</runing> 15: </NlbWorkItem> 16: <NlbWorkItem> 17: <host>127.0.0.1</host> 18: <wcfChannel> 19: <HttpPort>6808</HttpPort> 20: <TcpPort>6807</TcpPort> 21: </wcfChannel> 22: <socketChannel> 23: <TcpPort>6806</TcpPort> 24: </socketChannel> 25: <enabled>true</enabled> 26: <runing>false</runing> 27: </NlbWorkItem> 28: </items> 29: </NLB> OK,现在已经完成了对负载均衡的配置,接下来我们配置客户端程序“DrugShop.Main.exe”的连接信息,可以选择由配置工具生成,也可以选择手工书写,定义为SOA分布式环境下wcf-tcp连接,连接端口为127.0.0.1:6607(NLBServer),配置文件如下: 1: <?xml version="1.0" encoding="utf-8"?> 2: <configuration> 3: <configSections> 4: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel" /> 5: </configSections> 6: <!--SQLite运行必需--> 7: <startup useLegacyV2RuntimeActivationPolicy="true"> 8: <supportedRuntime version="v4.0"/> 9: </startup> 10: <eas> 11: <configurations> 12: <item name="Key" value="Value" /> 13: </configurations> 14: <objects> 15: <!--分布式通信组件。--> 16: <object name="ServiceBridger" assembly="EAS.Distributed" type="EAS.Distributed.ServiceBridger" LifestyleType="Thread" > 17: <property name="ServiceName" type="string" value="EAS.RMI.Service" /> 18: </object> 19: <object name="DataAccessor" assembly="EAS.Distributed" type="EAS.Distributed.DataAccessor" LifestyleType="Thread" > 20: <property name="ServiceBridger" type="object" value="ServiceBridger" /> 21: </object> 22: <object name="OrmAccessor" assembly="EAS.Distributed" type="EAS.Distributed.OrmAccessor" LifestyleType="Thread" > 23: <property name="ServiceBridger" type="object" value="ServiceBridger" /> 24: <property name="DataAccessor" type="object" value="DataAccessor" /> 25: </object> 26: <!--日志管理--> 27: <object name="Logger" assembly="EAS.MicroKernel" type="EAS.Loggers.TextLogger" LifestyleType="Singleton" /> 28: <!--资源--> 29: <object name="EAS.Explorer.Resource" assembly="DrugShop.Res" type="DrugShop.Res.Resources" LifestyleType="Singleton" /> 30: </objects> 31: <services> 32: <service name="EAS.RMI.Service" service-type="WcfService" singleton="true" url="net.tcp://127.0.0.1:6607/eas/services/EAS.RMIService" /> 33: </services> 34: </eas> 35: </configuration> OK,客户端程序配置完成。 五、测试验证 启动DrugShop.Main.exe,可以选择启动多个客户端程序实例,可以看到以控制台运行的两个服务实例都有不同程序的请求响应: 我们可以看到,客户端的业务请求被NLBServer进行了有效的负载,当我们随便停止其他任务一个AppServer,我们可以通过“负载均衡监控”程序看到其处于离线状态: 在实际项目之中可以是某一台AppServer宕机了或者人为的进行某种维护升级活动,在这个时间,所有的客户端程序的所有业务操作都是可以的,从这一点我们可以看出,AppServer被NLBServer进行了有效的故障转移,有效的提高了系统的高可用性。 如果所有的AppServer都离线了,即所有AppServer都宕机了,如下图: 那么这个时间,系统就不能提供任务的服务了,当我们在客户端执行任何操作都会报错: 当我们恢复负载之中的任务一个节点之后,系统则可以向使用者提供全部的业务服务。 六、联系我们 为完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET SOA中间件平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、关于GReport、Grid++报表系统 AgileEAS.NET SOA中间件平台目前集成两套优秀的报表系统,一套是开源的fyireporting报表系统3.96版本,其始于2007年AgileEAS.NET SOA中间件平台3.0版本之时就集成入平台的一套报表系统,其快速方便的条带式报表非常适合用于MIS系统的报表展示,我们在fyireporting基础上做了大是的汉化、改动并且与AgileEAS.NET SOA中间件平台进行紧密的集成。 但是对于市场在国内的大多数软件企业都会遇到客户的很多近似于变态的报表需求,fyireporting有也其不足的地方,其在处理中国式的票据、和一个特殊报表时无能无为,之后我们考虑集成一套更好的中国式报表系统,在和几家行业医疗供应商合作的两个年头之中,我们集成广州锐浪的Grid++报表系统并与AgileEAS.NET SOA中间件进行融合,称之为GReport。 AgileEAS.NET SOA中间件平台的报表管理体系并设计为集中式的报表管理、设计与报表浏览、打印相协调的可集中管理的报表体系,极大的简化和方便报表的开发、部署和管理。 在AgileEAS.NET中间件平台之中提供了一个用于管理、和设计GRport的功能模块“GR报表”: 系统之中的所有报表都是可管理的,当在系统的任何一个客户端修改了报表定义之后,不需要重新部署程序,即可让报表的修改通过所有的使用者。即时生效。 在GR报表模块之中,直接双击选中的报表即可进行报表设计界面,进行报表的设计: GR报表的设计器界面是基于Grid++报表所提供的设计器控件实现的,其使用方法同Grid++原始的报表设计工作,具体的使用方法请参考Grid++官方帮助。 本设计器与官方的原生设计器之间的差别主要是新建报表与原生不同,原生的报表系统只能基于数据库连接和SQL语句创建报表,而本设计器提供了除通过书写SQL创建报表(不用提供连接信息,以当前连接为准)之外还提供了基于AgileEAS.NET SOA中间件平台的ORM实体创建报表: 数据报表即为基于SQL语句创建报表,对象报表基于ORM实体对象创建报表: 当基于实体创建报表时确定报表对应的实体对象之后,系统会自动的从ORM定义信息之中读出实体的属性定义信息并且自动的转换为报表的数据列。 三、GReport组件 AgileEAS.NET SOA中间件平台为开发人员提供了三个有关于GReport报表的控件,包括打印预览对话框、报表数据显示控件、报表打印控件,这三个控件都由EAS.GReport.Controls.dll程序集承载,使用这三个组件之前都需要先引用EAS.GReport.Controls.dll程序集或者把这三个组件加载到Visual Studio的工具箱之中。 打印预览对话框: EAS.GReport.Controls.PrintViewDialog,用于打开一个新的窗口并且预览打印报表。 报表查询显示控件: EAS.GReport.Controls.GDisplayViewer,以查询模式显示报表及报表数据的一个控件。 报表预览显示控件: EAS.GReport.Controls.GPrintViewer,以打印模式显示报表及报表数据的一个控件。 以上三个控件都提供相同的报表API: 1: // 2: // 摘要: 3: // 报表ID。 4: [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 5: [Browsable(false)] 6: public Guid ReportID { get; set; } 属性ReportID:其意思为报表ID,其取值为GR报表模块之中设计好的报表ID号,用于实现与系统报表管理的绑定。 1: // 2: // 摘要: 3: // 数据源对象。 4: [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 5: [Browsable(false)] 6: public object DataObject { get; set; } 属性DataObject:其意义为报表的数据对象,即控件要显示或者打印的数据源,DataObject的值必须为DataTable或者为ORM实体的List<T>集合。 程序之中调用报表的流程即为设计这两个属性即可,首先设计ReportID为要显示、打印的报表ID,然后向控件设置报表的显示数据源DataObject即可完成对报表系统的调用。 四、报表开发实例 我们下面以DrugShop案例之中的药品字典模块的字打印实例如何进行GReport报表开发: 首先我们需要在GR报表模块之中增加一个名称为“药品字典明细报表”的报表项目。 报表名称必须要填写并且不能重名,别名可以选择填写,缓存间隔默认为15分种,最小1分种,自由设定,原则上在系统开发测试阶段设小一些,在稳定运行阶段设大一些。 其他参数,如“报表模块,把报表做为独立模块发布”、查询语句、查询参数可以不去理会,这些参数为动态报表提供,关于动态报表我们会在后面的文章之中进行专门的介绍。 然后我们点“确定”按钮保存报表进行下一步的报表设计工作。 双击我们刚才添加的“药品字典明细报表”进入报表设计界面,我们可以看到这是一个空报表: 选择“文件”菜单之中的“新建”=》“对象报表”: 切换到数据定义Tab页,进行实体类型的选择: 我们浏览选择程序集DrugShop.Entitties.dll,然后在对象下拉列表框中选择DrugShop.Entitties.PIn,即药品入库ORM对象,我们基于DrugShop.Entitties.PIn创建报表,点击“确定”完成报表的新建。 系统会自动的更具新建导向生成一个初始报表,如果需要对报表的显示、格式进行调用,请参考Grid++设计手册进行学习。 修改完成之后,点击“保存”图标、或者“文件=》保存”菜单项保存报表的格式定义,这样就完成了报表的定义。 接下来我们需要把刚才定义、设计好的报表挂在程序之中,使用Visual Studio 打开DrugShop解决方案,打开DrugShop.WinUI项目之中的药品字典模块DrugDictList.cs: 双击“打印”按钮写以下打印代码: 1: private void tsbPrint_Click(object sender, EventArgs e) 2: { 3: if (this.dictList != null) 4: { 5: EAS.GReport.Controls.PrintViewDialog ViewDialog = new EAS.GReport.Controls.PrintViewDialog(); 6: ViewDialog.ReportID = new Guid("F29C4C91-0791-4116-BE26-3A2A88F30A2A"); 7: ViewDialog.DataObject = this.dictList; 8: ViewDialog.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 9: ViewDialog.WindowState = System.Windows.Forms.FormWindowState.Maximized; 10: ViewDialog.ShowDialog(); 11: } 12: } 这样我们就完成了对报表的调用,另外,在DrugShop案例之中,药品入库查询和药品销售查询两个模块之中分别使用了GReport报表,请大家在开发过程之中参考。 五、执行验证 我们编译并且启动DrugShop.Main.exe,使用0001密码sa登录,打开药品字典功能,来试一下是报表是否正常: OK,使用正常,没有任何问题。 DrugShop案例之中同步提供了本例子的报表定义和使用代码,请大家通过AgileEAS.NET SOA中间件官方网站的最新下载栏目进行下载。 六、联系我们 为完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET SOA中间件平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、关于WinClient的外挂资源体系介绍 最初版本的AgileEAS.NET SOA中间件平台的运行容器/外壳是没有界面替换体系,最初只是提供了替换关键部分的图片、文字的功能,随着AgileEAS.NET SOA中间件被众多的客户应用到各行各业之后,我们从客户的应用反馈之中进行了大量的重构,其中运行容器也越来越开放,从最初令开放替换部分图片到慢慢开放可以自由修改其他的导航栏、Banner、状态栏、菜单、登录界面、关于界面,发生了很大的变化,同步我们也提供了Desktop、MDI、Dockable等多种界面风格,可以说客户有更我的选择了。 随着更多软件企业或组织加入应用AgileEAS.NET SOA中间件行业,有许多的客户已经不能满足于在这几种风格之中进行选择,希望能给自己最大的自定义空间和范围,提供了更换主界面的需求,我们积极的响应这种需求,并且提出了相关的解决方案,并且在2012年AgileEAS.NET SOA 5.0版本的时间向大家提供。 主界面替换被某一些我们服务于的客户所使用,但是对于广大的关心AgileEAS.NET SOA中间件的朋友来说,并不能得到我们细致并且一对一的服务,因为我们还没有变此部分内容给大家做过介绍和在公开的案例之中提供,所以对于社区之中的很多朋友来说,还能灵活的应用本部分内容。 下图是一个典型的AgileEAS.NET SOA中间件平台WinClient容器的主界面: 其中包含以下组成部分: 主菜单:界面最上部的主菜单,系统、视图和帮助。 导航菜单:通过菜单之中的菜单项可以打开指点的功能模块。 导航栏:同系统导航菜单、以树形或者其他形式展示。 状态栏:显示系统的一些状态信息,如操作消息、当前登录信息等。 内容区:除以上项目外的界面空白区域为业务工作区,即模块插件的工作区域,新打开的模块在经区域显示和工作。 启始页:特指工作区之中第一个打开的模块,当系统登录完成之后会自动打开一个模块,此模块称为起始页模块。 三、IResource接口 AgileEAS.NET SOA 中间件平台为了应用对运行容器的各个部分进行自定义和扩展,提供了一个资源接口IResource: 1: using System; 2: 3: namespace EAS.Explorer 4: { 5: /// <summary> 6: /// 运行容器的外壳资源。 7: /// </summary> 8: public interface IResource 9: { 10: /// <summary> 11: /// 获取应用系统的图标,用于替换主界面的图标。 12: /// </summary> 13: System.Drawing.Icon GetMainIcon(); 14: 15: /// <summary> 16: /// 获取默认的模块图标,用于简约、经典风格的Tab页图标显示,也用于Desktop模式的桌面图标显示。 17: /// </summary> 18: System.Drawing.Image GetModuleIcon(); 19: 20: /// <summary> 21: /// 获取桌面背景图像,用于Desktop模式的桌面模块。 22: /// </summary> 23: System.Drawing.Image GetDesktopImage(); 24: 25: /// <summary> 26: /// 获取应用系统的导航控件,用于替换平台的导航控件。 27: /// </summary> 28: /// <returns>WinForm/WPF用户控件。</returns> 29: object GetNavigationControl(); 30: 31: /// <summary> 32: /// 获取应用系统的Banner控件,用于替换平台的Banner条。 33: /// </summary> 34: /// <returns>WinForm/WPF用户控件。</returns> 35: object GetBannerControl(); 36: 37: /// <summary> 38: /// 获取应用系统的Bottom控件,用于替换平台的状态栏。 39: /// </summary> 40: /// <returns>WinForm/WPF用户控件。</returns> 41: object GetBottomControl(); 42: 43: /// <summary> 44: /// 获取WinForm/WPF容器的关于对话框,用于替换平台的关于对话框。 45: /// </summary> 46: /// <returns>WinForm/WPF窗体。</returns> 47: object GetAboutForm(); 48: 49: /// <summary> 50: /// 获取WinForm/WPF容器的主界面,用于替换平台的主界面。 51: /// </summary> 52: /// <returns>WinForm/WPF窗体。</returns> 53: object GetMainShell(); 54: 55: /// <summary> 56: /// 获取WinForm/WPF/Silverlight容器的登录对话框,用于替换平台的登录对话框。 57: /// </summary> 58: /// <returns>WinForm/WPF/Silverlight窗体。</returns> 59: ILoginForm GetLoginForm(); 60: 61: /// <summary> 62: /// 获取WinForm/WPF容器的起始页/初始模块,用于替换平台的起始页。 63: /// </summary> 64: /// <returns>WinForm/WPF用户控件。</returns> 65: object GetStartModule(); 66: 67: /// <summary> 68: /// 获取系统的名称,显示在运行环境的导航栏。 69: /// </summary> 70: /// <returns>应用系统名称。</returns> 71: string GetApplicationName(); 72: 73: /// <summary> 74: /// 获取系统的标题,显示在运行环境的主窗口之上。 75: /// </summary> 76: /// <returns>应用系统名称。</returns> 77: string GetApplicationTitle(); 78: 79: /// <summary> 80: /// 是否显示主菜单。 81: /// </summary> 82: bool DisplayMainMenu 83: { 84: get; 85: } 86: 87: /// <summary> 88: /// 是否显示导航工具条。 89: /// </summary> 90: bool DisplayNavigationTool 91: { 92: get; 93: } 94: } 95: } 实现AgileEAS.NET SOA 平台的资源替换即是实现IResource接口的过程,在我们DrugShop、SmartERP案例之中都有对应的实现项目DrugShop.Res和SmartERP.Res。 当然,光实现IResource还不购,还需要修改系统的配置文件,以便让资源生效: 1: <;!--资源--> 2: <object name="EAS.Explorer.Resource" assembly="DrugShop.Res" type="DrugShop.Res.Resources" LifestyleType="Singleton"/> 需要注意的是在EAS.Explorer.dll程序集之中还定义了以下两个接口,INavigation接口: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Text.RegularExpressions; 6: 7: namespace EAS.Explorer 8: { 9: /// <;summary> 10: /// 导航控件接口。 11: /// <;/summary> 12: public interface INavigation 13: { 14: /// <;summary> 15: /// 初始化导航。 16: /// <;/summary> 17: /// <;param name="m_GroupList">导航清单。</param> 18: /// <;param name="m_ModuleList">模块清单。</param> 19: void Initialize(IList<;INavigateGroup> m_GroupList, IList<INavigateModule> m_ModuleList); 20: } 21: } ILoginForm接口: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: 6: namespace EAS.Explorer 7: { 8: /// <;summary> 9: /// 定义登记对话框接口,用于实现自定义登录。 10: /// <;/summary> 11: public interface ILoginForm 12: { 13: /// <;summary> 14: /// 是否已经通过登录验证。 15: /// <;/summary> 16: bool Passed { get; } 17: } 18: } 自定义的导航控件必须实现INavigation接口,以便于平台实现导航的初始化,方法Initialize由平台调用,传入当前系统登录人员所具有权限的模块清单及相关的导航清单。 自定我的登录界面必须实现ILoginForm,以便于系统判定登录界面是否完成了登录验证。 四、IMainShell接口和自定义主界面 第三节在介绍IResource接口的时候我们会发现其他有一个GetMainShell()方法,其用于获取资源实现之中的主界面定义,系统主界面必须是一个Form并且要实现IMainShell接口: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: 6: namespace EAS.Explorer 7: { 8: /// <;summary> 9: /// 定义主界面接口,用于实现自定义主界面。 10: /// <;/summary> 11: public interface IMainShell 12: { 13: /// <;summary> 14: /// 初始化主界面,根据平台传入的模块清单和相关的导航分组初始化主界面。 15: /// <;/summary> 16: /// <;param name="m_GroupList">导航清单。</param> 17: /// <;param name="m_ModuleList">模块清单。</param> 18: void InitializeShell(IList<;INavigateGroup> m_GroupList, IList<INavigateModule> m_ModuleList); 19: 20: /// <;summary> 21: /// 加载/打开指定模块,响应系统的模块打开操作。 22: /// <;/summary> 23: /// <;param name="module">模块实例。</param> 24: void OpenModule(object module); 25: 26: /// <summary> 27: /// 关闭当前模块(活动的模块)。 28: /// <;/summary> 29: void CloseModule(); 30: 31: /// <summary> 32: /// 关闭指定模块。 33: /// <;/summary> 34: /// <;param name="module">模块实例。</param> 35: void CloseModule(object module); 36: 37: /// <summary> 38: /// 切换导航,展开、隐藏导航,主界面没有导航的隐藏、展开需求可以不处理。 39: /// <;/summary> 40: void SwitchNavigation(); 41: 42: /// <summary> 43: /// 当前活动插件/模块。 44: /// <;/summary> 45: object ActiveAddIn 46: { 47: get; 48: } 49: 50: /// <;summary> 51: /// 已打开的插件/模块集合。 52: /// <;/summary> 53: List<;object> AddIns 54: { 55: get; 56: } 57: } 58: } 其中InitializeShell方法:用于平台传入当前系统登录人员所具有权限的模块清单及相关的导航清单,由自定义界面实现界面的初始化。 OpenModule方法:用于实现对模块的打开,平台传入要打开的模块,由主界面进行处理,实现主界面对模块的动态加载。 CloseModule方法:用于关闭已经打开的模块,并对界面进行清理。 SwitchNavigation方法:切换导航,展开、隐藏导航,主界面没有导航的隐藏、展开需求可以不处理。 ActiveAddIn属性:向平台返回当前的活动模块。 AddIns属性:向平台返回已加载的模块清单。 四、自定义界面实例 近期 有朋友建议使用devcomponents或者DotNetBar为大家演示一下如何自定义平台的主体界面,参考了网有对devcomponents和DotNetBar相关的资料之后我们选择了较为轻量级的DotNetBar为大家演示如何替换系统的主界面。 我们使用DotNetBar所提供的一些控件实现了以下三种风格的主体界面: 第一种是Win7/Ribbon风格的主界面RibbonShell,如下图所示: 其对应代码为DrugShop案例之中的DrugShop.Res项目之中的RibbonShell.cs程序文件。 第二种为类似Visual Studio界面风格的DockableShell,其效果如下: 其对应代码为DrugShop案例之中的DrugShop.Res项目之中的DockableShell.cs程序文件。 第三种为不包含导航栏的简单MDI界面风格的TabShell,其效果如下: 其对应代码为DrugShop案例之中的DrugShop.Res项目之中的TabShell.cs程序文件。 五、关于代码 以上介绍了三种风格的自定义主界面的例子,例子不多,也不复杂,或许也不能满足所有人的美观度需求和功能需求,其目的在于抛砖引用,希望借此文让更多的开发者加入到我们的行列之中来,做出更加美观大方的界面。 关于以上三种风格自定义界面代码,我们已经合并到DrugShop案例和SmartEPR案例之中,请大家在AgileEAS.NET SOA中间件官方网站的最新下载栏目进行下载。 在启动自定义界面的过程之中切记要修改资源项目之中IResource的实现代码之中的GetMainShell方法代码: 1: public object GetMainShell() 2: { 3: return new RibbonShell(); //Ribbon风格自定义界面。 4: //return new DockableShell(); //Dockable风格自定义界面。 5: //return new TabShell(); //TabMdi风格自定义界面。 6: //return null; //使用AgileEAS.NET SOA平台自带界面。 7: } 本文所使用的是DotNetBar115版本,有关于DotNetBar115请通过http://42.121.30.77/downloads/DotNetBar115.rar下载。 六、联系我们 为完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET SOA中间件平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、关于SmartERP.NET SmartERP.NET 是一套简单的电脑耗材分销ERP系统,其实说是ERP系统还有点夸张,但是最初的开发者都已经这么叫了,那么我们也就也就这么理解吧,SmartERP.NET 原本是我们的一个客户在2011年为其一个客户/朋友开发的一套软件,当时客户人员的开发都是以VB6.0进行开发,客户打算把开发语言换到C#上,基于我们平台进行技术预研,并且打算基于AgileEAS.NET SOA中间件平台进行应用开发,正好当然有一个朋友是做某品牌电脑大区经销的,双方双有所需,正好就基于我们AgileEAS.NET SOA中间件开发了这套简单的ERP系统,其目的有两个,一个是解决客户的需求、另一个是锻炼一下自己的开发人员。 以下是系统主界面: 什么是ERP: ERP是Enterprise Resource Planning(企业资源计划)的简称,是一种主要面向制造行业进行物质资源、资金资源和信息资源集成一体化管理的企业信息管理系统。 ERP是一个以管理会计 为核心可以提供跨地区、跨部门、甚至跨公司整合实时信息的企业管理软件。 参见百度百科: http://baike.baidu.com/subview/109408/7177679.htm SmartERP.NET货物采购入库流程 SmartERP.NET 货物销售流程 三、系统客户端及服务端配置 有关程序如何配置请参见 魏琼东的文章 AgileEAS.NET SOA 中间件平台 5.2 发布说明-包含Silverlight及报表系统的开源代码下载 AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(一):下载平台并基于直连环境运行 AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(二):配置WinClient分布式运行环境 AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(三):配置ActiveXForm运行环境 AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(四):开源的Silverlight运行容器的编译、配置 四、完整的应用-实现完整的ERP 本文我们将实现一个类似电脑城的货物ERP系统,主界面如下:(登录账户:erp-admin 密码为空) 五、下载源代码编译配置运行 本案例源代码请通AgileEAS.NET SOA中间件官方网站的最新下载中的栏目进行下载或者从SVN中获取最新版本的源代码: 下载或者SVN-OUT得到代码之后我们来看一下代码文建构: 一级目录 二级目录 说明 Code 程序源代码 SmartERP.Entities 实体(ORM)代码 SmartERP.BLL.Contracts 业务契约定义代码 SmartERP.BLL.Host 数据实现代码 SmartERP.Common 公用类库 SmartERP.WinUI 界面层代码 db 用户数据库文件,SQL Server数据库 Documents 文档,用户模型文档 Bin 引用程序集及编译输出 用VS2010或者VS2012打开Code目录之中的SmartERP.sln解决方案进行编译,编译成功之后我们开始进行配置。 打开Bin目录之中的SmartERP.Main.exe.config进行客户端配置: 修改红色部分连接字符串 六、统计报表 SmartERP示例中使用的是Gird++ 报表程序 开发管理 -- GR报表管理 数据报表就是写SQL语句查询数据库 获取结果 对象报表就是通过查询内存对象 获取结果 报表的制作:为了降低入门的难度,本编介绍的是用数据报表也就是写SQL语句查询数据库的方式,对象报表将在以后的文章中介绍。 1.新建-数据报表-查询语句中 写入要查询的报表sql语句 2.报表设计界面 3.设置要显示的是哪张报表,根据GUID 4.编写查询语句 并设置过滤条件 5. 报表预览效果 由于时间仓促,程序难免会有Bug,望大家谅解。 截止这里 我们的教程就已经写完了,表结构及相关说明请参阅SmartErp.NET下载包里面的相关文档。 最后感谢SmartErp.NET的原始作者陶虎刚同学,也感谢对原始代码、文档进行整理升级,以及本文的作者计文析同学。 七、联系我们 为完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET SOA中间件平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、关于Silverlight运行容器 在2011年秋天的的时候,曾经在Silverlight企业应用开发实践-AgileEAS.NET平台5.0 Silverlight支撑预览一文之中向大家介绍过AgileEAS.NET SOA中间件平台的Silverlight运行容器,其主要目的是当时有很多朋友希望我们能支撑Silverlight的应用开发,我们就基于我们AgileEAS.NET SOA中间件平台的“敏捷并行开发思想事件”、结合“插件开发&整合”思路、AgileEAS.NET SOA中间件平台的数据访问并结合AgleEAS.NET SOA中件的SOA分布式通信技术。 目前AgileEAS.NET SOA中间件Silverlight运行容器主要应用于医疗、物联网、ERP、CRM之类人企业内部应用之中。 AgileEAS.NET SOA 中间件平台Silverlight运行容器为开发人员带来如下好处: 1.)开发Silverlight应用同开发WinForm/WPF/WebForm/WebMVC应用一样可以使用AgileEAS.NET SOA提供的ORM和Linq技术。 2.)Silverlight应用同其他WinForm/WPF/WebForm/WebMVC应用使用同样的分布式服务端平台。 3.)Silverlight应用同其他WinForm/WPF/WebForm/WebMVC应用使用同样的服务端业务代码。 4.)为应用开发人员提供了类似在Silverlight客户段直接访问远程数据库的功能,提供了类似DataTable的数据结构Matrix。 5.)AgileEAS.NET SOA中间件平台已经实现了与WinForm/WPF运行环境同样的资源管理平台的系列功能(模块管理、权限、用户、角色)以及工作流系统绝大多数功能。 6.)AgileEAS.NET SOA中间件平台Silverlight运行容器源代码是以开源形式向大家提供的,大家可以在此基础上做一些在学大的调整。 三、学习Silverlight运行容器代码结构并进行编译 ActiveXForm运行容器的运行网站由在”Silverlight.src”目录之中以源代码形式向大家提供,我们用VS2010或者VS2012打开”Silverlight.src”目录之中的”AgileEAS.NET.Silverlight”解决方案: ”AgileEAS.NET.Silverlight”解决方案之中共有九个项目: EAS.BPM.SilverlightUI:为BPM工作流系统的界面元素文件,AgileEAS.NET SOA中间件的Silverlight运行环境的工作流支持管理功能功能都由这个项目提供。 EAS.Demo.Res:AgileEAS.NET SOA中间件的Silverlight运行环境的客户端演示资源插件,即用于替换AgileEAS.NET SOA中间件的Silverlight运行环境主界面,登录界面的界面定义代码的一个示例。 EAS.Explorer:AgileEAS.NET SOA中间件的Silverlight运行环境的一些接口定义,主要是资源替换接口的定义。 EAS.Explorer.Entities:AgileEAS.NET SOA中间件的Silverlight运行环境管理功能的数据实体定义,比如账号、角色、模块、报表等对象的定义。 EAS.Explorer.BLL.Contracts:AgileEAS.NET SOA中间件的Silverlight运行环境管理功能的服务契约定义,因为Silverlight是分布式运行的,即业务的实现在SOA服务之中运行,所以客户端只有业务契约,没有实现实体。 EAS.SilverlightClient:AgileEAS.NET SOA中间件的Silverlight运行环境主要程序,在这里面实现了一个可替换的插件应用环境。 EAS.SilverlightClient.AddIn:AgileEAS.NET SOA中间件的Silverlight运行环境管理功能的实现程序,主要实现了模块管理、角色账号、权限、组织机构等等。 EAS.SilverlightClient.AdminKit:辅助程序,本身没有多大意思,其功能是把EAS.SilverlightClient.AddIn和EAS.BPM.SilverlightUI打成一个EAS.SilverlightClient.AdminKit.xap包。 EAS.SilverlightClient.Web:AgileEAS.NET SOA中间件平台Silverlight运行容器的入口网站,即功能承载网站,包括一个首页及Silverlight XAP包的部署目录及客户端运行时所需要的配置文件和XAP包的自动升级配置。 了解了这九个项目的功能之后我们开始编译整个解决方案,保证所有项目编译通过: 了解了这八个项目的功能之后我们开始编译整个解决方案,保证所有项目编译通过: 四、配置并运行Silverlight运行容器 Silverlight应用是不直接连接数据库进行处理的,所以配置ActiveXForm运行容器/环境必须有一个先决条件,那就是Silverlight必须运行的AgileEAS.NET SOA 中间件的分布式环境下,即我们的SOA服务端必须运行,关于如何做这此工作,请参考前面的AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(二):配置WinClient分布式运行环境一文。 那么我们首先启动运行“AppServer\Bin”目录之中的“soaserver.start.bat”脚本,运行SOA服务: 接下来我们开始配置Silverlight运行容器的一些参数、以及Silverlight客户端XAP文件的升级配置,这些配置信息记录在项目”EAS.SilverlightClient.Web”的“ClientBin”目录之中,文件名称为“slconfig.xml”和“slUpdate.xml”。 其中“slconfig.xml”为Silverlight应用的系统配置文件,其内容如下: 1: <?xml version="1.0" encoding="utf-8"?> 2: <eas> 3: <configurations> 4: <item name="Key" value="Value" /> 5: <!--是否调试状态。--> 6: <item name="Debug" value="false" /> 7: <!--调试程序集。--> 8: <item name="Assembly" value="EAS.SilverlightClient.AddIn" /> 9: <!--外挂资源包。--> 10: <!--<item name="EAS.Explorer.Resource" value="EAS.Explorer.Res.xap,EAS.Explorer.Res.dll,EAS.Explorer.Res.Resources" />--> 11: </configurations> 12: <objects> 13: <!--分布式通信组件。--> 14: <object name="ServiceBridger" assembly="EAS.MicroKernel" type="EAS.Distributed.ServiceBridger" LifestyleType="Thread" > 15: <property name="ServiceUrl" type="string" value="http://localhost:6608/eas/services/EAS.RIAService" /> 16: </object> 17: <object name="DataAccessor" assembly="EAS.Data" type="EAS.Data.Access.DataAccessor" LifestyleType="Thread"> 18: <property name="ServiceBridger" type="object" value="ServiceBridger"/> 19: </object> 20: <object name="OrmAccessor" assembly="EAS.Data" type="EAS.Data.ORM.OrmAccessor" LifestyleType="Thread"> 21: <property name="ServiceBridger" type="object" value="ServiceBridger"/> 22: </object> 23: </objects> 24: </eas> 其中参数Debug表示系统是否为调试模式,即加载某一个Silverlight程序集并自动加载其中的插件进行调试运行,如果这个值为True,则系统会自动加载参数Assembly所指向的程序集,并加载其中的插件到系统导航之中,并跳过系统对登录账号的对所加载模块的权限检查,直接运行,如果这个参数为False,则Assembly参数无效,系统按照当前登录账号的权限加载导航,运行时也运行模块权限检测,一版情况下在开发过程之中我们都采用调试模式,这样可以省去安装配置插件的过程,而在生产过程,我们则使用非调试模式。 参数EAS.Explorer.Resource为外挂界面资源的配置,类似于WinClient的配置,我们不要修改他。 对像ServiceBridger的属性ServiceUrl配置了远程RIA服务的地址,即SOA服务实现之中的RIA服务的地址: 1: <object name="ServiceBridger" assembly="EAS.MicroKernel" type="EAS.Distributed.ServiceBridger" LifestyleType="Thread" > 2: <property name="ServiceUrl" type="string" value="http://localhost:6608/eas/services/EAS.RIAService" /> 3: </object> 一搬情况下,我们只需要修改IP地址或者域名即可,后面的不要做修改。 接下来我们打开升级配置“slUpdate.xml”: 1: <?xml version="1.0" encoding="utf-8"?> 2: <SmartConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 3: <URI>http://www.smarteas.net/</URI> 4: <Name>AgileEAS.NET升级配置文件</Name> 5: <Description>用于AgileEAS.NET平台SmartClient/ActiveX运行容器模块升级之用</Description> 6: <StartEx /> 7: <Time>2013-10-16T16:13:19.7125705+08:00</Time> 8: <Files> 9: <SmartFile> 10: <FileName>EAS.SilverlightClient.AdminKit.xap</FileName> 11: <Version>1.1.0.0</Version> 12: <Time>2013-10-16T09:54:19.7125705+08:00</Time> 13: </SmartFile> 14: <SmartFile> 15: <FileName>WF.Demo.SilverlightUI.xap</FileName> 16: <Version>1.1.0.0</Version> 17: <Time>2013-10-16T09:54:19.7125705+08:00</Time> 18: </SmartFile> 19: </Files> 20: </SmartConfig> 这个配置文件结构等同于前面的AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(二):配置WinClient分布式运行环境一文之中“EAS.SmartUpdateConfig.exe”工作所生成的文件,只不过,此处手工配置,而不是工具生成,我们需要把下载到客户端Silverlight环境之中的文件(主要是一些XAP包)以SmartFile配置信息形式记录在这个配置文件之中,需要多次注意的是,客户端会依据这个文件的最后时间进行更新。 OK,Silverlight环境的配置到这就可以了,接下来我们运行AgileEAS.NET SOA 中间件Silverlight运行容器看看。 按F5运行”EAS.SilverlightClient.Web”项目,打开浏览器: 输入用户名:Administrator,密码:sa然后点击登录,系统会有如下有“是否增加可用存储”的提示: 因为AgileEAS.NET SOA 中间件设置为支持Silverlight的本地存储文件,以缓存XAP包和某些业务数据,我们选择点击“是”,然后重新输入密码进行登录,将会打开系统主界面: 我们选择某个功能进行操作: OK,Silverlight运行容器搞定。 五、联系我们 为了完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台了开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 技术团队成员都是合作多年的老朋友,因为这个平台是免费的,我们的营运开支主要靠为客户提供咨询服务所得,我们都是因为程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友和一直支持我们工作的客户、朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381 AgileEAS.NET QQ群: 113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、关于ActiveXForm运行容器 在我早期的博客园文章基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET - ActiveXForm运行容器曾经向大家介绍过AgileEAS.NET SOA中间件平台的ActiveXForm运行容器,其主要用于把早期用WinForm开发的程序跑在IE浏览器之中,给用户造成一个BS项目的错觉,本来打算在4.0版本之中就给大家公开下载和发布的,但是鉴于之前直接在网上部署引用的一下配置问题的反馈我们并没有公开发布给大家。 如果是做互联网项目,使用ActiveXForm技术来做BS应用,那么我们很直接的告诉你,这事你是找抽,不靠谱,也不可取,但是在做内部管理信息系统的时候,比如财务、EPR、HIS、电子病历等这些项目,这东西又是一种可以去尝试的做法,我们虽然没有公开发布ActiveXForm但是我们一真在为使用ActiveXForm的软件企业提供技术帮助和升级。 AgileEAS.NET SOA 中间件平台所提供的功能都是比较实现的企业应用开发功能,在5.0发布之后就有很多企业希望能得到有关于ActiveXForm的发布包和技术支持资料,所以我们决定在AgileEAS.NET SOA中间件5.2版本之中提供ActiveXForm的内容,也在配置和使用上面提供一些文档资料。 三、配置ActiveXForm运行容器 配置ActiveXForm运行容器/环境必须有一个先决条件,那就是系统必须具有自动升级功能,即我们的SOA服务端必须运行并且配置好自动升级,关于如何做这此工作,请参考前面的AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(二):配置WinClient分布式运行环境一文。 那么我们首先启动运行“AppServer\Bin”目录之中的“soaserver.start.bat”脚本,运行SOA服务: 接下来我们开始配置ActiveXForm运行容器。 ActiveXForm运行容器的运行网站由在”ActiveXForm.Web”目录之中以源代码形式向大家提供,我们用VS2010或者VS2012打开”ActiveXForm.Web”目录之中的”EAS.ActiveXForm.Web”解决方案: 在”EAS.ActiveXForm.Web”项目之中,我们会看到如下结构: 首先我们修改”xClient\config”目录之中的文件”clientclasp.xml”和”activexForm.xml”两个配置文件,其中”clientclasp.xml”定义了ActiveXForm引擎/客户端钩子的定义,主要包括程序的升级定义,内容如下: 1: <?xml version="1.0" encoding="utf-8"?> 2: <ClientClasp> 3: <!--客户端钩子启动模块。--> 4: <item name="ClaspStart" value="EAS.ActiveXForm.ClaspStart,EAS.ActiveXForm.ClientClasp.AddIn" /> 5: <!--应用系统名称。--> 6: <item name="ApplicationName" value="AgileEAS.Net SOA中间件" /> 7: <!--是否开启升级。--> 8: <item name="AllowUpdate" value="true" /> 9: <!--升级服务地址。--> 10: <item name="UpdateUrl" value="net.tcp://localhost:6607/eas/services/eas.updateservice" /> 11: </ClientClasp> 其中配置项目”claspstart”为客户端初始化参数,这个不需要改变,”ApplicationName”为升级程序的标题显示,”AllowUpdate”是否开启升级,”UpdateUrl”为升级地址,关于具体的配置参数得参考AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(二):配置WinClient分布式运行环境一文中服务端的配置参数。 ”activexForm.xml”配置文件为ActiveXForm应用程序的运行配置,其内容和AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(二):配置WinClient分布式运行环境一文这是分布式环境情况下“EAS.WinClient.Start.exe.config”配置文件内容一模一样,我们可以把配置复制过来: 1: <?xml version="1.0" encoding="utf-8"?> 2: <configuration> 3: <configSections> 4: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel" /> 5: </configSections> 6: <!--SQLite运行必需--> 7: <startup useLegacyV2RuntimeActivationPolicy="true"> 8: <supportedRuntime version="v4.0"/> 9: </startup> 10: <eas> 11: <configurations> 12: <item name="Key" value="Value" /> 13: </configurations> 14: <objects> 15: <!--分布式通信组件。--> 16: <object name="ServiceBridger" assembly="EAS.Distributed" type="EAS.Distributed.ServiceBridger" LifestyleType="Thread" > 17: <property name="ServiceName" type="string" value="EAS.RMI.Service" /> 18: </object> 19: <object name="DataAccessor" assembly="EAS.Distributed" type="EAS.Distributed.DataAccessor" LifestyleType="Thread" > 20: <property name="ServiceBridger" type="object" value="ServiceBridger" /> 21: </object> 22: <object name="OrmAccessor" assembly="EAS.Distributed" type="EAS.Distributed.OrmAccessor" LifestyleType="Thread" > 23: <property name="ServiceBridger" type="object" value="ServiceBridger" /> 24: <property name="DataAccessor" type="object" value="DataAccessor" /> 25: </object> 26: <!--日志管理--> 27: <object name="Logger" assembly="EAS.MicroKernel" type="EAS.Loggers.TextLogger" LifestyleType="Singleton" /> 28: <!--资源--> 29: <!--<object name="EAS.Explorer.Resource" assembly="EAS.Explorer.Res" type="EAS.Explorer.Res.Resources" LifestyleType="Singleton" />--> 30: </objects> 31: <services> 32: <service name="EAS.RMI.Service" service-type="WcfService" singleton="true" url="net.tcp://127.0.0.1:6607/eas/services/EAS.RMIService" /> 33: <service name="EAS.Storage.Service" service-type="WcfService" singleton="true" url="net.tcp://127.0.0.1:6607/eas/services/EAS.StorageService" /> 34: </services> 35: </eas> 36: </configuration> 接下来我们配置“Web.config”文件,因为ActiveXForm运行的登录验证需要访问验证服务,所以我们必须配置“Web.config”,其内容如下: 1: <?xml version="1.0" encoding="utf-8"?> 2: <configuration> 3: 4: <configSections> 5: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel" /> 6: </configSections> 7: 8: <!--支持混合程序集--> 9: <startup useLegacyV2RuntimeActivationPolicy="true"> 10: <supportedRuntime version="v4.0"/> 11: </startup> 12: <eas> 13: <configurations> 14: <item name="Key" value="Value" /> 15: </configurations> 16: <objects> 17: <!--分布式通信组件。--> 18: <object name="ServiceBridger" assembly="EAS.Distributed" type="EAS.Distributed.ServiceBridger" LifestyleType="Thread" > 19: <property name="ServiceName" type="string" value="EAS.RMI.Service" /> 20: </object> 21: <object name="DataAccessor" assembly="EAS.Distributed" type="EAS.Distributed.DataAccessor" LifestyleType="Thread" > 22: <property name="ServiceBridger" type="object" value="ServiceBridger" /> 23: </object> 24: <object name="OrmAccessor" assembly="EAS.Distributed" type="EAS.Distributed.OrmAccessor" LifestyleType="Thread" > 25: <property name="ServiceBridger" type="object" value="ServiceBridger" /> 26: <property name="DataAccessor" type="object" value="DataAccessor" /> 27: </object> 28: <!--日志管理--> 29: <object name="Logger" assembly="EAS.MicroKernel" type="EAS.Loggers.TextLogger" LifestyleType="Singleton" /> 30: </objects> 31: <services> 32: <service name="EAS.RMI.Service" service-type="WcfService" url="net.tcp://localhost:6607/eas/services/EAS.RMIService" /> 33: </services> 34: </eas> 35: 36: <system.web> 37: <compilation debug="true" targetFramework="4.0" /> 38: <httpModules> 39: <add name="SecurityDemandModule" type="EAS.Explorer.Web.SecurityDemandModule, EAS.Explorer.Web"/> 40: </httpModules> 41: </system.web> 42: 43: </configuration> 在配置文件的“configuration/eas/objects”之中的内容同ActiveXForm.xml文件内容一致,但是没有“EAS.Explorer.Resource”,在ActieXForm.xml和Web.Config文件之中,重点是远程服务地址的配置: 1: <services> 2: <service name="EAS.RMI.Service" service-type="WcfService" singleton="true" url="net.tcp://127.0.0.1:6607/eas/services/EAS.RMIService" /> 3: </services> ActiveXForm运行之前的配置到这就可以了,接下来看运行时的IE设置。 四、ActiveXForm运行时的IE设置 把“Default.aspx”设为起始页,然后按F5运行”EAS.ActiveXForm.Web”项目,打开IE浏览器,有如下界面: 很显然,IE的安全性阻止ActiveXForm的运行,我们按下面的提示点击“安装根证书”,会有如下提示: 选择打开,弹出如下窗口: 点击“安装证书”继续: 选择“下一步”: 选中“将所有的证书放入下列存储”,点击“浏览”: 选择“受信任的根证书颁发机构”,点击“确定”: 点击“下一步”: 点击“完成”进行证书安装,将会弹出证书安装确定: 点击“是”完成证书安装,然后我们重新打开“Default.aspx”页面: 在IE安全提示“?”处点鼠标邮: 选中“为计算机上的所有用户安装此加载项(A)”,将会弹出“ActiveXForm插件”安装对话框: 点击“安装”,IE会自动安装AgileEAS.NET SOA中间件ActiveXForm插件,安装完成后系统会有如下升级提示: 点击“确定”,打开自动升级程序进行升级: 升级完成之后点击“关闭”然后重新打开打开“Default.aspx”页面,发布不再提示脚本错误: 输入用户名:Administrator,密码:sa之后点击“登录”,系统将会为我们呈现出AgileEAS.NET SOA 中间件ActiveXForm运行容器的主界面: 我们随便打开个功能看看是否好用,比如打开模块管理,并查看某个模块的属性: 是否发现这界面似曾相似^_^ 五、如果配置不成功 如果按照第四节的配置还是不能运行成功运行,那么首先打开首页之后,把当前网站localhost加入到可信息站点: 然后再进行第四节的配置,如果还不行,那么打开首页之设置IE“可信站点”区域的安全性,选择自定义级别,启用“对未标记为可安全执行脚本的ActiveX控件初始化并且执行脚本: 然后再进行第四节的操作,如果还是不行,那么请打开首页之后: 即手机下载msi安装包文件”xClient/downloads/EAS.ActiveXForm.msi”安装项目,进行手工安装,安装完成之后重新打开“Default.aspx”页面。 六、ActiveXForm的特点与局限 AgileEAS.NET SOA中间件ActiveXForm运行容器的本质是通过一个浏览器插件,把原来基于AgileEAS.NET SOA中间件平台所开发的WinForm/WPF应用运行与IE浏览器之中,以达到通过Winform/WPF开发BS应用(此处需要说明一下应该是伪BS应用),非常适合没有BS开发能力的一些中小管理软件企业,基于某些原因,ActiveXForm这种方式的伪BS应用非常的广,比如企业内部的财务系统、医院的电子病历、区域公共卫生平台之中的医疗机构信息系统,企业内部使用的其他一些系统之中。 AgileEAS.NET SOA中间件ActiveXForm运行容器并不只能运行基于AgileEAS.NET SOA中间件开发的应用系统,理论上可以扩展为可以把任何用WinFrom/WPF开发的系统都能转换为这种ActiveXForm加载的BS应用。 当然了,AgileEAS.NET SOA中间件ActiveXForm这种模式的应用也是有很大的局限的,比如,非常不适合在互联网上运行,因为其所有客户端都需要安装.NET Framework ,也需要安装ActiveXForm插件、导入证书甚至设置安全性。 七、联系我们 为了完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台了开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 技术团队成员都是合作多年的老朋友,因为这个平台是免费的,我们的营运开支主要靠为客户提供咨询服务所得,我们都是因为程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友和一直支持我们工作的客户、朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381 AgileEAS.NET QQ群: 113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、配置分布式方式运行WinClient运行容器 在前面的AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(一):下载平台并基于直连环境运行一文之中,为大家介绍了如何下载AgileEAS.NET SOA中间件平台,以及如何初始化数据库运行环境、配置以直连方式运行AgileEAS.NET SOA 中间件WinCleint以直接数据库方式运行。 本文我们将为大家讲解如何以配置以”SOA服务-分布式客户端”方向运行AgileEAS.ENT SOA中间件平台WinClient容器。 三、配置SOA分布式服务端 在配置服务端之湔我们抚运动一下下载包根目录之中的”EAS.Publisher.exe”应用程序: ”EAS.Publisher.exe”控件台应用程序是一个用于帮助开发人员进行分布式部署时的分发程序,其本质是将发布包“bin\dotnet”之中的程序集复制到“SOA服务”运行的环境目录“AppServer”下面的各级目录,运行程序如下: 运行时自动调用“eas.publish.cmd”脚本,将文件分发到“AppServer”下面的各级目录,其脚本内容如下: 1: @rem 复制到下载目录 2: copy @RootDirectory\bin\dotnet\AgileIM.Client.exe @RootDirectory\appserver\xclient\files\AgileIM.Client.exe /y 3: copy @RootDirectory\bin\dotnet\AgileIM.Client.exe.config @RootDirectory\appserver\xclient\files\AgileIM.Client.exe.config /y 4: copy @RootDirectory\bin\dotnet\AgileIM.Contracts.dll @RootDirectory\appserver\xclient\files\AgileIM.Contracts.dll /y 5: copy @RootDirectory\bin\dotnet\AgileIM.Service.dll @RootDirectory\appserver\xclient\files\AgileIM.Service.dll /y 6: copy @RootDirectory\bin\dotnet\AxInterop.grdesLib.dll @RootDirectory\appserver\xclient\files\AxInterop.grdesLib.dll /y 7: copy @RootDirectory\bin\dotnet\AxInterop.grproLib.dll @RootDirectory\appserver\xclient\files\AxInterop.grproLib.dll /y 8: copy @RootDirectory\bin\dotnet\EAS.ActiveXForm.ClientClasp.AddIn.dll @RootDirectory\appserver\xclient\files\EAS.ActiveXForm.ClientClasp.AddIn.dll /y 9: copy @RootDirectory\bin\dotnet\EAS.BPM.Activities.dll @RootDirectory\appserver\xclient\files\EAS.BPM.Activities.dll /y 10: copy @RootDirectory\bin\dotnet\EAS.BPM.BLL.Host.dll @RootDirectory\appserver\xclient\files\EAS.BPM.BLL.Host.dll /y 11: copy @RootDirectory\bin\dotnet\EAS.BPM.WinUI.dll @RootDirectory\appserver\xclient\files\EAS.BPM.WinUI.dll /y 12: copy @RootDirectory\bin\dotnet\eas.client.ini @RootDirectory\appserver\xclient\files\eas.client.ini /y 13: copy @RootDirectory\bin\dotnet\EAS.Configure.exe @RootDirectory\appserver\xclient\files\EAS.Configure.exe /y 14: copy @RootDirectory\bin\dotnet\EAS.Configure.exe.config @RootDirectory\appserver\xclient\files\EAS.Configure.exe.config /y 15: copy @RootDirectory\bin\dotnet\EAS.Data.Controls.dll @RootDirectory\appserver\xclient\files\EAS.Data.Controls.dll /y 16: copy @RootDirectory\bin\dotnet\EAS.Data.dll @RootDirectory\appserver\xclient\files\EAS.Data.dll /y 17: copy @RootDirectory\bin\dotnet\EAS.Data.Provider.dll @RootDirectory\appserver\xclient\files\EAS.Data.Provider.dll /y 18: copy @RootDirectory\bin\dotnet\EAS.Distributed.dll @RootDirectory\appserver\xclient\files\EAS.Distributed.dll /y 19: copy @RootDirectory\bin\dotnet\EAS.Explorer.BLL.Contracts.dll @RootDirectory\appserver\xclient\files\EAS.Explorer.BLL.Contracts.dll /y 20: copy @RootDirectory\bin\dotnet\EAS.Explorer.BLL.Host.dll @RootDirectory\appserver\xclient\files\EAS.Explorer.BLL.Host.dll /y 21: copy @RootDirectory\bin\dotnet\EAS.Explorer.dll @RootDirectory\appserver\xclient\files\EAS.Explorer.dll /y 22: copy @RootDirectory\bin\dotnet\EAS.Explorer.Entities.dll @RootDirectory\appserver\xclient\files\EAS.Explorer.Entities.dll /y 23: copy @RootDirectory\bin\dotnet\EAS.Explorer.Res.dll @RootDirectory\appserver\xclient\files\EAS.Explorer.Res.dll /y 24: copy @RootDirectory\bin\dotnet\EAS.Explorer.WinUI.dll @RootDirectory\appserver\xclient\files\EAS.Explorer.WinUI.dll /y 25: copy @RootDirectory\bin\dotnet\EAS.FormDesigner.exe @RootDirectory\appserver\xclient\files\EAS.FormDesigner.exe /y 26: copy @RootDirectory\bin\dotnet\EAS.GReport.Controls.dll @RootDirectory\appserver\xclient\files\EAS.GReport.Controls.dll /y 27: copy @RootDirectory\bin\dotnet\EAS.MicroKernel.dll @RootDirectory\appserver\xclient\files\EAS.MicroKernel.dll /y 28: copy @RootDirectory\bin\dotnet\EAS.Monitor.dll @RootDirectory\appserver\xclient\files\EAS.Monitor.dll /y 29: copy @RootDirectory\bin\dotnet\EAS.NLB.Monitor.exe @RootDirectory\appserver\xclient\files\EAS.NLB.Monitor.exe /y 30: copy @RootDirectory\bin\dotnet\EAS.NLB.Server.exe @RootDirectory\appserver\xclient\files\EAS.NLB.Server.exe /y 31: copy @RootDirectory\bin\dotnet\EAS.OrmDesigner.exe @RootDirectory\appserver\xclient\files\EAS.OrmDesigner.exe /y 32: copy @RootDirectory\bin\dotnet\EAS.OrmDesigner.exe.config @RootDirectory\appserver\xclient\files\EAS.OrmDesigner.exe.config /y 33: copy @RootDirectory\bin\dotnet\EAS.Report.Controls.dll @RootDirectory\appserver\xclient\files\EAS.Report.Controls.dll /y 34: copy @RootDirectory\bin\dotnet\EAS.SmartUpdater.exe @RootDirectory\appserver\xclient\files\EAS.SmartUpdater.exe /y 35: copy @RootDirectory\bin\dotnet\EAS.SOA.Monitor.exe @RootDirectory\appserver\xclient\files\EAS.SOA.Monitor.exe /y 36: copy @RootDirectory\bin\dotnet\EAS.ThirdParty.Controls.dll @RootDirectory\appserver\xclient\files\EAS.ThirdParty.Controls.dll /y 37: copy @RootDirectory\bin\dotnet\EAS.WinClient.dll @RootDirectory\appserver\xclient\files\EAS.WinClient.dll /y 38: copy @RootDirectory\bin\dotnet\EAS.WinClient.Start.exe @RootDirectory\appserver\xclient\files\EAS.WinClient.Start.exe /y 39: copy @RootDirectory\bin\dotnet\EAS.WinClient.Start.exe.config @RootDirectory\appserver\xclient\files\EAS.WinClient.Start.exe.config /y 40: copy @RootDirectory\bin\dotnet\EAS.Windows.dll @RootDirectory\appserver\xclient\files\EAS.Windows.dll /y 41: copy @RootDirectory\bin\dotnet\EAS.Wpf.Controls.dll @RootDirectory\appserver\xclient\files\EAS.Wpf.Controls.dll /y 42: copy @RootDirectory\bin\dotnet\grdes50.dll @RootDirectory\appserver\xclient\files\grdes50.dll /y 43: copy @RootDirectory\bin\dotnet\gregn50.dll @RootDirectory\appserver\xclient\files\gregn50.dll /y 44: copy @RootDirectory\bin\dotnet\ICSharpCode.AvalonEdit.dll @RootDirectory\appserver\xclient\files\ICSharpCode.AvalonEdit.dll /y 45: copy @RootDirectory\bin\dotnet\Interop.grdesLib.dll @RootDirectory\appserver\xclient\files\Interop.grdesLib.dll /y 46: copy @RootDirectory\bin\dotnet\Interop.grproLib.dll @RootDirectory\appserver\xclient\files\Interop.grproLib.dll /y 47: copy @RootDirectory\bin\dotnet\itextsharp.dll @RootDirectory\appserver\xclient\files\itextsharp.dll /y 48: copy @RootDirectory\bin\dotnet\lua51.x64.dll @RootDirectory\appserver\xclient\files\lua51.x64.dll /y 49: copy @RootDirectory\bin\dotnet\lua51.x86.dll @RootDirectory\appserver\xclient\files\lua51.x86.dll /y 50: copy @RootDirectory\bin\dotnet\LuaInterface.x64.dll @RootDirectory\appserver\xclient\files\LuaInterface.x64.dll /y 51: copy @RootDirectory\bin\dotnet\LuaInterface.x86.dll @RootDirectory\appserver\xclient\files\LuaInterface.x86.dll /y 52: copy @RootDirectory\bin\dotnet\Microsoft.Data.ConnectionUI.Dialog.dll @RootDirectory\appserver\xclient\files\Microsoft.Data.ConnectionUI.Dialog.dll /y 53: copy @RootDirectory\bin\dotnet\Microsoft.Data.ConnectionUI.dll @RootDirectory\appserver\xclient\files\Microsoft.Data.ConnectionUI.dll /y 54: copy @RootDirectory\bin\dotnet\Microsoft.XmlNotepad.dll @RootDirectory\appserver\xclient\files\Microsoft.XmlNotepad.dll /y 55: copy @RootDirectory\bin\dotnet\MongoDB.dll @RootDirectory\appserver\xclient\files\MongoDB.dll /y 56: copy @RootDirectory\bin\dotnet\MySql.Data.dll @RootDirectory\appserver\xclient\files\MySql.Data.dll /y 57: copy @RootDirectory\bin\dotnet\NetronGraphLib.dll @RootDirectory\appserver\xclient\files\NetronGraphLib.dll /y 58: copy @RootDirectory\bin\dotnet\protobuf-net.xml @RootDirectory\appserver\xclient\files\protobuf-net.xml /y 59: copy @RootDirectory\bin\dotnet\RdlDesigner.dll @RootDirectory\appserver\xclient\files\RdlDesigner.dll /y 60: copy @RootDirectory\bin\dotnet\RdlEngine.dll @RootDirectory\appserver\xclient\files\RdlEngine.dll /y 61: copy @RootDirectory\bin\dotnet\RdlViewer.dll @RootDirectory\appserver\xclient\files\RdlViewer.dll /y 62: copy @RootDirectory\bin\dotnet\System.Data.SQLite.DLL @RootDirectory\appserver\xclient\files\System.Data.SQLite.DLL /y 63: copy @RootDirectory\bin\dotnet\System.Workflow.Activities.dll @RootDirectory\appserver\xclient\files\System.Workflow.Activities.dll /y 64: copy @RootDirectory\bin\dotnet\System.Workflow.ComponentModel.dll @RootDirectory\appserver\xclient\files\System.Workflow.ComponentModel.dll /y 65: copy @RootDirectory\bin\dotnet\System.Workflow.Runtime.dll @RootDirectory\appserver\xclient\files\System.Workflow.Runtime.dll /y 66: copy @RootDirectory\bin\dotnet\update.ini @RootDirectory\appserver\xclient\files\update.ini /y 67: copy @RootDirectory\bin\dotnet\WF.Demo.DAL.dll @RootDirectory\appserver\xclient\files\WF.Demo.DAL.dll /y 68: copy @RootDirectory\bin\dotnet\WF.Demo.UI.dll @RootDirectory\appserver\xclient\files\WF.Demo.UI.dll /y 69: @rem 复制到下载配置目录 70: copy @RootDirectory\bin\dotnet\EAS.SmartUpdateConfig.exe @RootDirectory\appserver\xclient\EAS.SmartUpdateConfig.exe /y 71: copy @RootDirectory\bin\dotnet\EAS.SmartUpdateConfig.exe.config @RootDirectory\appserver\xclient\EAS.SmartUpdateConfig.exe.config /y 72: @rem 复制到SOA服务Bin目录 73: copy @RootDirectory\bin\dotnet\AgileIM.Contracts.dll @RootDirectory\appserver\bin\AgileIM.Contracts.dll /y 74: copy @RootDirectory\bin\dotnet\AgileIM.Service.dll @RootDirectory\appserver\bin\AgileIM.Service.dll /y 75: copy @RootDirectory\bin\dotnet\EAS.BPM.Activities.dll @RootDirectory\appserver\bin\EAS.BPM.Activities.dll /y 76: copy @RootDirectory\bin\dotnet\EAS.BPM.BLL.Host.dll @RootDirectory\appserver\bin\EAS.BPM.BLL.Host.dll /y 77: copy @RootDirectory\bin\dotnet\EAS.Configure.exe @RootDirectory\appserver\bin\EAS.Configure.exe /y 78: copy @RootDirectory\bin\dotnet\EAS.Configure.exe.config @RootDirectory\appserver\bin\EAS.Configure.exe.config /y 79: copy @RootDirectory\bin\dotnet\EAS.Data.dll @RootDirectory\appserver\bin\EAS.Data.dll /y 80: copy @RootDirectory\bin\dotnet\EAS.Data.Provider.dll @RootDirectory\appserver\bin\EAS.Data.Provider.dll /y 81: copy @RootDirectory\bin\dotnet\EAS.Data.xml @RootDirectory\appserver\bin\EAS.Data.xml /y 82: copy @RootDirectory\bin\dotnet\EAS.DbInitializer.exe @RootDirectory\appserver\bin\EAS.DbInitializer.exe /y 83: copy @RootDirectory\bin\dotnet\EAS.DbInitializer.exe.config @RootDirectory\appserver\bin\EAS.DbInitializer.exe.config /y 84: copy @RootDirectory\bin\dotnet\EAS.Distributed.dll @RootDirectory\appserver\bin\EAS.Distributed.dll /y 85: copy @RootDirectory\bin\dotnet\EAS.Explorer.BLL.Contracts.dll @RootDirectory\appserver\bin\EAS.Explorer.BLL.Contracts.dll /y 86: copy @RootDirectory\bin\dotnet\EAS.Explorer.BLL.Host.dll @RootDirectory\appserver\bin\EAS.Explorer.BLL.Host.dll /y 87: copy @RootDirectory\bin\dotnet\EAS.Explorer.dll @RootDirectory\appserver\bin\EAS.Explorer.dll /y 88: copy @RootDirectory\bin\dotnet\EAS.Explorer.Entities.dll @RootDirectory\appserver\bin\EAS.Explorer.Entities.dll /y 89: copy @RootDirectory\bin\dotnet\EAS.MicroKernel.dll @RootDirectory\appserver\bin\EAS.MicroKernel.dll /y 90: copy @RootDirectory\bin\dotnet\EAS.Monitor.dll @RootDirectory\appserver\bin\EAS.Monitor.dll /y 91: copy @RootDirectory\bin\dotnet\EAS.NLB.Monitor.exe @RootDirectory\appserver\bin\EAS.NLB.Monitor.exe /y 92: copy @RootDirectory\bin\dotnet\EAS.NLB.Server.exe @RootDirectory\appserver\bin\EAS.NLB.Server.exe /y 93: copy @RootDirectory\bin\dotnet\EAS.NLB.Server.exe.config @RootDirectory\appserver\bin\EAS.NLB.Server.exe.config /y 94: copy @RootDirectory\bin\dotnet\EAS.NLB.Server.x64.exe @RootDirectory\appserver\bin\EAS.NLB.Server.x64.exe /y 95: copy @RootDirectory\bin\dotnet\EAS.SOA.Server.exe @RootDirectory\appserver\bin\EAS.SOA.Server.exe /y 96: copy @RootDirectory\bin\dotnet\EAS.SOA.Server.exe.config @RootDirectory\appserver\bin\EAS.SOA.Server.exe.config /y 97: copy @RootDirectory\bin\dotnet\EAS.SOA.Server.x64.exe @RootDirectory\appserver\bin\EAS.SOA.Server.x64.exe /y 98: copy @RootDirectory\bin\dotnet\EAS.SOA.Server.x64.exe.config @RootDirectory\appserver\bin\EAS.SOA.Server.x64.exe.config /y 99: copy @RootDirectory\bin\dotnet\lua51.x64.dll @RootDirectory\appserver\bin\lua51.x64.dll /y 100: copy @RootDirectory\bin\dotnet\lua51.x86.dll @RootDirectory\appserver\bin\lua51.x86.dll /y 101: copy @RootDirectory\bin\dotnet\LuaInterface.x64.dll @RootDirectory\appserver\bin\LuaInterface.x64.dll /y 102: copy @RootDirectory\bin\dotnet\LuaInterface.x86.dll @RootDirectory\appserver\bin\LuaInterface.x86.dll /y 103: copy @RootDirectory\bin\dotnet\MongoDB.dll @RootDirectory\appserver\bin\MongoDB.dll /y 104: copy @RootDirectory\bin\dotnet\MySql.Data.dll @RootDirectory\appserver\bin\MySql.Data.dll /y 105: copy @RootDirectory\bin\dotnet\RdlEngine.dll @RootDirectory\appserver\bin\RdlEngine.dll /y 106: copy @RootDirectory\bin\dotnet\RdlViewer.dll @RootDirectory\appserver\bin\RdlViewer.dll /y 107: copy @RootDirectory\bin\dotnet\soaserver.start.bat @RootDirectory\appserver\bin\soaserver.start.bat /y 108: copy @RootDirectory\bin\dotnet\soaserver.start.bat @RootDirectory\appserver\bin\install.bat /y 109: copy @RootDirectory\bin\dotnet\soaserver.start.bat @RootDirectory\appserver\bin\uinstall.bat /y 110: copy @RootDirectory\bin\dotnet\System.Data.SQLite.DLL @RootDirectory\appserver\bin\System.Data.SQLite.DLL /y 111: copy @RootDirectory\bin\dotnet\System.Workflow.Activities.dll @RootDirectory\appserver\bin\System.Workflow.Activities.dll /y 112: copy @RootDirectory\bin\dotnet\System.Workflow.ComponentModel.dll @RootDirectory\appserver\bin\System.Workflow.ComponentModel.dll /y 113: copy @RootDirectory\bin\dotnet\System.Workflow.Runtime.dll @RootDirectory\appserver\bin\System.Workflow.Runtime.dll /y 114: copy @RootDirectory\bin\dotnet\WF.Demo.DAL.dll @RootDirectory\appserver\bin\WF.Demo.DAL.dll /y 115: 其中@RootDirectory程序会根据运行时工作目录进行替换,注意:下载的AgileEAS.NET SOA中间件平台的解压目录路径之中最好不要带空格和中文。 接下来我们配置服务端,数据库我们将使用“AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(一):下载平台并基于直连环境运行一文所建立和初始化的”eas_demo”数据库。 我们运行“AppServer\Bin”目录之中的“EAS.Configure.exe”AgileEAS.NET SOA中间件配置文件生成工具生成服务端配置: 一定要选中“生成SOA分布式服务器配置”和“保存配置到AgileEAS.NET SOA 平台相关配置文件”然后点“下一步”: 填写WCF服务所需要的通信端口号(http和tcp各一个)、以及Socket通信服务的tcp的端口”以及数据库连接信息,然后点“下一步”: 界面上方是根据所设参数生成的配置信息,此处,可以改变配置信息的输出路径,默认为当前目录之中的“EAS.SOA.Server.exe.config”,点击“完成”输出配置: 至此,服务端的配置已经完成,接焉为我们以控件台方式运行一下SOA服务端,运行“AppServer\Bin”目录之中的“soaserver.start.bat”指处理文件: “soaserver.start.bat”批处理文件是SOA服务的控制台运行脚本,即以控制台模式运行SOA服务端,我们运行如下: “appServer\Binsoaserver.start.bat”批处理文件其内容如下: 1: EAS.soa.Server.exe -run 2: pause 其本质是“EAS.soa.Server.exe -run”这一旬,EAS.SOA.Server.exe带了一个启动参考 -run,即告诉EAS.SOA.Server.exe以控制台方式运行承载服务,除-run参数之外,EAS.SOA.Server.exe还支持以下参数: -i 或者/i:向Windows服务控制器安装AgileEAS.NET SOA中间件平台SOA服务。 -u 或者/u:卸载已存在的AgileEAS.NET SOA中间件平台SOA服务。 /name=实例名:在安装、卸载AgileEAS.NET SOA中间件平台SOA服务的时候,告诉服务控制器,要安装什么实例的名称是什么,AgileEAS.NET SOA中间件的服务设计为可以多服务实例运行,即一台电脑上可以运行实例名称为”EAS”、“Demo”、“HIS”、“EMR”、“PACS”等不同的服务实例,类似于SQL的命名实现,当然这个参数是一个可选参考,如果不使用本参数,则安装和卸载默认实例,一台电脑只能安装一个默认实例,比如以下脚本: “AppServer\Bin\install.bat”脚本 EAS.SOA.Server.exe /i /name=demo pause 表现安装一个实例名称为“demo”的AgileEAS.NET SOA中间件平台SOA服务实例,我们可以执行这个脚本: 我们打开系统管理工具之中的服务管理: 那以在生产环境之中我们就可以通过这种方式部署AgileEAS.NET SOA 中间件平台的SOA服务,服务安装之后会随计算机启动而自动启动,我们可以很方便的通过系统服务管理工具进行启动、停止服务,如果我们不使用这个服务了,我们可以使用以下脚本卸载这个服务: “AppServer\Bin\uinstall.bat”脚本 1: EAS.SOA.Server.exe /u /name=demo 2: pause 执行脚本如下: 我们运行“appServer\Bin\soaserver.start.bat”启动服务进行下一步配置。 四、配置分布式WinClient客户段 在第三节中我们使用”EAS.Publisher.exe”分发程序分发文件,会自动把客户段运行文件复制到”appServer\xclient\files”之中,那么我们运行”appServer\xclient\files\EAS.Configure.exe”配置程序配置客户端: 选中“生成客户端配置(分布式访问结果)”和“保存配置到AgileEAS.NET SOA 平台相关配置文件”然后点击“下一步”: 这里需要注意的是端口号要根据选择的通信模式和第三节所设置的服务器参数进行决定,tcp对应第三节服务器设置之中的WCF服务之中的Tcp端口号,http对应WCF服务之中的http端口号,socket对应socket服务模式之中的tcp端口号。 点击“下一步”继续: 点击“完成”输出客户端配置到“EAS.WinClient.Start.exe.config”配置文件之中,内容如下: 1: <?xml version="1.0" encoding="utf-8"?> 2: <configuration> 3: <configSections> 4: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel" /> 5: </configSections> 6: <!--SQLite运行必需--> 7: <startup useLegacyV2RuntimeActivationPolicy="true"> 8: <supportedRuntime version="v4.0"/> 9: </startup> 10: <eas> 11: <configurations> 12: <item name="Key" value="Value" /> 13: </configurations> 14: <objects> 15: <!--分布式通信组件。--> 16: <object name="ServiceBridger" assembly="EAS.Distributed" type="EAS.Distributed.ServiceBridger" LifestyleType="Thread" > 17: <property name="ServiceName" type="string" value="EAS.RMI.Service" /> 18: </object> 19: <object name="DataAccessor" assembly="EAS.Distributed" type="EAS.Distributed.DataAccessor" LifestyleType="Thread" > 20: <property name="ServiceBridger" type="object" value="ServiceBridger" /> 21: </object> 22: <object name="OrmAccessor" assembly="EAS.Distributed" type="EAS.Distributed.OrmAccessor" LifestyleType="Thread" > 23: <property name="ServiceBridger" type="object" value="ServiceBridger" /> 24: <property name="DataAccessor" type="object" value="DataAccessor" /> 25: </object> 26: <!--日志管理--> 27: <object name="Logger" assembly="EAS.MicroKernel" type="EAS.Loggers.TextLogger" LifestyleType="Singleton" /> 28: <!--资源--> 29: <!--<object name="EAS.Explorer.Resource" assembly="EAS.Explorer.Res" type="EAS.Explorer.Res.Resources" LifestyleType="Singleton" />--> 30: </objects> 31: <services> 32: <service name="EAS.RMI.Service" service-type="WcfService" singleton="true" url="net.tcp://127.0.0.1:6607/eas/services/EAS.RMIService" /> 33: <service name="EAS.Storage.Service" service-type="WcfService" singleton="true" url="net.tcp://127.0.0.1:6607/eas/services/EAS.StorageService" /> 34: </services> 35: </eas> 36: </configuration> 至此为止,我们完成了不带自动升级功能的分布式客户端配置,我们启动客户程序“EAS.WinClient.Start.exe”,并使用账号:Adminstrator,密码:sa登录,看到如下界面: 那么如何分辨程序是以分布式方式运行的呢,我们打开以控件台运行的SOA服务程序CMD窗口,就会看到其中一些消息通信记录: 五、配置自动升级 第四节我们在”appServer\xclient\files”目录之中成功配置了分布式客户端并且成功运行,那么我们”appServer\xclient\files”为基础配置一个自升级服务。 打开”appServer\xclient\files\update.ini”文件进行修改: 1: # AgileEAS.Net 平台升级控件文件。 2: 3: [config] 4: 5: allow = 0 6: application = EAS.WinClient.Start.exe 7: url = net.tcp://localhost:6607/eas/services/EAS.UpdateService 其中allow表示是否升级,url为升级服务地址,地址组成为wcf协议net.tcp://或http://+主机名称为IP+端口号+/eas/services/eas.updateservice,application表示升级完成之后启动运行的程序,我们根据第三节的配置修改如下: 1: # AgileEAS.Net 平台升级控件文件。 2: 3: [config] 4: 5: allow = 1 6: application = EAS.WinClient.Start.exe 7: url = net.tcp://localhost:6607/eas/services/EAS.UpdateService 然后我们删除目录里面的临时文件夹“Data”和“logs”,进行”appServer\xclient”,运行目录之中的”EAS.SmartUpdateConfig.exe“程序: ”EAS.SmartUpdateConfig.exe“程序是AgileEAS.NET SOA 中间件平台的升级配置程序,即当我们的应用的程序文件发生了新级和变更,需要把文件复制”appServer\xclient\files”目录之中,并且运行”EAS.SmartUpdateConfig.exe“程序以生成升级配置文件,升级配置文件存储在”appServer\xclient\conig”目录之中的”SmartUpdate.xml“文件之中,其内容如下: 1: <?xml version="1.0" encoding="utf-8"?> 2: <SmartConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 3: <URI>http://www.smarteas.net/</URI> 4: <Name>AgileEAS.NET SOA平台升级配置文件</Name> 5: <Description>用于AgileEAS.NET SOA平台SmartClient/ActiveX运行容器模块升级之用</Description> 6: <StartEx /> 7: <Time>2013-10-16T08:56:44.67765+08:00</Time> 8: <Files> 9: <SmartFile> 10: <FileName>AgileIM.Client.exe</FileName> 11: <Version>1.0.0.0</Version> 12: <Time>2013-10-15T16:59:23.5252+08:00</Time> 13: </SmartFile> 14: <SmartFile> 15: <FileName>AgileIM.Client.exe.config</FileName> 16: <Time>2013-08-27T12:10:12.0756571+08:00</Time> 17: </SmartFile> 18: <SmartFile> 19: <FileName>AgileIM.Contracts.dll</FileName> 20: <Version>1.0.0.0</Version> 21: <Time>2013-10-12T19:50:18.155+08:00</Time> 22: </SmartFile> 23: <SmartFile> 24: <FileName>AgileIM.Service.dll</FileName> 25: <Version>1.0.0.0</Version> 26: <Time>2013-10-15T16:59:24.5722599+08:00</Time> 27: </SmartFile> 28: <SmartFile> 29: <FileName>AxInterop.grdesLib.dll</FileName> 30: <Version>5.0.0.0</Version> 31: <Time>2013-10-12T19:50:02.442+08:00</Time> 32: </SmartFile> 33: <SmartFile> 34: <FileName>AxInterop.grproLib.dll</FileName> 35: <Version>5.0.0.0</Version> 36: <Time>2013-10-12T19:50:02.975+08:00</Time> 37: </SmartFile> 38: <SmartFile> 39: <FileName>EAS.ActiveXForm.ClientClasp.AddIn.dll</FileName> 40: <Version>1.0.0.0</Version> 41: <Time>2013-10-15T17:00:44.6468399+08:00</Time> 42: </SmartFile> 43: <SmartFile> 44: <FileName>EAS.BPM.Activities.dll</FileName> 45: <Version>1.1.0.0</Version> 46: <Time>2013-10-15T16:59:38.4650545+08:00</Time> 47: </SmartFile> 48: <SmartFile> 49: <FileName>EAS.BPM.BLL.Host.dll</FileName> 50: <Version>1.0.0.0</Version> 51: <Time>2013-10-15T17:00:41.6456682+08:00</Time> 52: </SmartFile> 53: <SmartFile> 54: <FileName>EAS.BPM.WinUI.dll</FileName> 55: <Version>2.0.0.0</Version> 56: <Time>2013-10-15T16:59:45.0194294+08:00</Time> 57: </SmartFile> 58: <SmartFile> 59: <FileName>eas.client.ini</FileName> 60: <Time>2013-10-15T21:22:56.5866492+08:00</Time> 61: </SmartFile> 62: <SmartFile> 63: <FileName>EAS.Configure.exe</FileName> 64: <Version>2.0.0.0</Version> 65: <Time>2013-10-15T16:59:27.6444356+08:00</Time> 66: </SmartFile> 67: <SmartFile> 68: <FileName>EAS.Configure.exe.config</FileName> 69: <Time>2013-04-15T19:59:09.4420283+08:00</Time> 70: </SmartFile> 71: <SmartFile> 72: <FileName>EAS.Data.Controls.dll</FileName> 73: <Version>1.0.0.0</Version> 74: <Time>2013-10-15T17:36:07.4252559+08:00</Time> 75: </SmartFile> 76: <SmartFile> 77: <FileName>EAS.Data.dll</FileName> 78: <Version>5.0.0.0</Version> 79: <Time>2013-10-15T16:59:34.241813+08:00</Time> 80: </SmartFile> 81: <SmartFile> 82: <FileName>EAS.Data.Provider.dll</FileName> 83: <Version>5.0.0.0</Version> 84: <Time>2013-10-15T16:59:59.6222646+08:00</Time> 85: </SmartFile> 86: <SmartFile> 87: <FileName>EAS.Distributed.dll</FileName> 88: <Version>5.0.0.0</Version> 89: <Time>2013-10-15T17:00:39.8145635+08:00</Time> 90: </SmartFile> 91: <SmartFile> 92: <FileName>EAS.Explorer.BLL.Contracts.dll</FileName> 93: <Version>5.0.0.0</Version> 94: <Time>2013-10-12T19:50:17.932+08:00</Time> 95: </SmartFile> 96: <SmartFile> 97: <FileName>EAS.Explorer.BLL.Host.dll</FileName> 98: <Version>5.0.0.0</Version> 99: <Time>2013-10-15T17:00:14.297104+08:00</Time> 100: </SmartFile> 101: <SmartFile> 102: <FileName>EAS.Explorer.dll</FileName> 103: <Version>5.0.0.0</Version> 104: <Time>2013-10-12T19:50:16.931+08:00</Time> 105: </SmartFile> 106: <SmartFile> 107: <FileName>EAS.Explorer.Entities.dll</FileName> 108: <Version>5.0.0.0</Version> 109: <Time>2013-10-15T17:00:16.9642565+08:00</Time> 110: </SmartFile> 111: <SmartFile> 112: <FileName>EAS.Explorer.Res.dll</FileName> 113: <Version>1.1.0.0</Version> 114: <Time>2013-10-12T19:50:50.7467432+08:00</Time> 115: </SmartFile> 116: <SmartFile> 117: <FileName>EAS.Explorer.WinUI.dll</FileName> 118: <Version>5.0.0.0</Version> 119: <Time>2013-10-15T16:59:56.5250875+08:00</Time> 120: </SmartFile> 121: <SmartFile> 122: <FileName>EAS.FormDesigner.exe</FileName> 123: <Version>5.0.0.0</Version> 124: <Time>2013-10-15T16:59:46.1954967+08:00</Time> 125: </SmartFile> 126: <SmartFile> 127: <FileName>EAS.GReport.Controls.dll</FileName> 128: <Version>1.0.0.0</Version> 129: <Time>2013-10-15T17:00:07.2997038+08:00</Time> 130: </SmartFile> 131: <SmartFile> 132: <FileName>EAS.MicroKernel.dll</FileName> 133: <Version>5.0.0.0</Version> 134: <Time>2013-10-15T16:59:29.7545563+08:00</Time> 135: </SmartFile> 136: <SmartFile> 137: <FileName>EAS.Monitor.dll</FileName> 138: <Version>1.0.0.0</Version> 139: <Time>2013-10-12T19:50:10.901+08:00</Time> 140: </SmartFile> 141: <SmartFile> 142: <FileName>EAS.NLB.Monitor.exe</FileName> 143: <Version>1.0.0.0</Version> 144: <Time>2013-10-15T17:00:08.143752+08:00</Time> 145: </SmartFile> 146: <SmartFile> 147: <FileName>EAS.NLB.Server.exe</FileName> 148: <Version>1.0.0.0</Version> 149: <Time>2013-10-15T17:00:16.3272201+08:00</Time> 150: </SmartFile> 151: <SmartFile> 152: <FileName>EAS.OrmDesigner.exe</FileName> 153: <Version>5.0.0.0</Version> 154: <Time>2013-10-15T16:58:10.8720445+08:00</Time> 155: </SmartFile> 156: <SmartFile> 157: <FileName>EAS.OrmDesigner.exe.config</FileName> 158: <Time>2012-01-07T11:28:39.2362631+08:00</Time> 159: </SmartFile> 160: <SmartFile> 161: <FileName>EAS.Report.Controls.dll</FileName> 162: <Version>3.0.0.0</Version> 163: <Time>2013-10-15T17:00:11.6179508+08:00</Time> 164: </SmartFile> 165: <SmartFile> 166: <FileName>EAS.SmartUpdater.exe</FileName> 167: <Version>1.0.0.0</Version> 168: <Time>2013-10-15T16:59:54.662981+08:00</Time> 169: </SmartFile> 170: <SmartFile> 171: <FileName>EAS.SOA.Monitor.exe</FileName> 172: <Version>1.0.0.0</Version> 173: <Time>2013-10-15T17:00:20.4044533+08:00</Time> 174: </SmartFile> 175: <SmartFile> 176: <FileName>EAS.ThirdParty.Controls.dll</FileName> 177: <Version>1.0.0.0</Version> 178: <Time>2013-10-12T19:49:55.311+08:00</Time> 179: </SmartFile> 180: <SmartFile> 181: <FileName>EAS.WinClient.dll</FileName> 182: <Version>5.1.0.0</Version> 183: <Time>2013-10-15T17:00:24.8407071+08:00</Time> 184: </SmartFile> 185: <SmartFile> 186: <FileName>EAS.WinClient.Start.exe</FileName> 187: <Version>5.0.0.0</Version> 188: <Time>2013-10-15T16:59:14.0236565+08:00</Time> 189: </SmartFile> 190: <SmartFile> 191: <FileName>EAS.WinClient.Start.exe.config</FileName> 192: <Time>2013-10-15T21:20:03.86277+08:00</Time> 193: </SmartFile> 194: <SmartFile> 195: <FileName>EAS.Windows.dll</FileName> 196: <Version>5.0.0.0</Version> 197: <Time>2013-10-15T17:00:30.9600571+08:00</Time> 198: </SmartFile> 199: <SmartFile> 200: <FileName>EAS.Wpf.Controls.dll</FileName> 201: <Version>1.0.0.0</Version> 202: <Time>2013-10-15T17:00:38.075464+08:00</Time> 203: </SmartFile> 204: <SmartFile> 205: <FileName>grdes50.dll</FileName> 206: <Version>5, 8, 13, 620</Version> 207: <Time>2013-06-24T23:11:32+08:00</Time> 208: </SmartFile> 209: <SmartFile> 210: <FileName>gregn50.dll</FileName> 211: <Version>5, 8, 13, 620</Version> 212: <Time>2013-06-24T23:10:26+08:00</Time> 213: </SmartFile> 214: <SmartFile> 215: <FileName>ICSharpCode.AvalonEdit.dll</FileName> 216: <Version>4.3.1.9429</Version> 217: <Time>2013-10-12T19:50:15.045+08:00</Time> 218: </SmartFile> 219: <SmartFile> 220: <FileName>Interop.grdesLib.dll</FileName> 221: <Version>5.0.0.0</Version> 222: <Time>2013-10-12T19:50:01.56+08:00</Time> 223: </SmartFile> 224: <SmartFile> 225: <FileName>Interop.grproLib.dll</FileName> 226: <Version>5.0.0.0</Version> 227: <Time>2013-10-12T19:50:02.088+08:00</Time> 228: </SmartFile> 229: <SmartFile> 230: <FileName>itextsharp.dll</FileName> 231: <Version>4.1.2.0</Version> 232: <Time>2011-04-19T10:03:14+08:00</Time> 233: </SmartFile> 234: <SmartFile> 235: <FileName>lua51.x64.dll</FileName> 236: <Time>2013-09-30T13:25:51.209+08:00</Time> 237: </SmartFile> 238: <SmartFile> 239: <FileName>lua51.x86.dll</FileName> 240: <Time>2013-09-30T13:27:36.369897+08:00</Time> 241: </SmartFile> 242: <SmartFile> 243: <FileName>LuaInterface.x64.dll</FileName> 244: <Version>2.0.4.24313</Version> 245: <Time>2013-09-30T13:30:27.8847071+08:00</Time> 246: </SmartFile> 247: <SmartFile> 248: <FileName>LuaInterface.x86.dll</FileName> 249: <Version>2.0.4.24313</Version> 250: <Time>2013-09-30T13:30:27.8937076+08:00</Time> 251: </SmartFile> 252: <SmartFile> 253: <FileName>Microsoft.Data.ConnectionUI.Dialog.dll</FileName> 254: <Version>8.0.50727.42 (RTM.050727-4200)</Version> 255: <Time>2011-04-19T14:03:22+08:00</Time> 256: </SmartFile> 257: <SmartFile> 258: <FileName>Microsoft.Data.ConnectionUI.dll</FileName> 259: <Version>8.0.50727.42 (RTM.050727-4200)</Version> 260: <Time>2011-04-19T14:03:22+08:00</Time> 261: </SmartFile> 262: <SmartFile> 263: <FileName>Microsoft.XmlNotepad.dll</FileName> 264: <Version>2.5.3145.19740</Version> 265: <Time>2008-08-11T11:58:04+08:00</Time> 266: </SmartFile> 267: <SmartFile> 268: <FileName>MongoDB.dll</FileName> 269: <Version>0.90.0.1</Version> 270: <Time>2012-03-16T19:11:12.6696083+08:00</Time> 271: </SmartFile> 272: <SmartFile> 273: <FileName>MySql.Data.dll</FileName> 274: <Version>5.0.9.0</Version> 275: <Time>2008-04-14T12:04:28+08:00</Time> 276: </SmartFile> 277: <SmartFile> 278: <FileName>NetronGraphLib.dll</FileName> 279: <Version>2.2.3328.30433</Version> 280: <Time>2009-02-10T16:54:28+08:00</Time> 281: </SmartFile> 282: <SmartFile> 283: <FileName>RdlDesigner.dll</FileName> 284: <Version>3.9.7.0</Version> 285: <Time>2013-10-12T19:50:00.225+08:00</Time> 286: </SmartFile> 287: <SmartFile> 288: <FileName>RdlEngine.dll</FileName> 289: <Version>3.9.7.0</Version> 290: <Time>2013-10-12T19:49:53.522+08:00</Time> 291: </SmartFile> 292: <SmartFile> 293: <FileName>RdlViewer.dll</FileName> 294: <Version>3.9.6.0</Version> 295: <Time>2013-10-12T19:49:56.182+08:00</Time> 296: </SmartFile> 297: <SmartFile> 298: <FileName>System.Data.SQLite.DLL</FileName> 299: <Version>1.0.66.0</Version> 300: <Time>2010-04-18T13:34:12+08:00</Time> 301: </SmartFile> 302: <SmartFile> 303: <FileName>System.Workflow.Activities.dll</FileName> 304: <Version>4.0.30319.1 (RTMRel.030319-0100)</Version> 305: <Time>2010-03-18T19:31:26+08:00</Time> 306: </SmartFile> 307: <SmartFile> 308: <FileName>System.Workflow.ComponentModel.dll</FileName> 309: <Version>4.0.30319.1 (RTMRel.030319-0100)</Version> 310: <Time>2010-03-18T19:31:26+08:00</Time> 311: </SmartFile> 312: <SmartFile> 313: <FileName>System.Workflow.Runtime.dll</FileName> 314: <Version>4.0.30319.1 (RTMRel.030319-0100)</Version> 315: <Time>2010-03-18T19:31:26+08:00</Time> 316: </SmartFile> 317: <SmartFile> 318: <FileName>update.ini</FileName> 319: <Time>2013-10-15T21:32:33.0976238+08:00</Time> 320: </SmartFile> 321: <SmartFile> 322: <FileName>WF.Demo.DAL.dll</FileName> 323: <Version>1.0.0.0</Version> 324: <Time>2013-10-12T19:49:57.9107211+08:00</Time> 325: </SmartFile> 326: <SmartFile> 327: <FileName>WF.Demo.UI.dll</FileName> 328: <Version>1.0.0.0</Version> 329: <Time>2013-10-12T19:50:49.1896541+08:00</Time> 330: </SmartFile> 331: </Files> 332: </SmartConfig> ”SmartUpdate.xml“文件为平台的升级配置文件,其本质是存储一个文件及其最后修改时间的一个清单,客户端也持有这么一份清单,客户端会依据自己持有的清单与服务器上的清单比对以判定需要升级更新那些文件。 ”appServer\xclient”为AgileEAS.NET SOA 中间件的服务端升级目录,这个路径是不能更改的,在AgileEAS.NET SOA 中间件有服务设计之中更新了硬性的规定,其中”appServer\xclient\files”目录其本质就是客户端的最新复制。 当我们完成以上配置之后,我们来验证一个自动升级是否可以使用,我们把”appServer\xclient\files”复制到其他地方,比如我们复制到“D:\”并重命名为”d:\eas.client”,如下图: 然后我们运行“d:\eas.client\eas.winclient.start.exe”,系统有如下提示: 我们点击“确定”将会启动升级程序进行升级: 升级完成之后点击“关闭”,系统将会自己启动“d:\eas.client\eas.winclient.start.exe”,打开登录窗口: 输入用户:Administrator密码:sa,点击登录,打开主界面: 六、联系我们 为了完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台了开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 技术团队成员都是合作多年的老朋友,因为这个平台是免费的,我们的营运开支主要靠为客户提供咨询服务所得,我们都是因为程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友和一直支持我们工作的客户、朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381 AgileEAS.NET QQ群: 113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、下载AgileEAS.NET SOA 中间件平台5.2 版本 通过AgileEAS.NET SOA 中间件平台官方网站最新下载页面进行下载: 可以选择通过下载打好的RAR压缩包,也可以选择通过SVN进行下载,一版情况下我们对AgileEAS.NET SOA 中间件平台进行改动和修正之后都会把最新的上传到SVN传大家下载,RAR包也会及时的重新打包,但是有是可以因为某些原因没有及时对RAR压缩包进行更新,所以最新的还是在SVN上,如果有条件的情况尽量通过SVN更新最新版本。 下载完成平台之后,有关于发布包之中的目录结构及程序集介绍请参考AgileEAS.NET SOA 中间件平台 5.2 发布说明一文。 三、初始化数据库并直接方式运行WinClient运行容器 运行bin\dotnet目录之中的EAS.DbInitializer.exe程序,即AgileEAS.NET SOA中间件数据库初始化工具,数据库初始化工具会帮助你完成AgileEAS.NET SOA中间件平台运行所必须的表结构及数据: 运行界面如下: 关于选择何种数据库请根据你的喜欢和你的擅长,假设我们选择SQL Server(2005/2008),然后进行下一步: 我们选择创建一个新库,在新库上创建AgileEAS.NET SOA 中间件的运行环境: 我们填写数据库名称,然后点“开始创建数据库”,完成后会有如下提示: 点确定后返回到如下界面: 我们点击完成之后开始AgileEAS.NET SOA中间件平台的数据库初始化工作: 数据库初始化工作包括创建数据库结构及建立初始化数据,初始化完成后会有完成提示(上图)。 如果选中了“完成后启动AgileEAS.NET SOA平台WinClient运行容器”,则会在初始化数据完成之后,我们点击确定之后启动AgileEAS.NET SOA中间件平台WinClient运行容器并以刚初始化完毕的数据库为基础进行运行,如下登录界面: 界面Administrator(管理员)初始密码:sa进入AgileEAS.NET SOA 中间件平台WinClient运行容器: 至此,AgileEAS.NET SOA 中间件平台的数据库初始化及直连数据库环境配置完成。 四、直连数据库的配置文件介绍 AgileEAS.NET SOA中间件平台的系统配置文档,其核心是AgileEAS.NET SOA中间件平台IOC框架的配置文件,其中配置了运行环境所依赖的数据库连接、数据访问、ORM数据存取等相关的组件的动态配置,以下为本例直接数据库的配置文件内容: 1: <?xml version="1.0" encoding="utf-8"?> 2: <configuration> 3: <configSections> 4: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel" /> 5: </configSections> 6: <startup useLegacyV2RuntimeActivationPolicy="true"> 7: <supportedRuntime version="v4.0"/> 8: </startup> 9: <eas> 10: <configurations> 11: <item name="Key" value="Value" /> 12: </configurations> 13: <objects> 14: <object name="DbProvider" assembly="EAS.Data" type="EAS.Data.Access.SqlClientDbProvider" LifestyleType="Thread"> 15: <property name="ConnectionString" type="string" value="Data Source=.;Initial Catalog=eas_demo;User ID=sa;Password=sa1q2w3e4r;Connect Timeout=0" /> 16: </object> 17: <object name="DataAccessor" assembly="EAS.Data" type="EAS.Data.Access.DataAccessor" LifestyleType="Thread"> 18: <property name="DbProvider" type="object" value="DbProvider"/> 19: <property name="Language" type="object" value="TSqlLanguage"/> 20: </object> 21: <object name="OrmAccessor" assembly="EAS.Data" type="EAS.Data.ORM.OrmAccessor" LifestyleType="Thread"> 22: <property name="DataAccessor" type="object" value="DataAccessor"/> 23: </object> 24: <!--查询语言--> 25: <object name="TSqlLanguage" assembly="EAS.Data" type="EAS.Data.Linq.TSqlLanguage" LifestyleType="Thread"/> 26: <!--服务桥--> 27: <object name="ServiceBridger" assembly="EAS.MicroKernel" type="EAS.Services.DirectServiceBridger" LifestyleType="Singleton" /> 28: <!--日志管理--> 29: <object name="Logger" assembly="EAS.MicroKernel" type="EAS.Loggers.TextLogger" LifestyleType="Singleton" /> 30: <!--资源--> 31: <!--<object name="EAS.Explorer.Resource" assembly="EAS.Explorer.Res" type="EAS.Explorer.Res.Resources" LifestyleType="Singleton" />--> 32: </objects> 33: </eas> 34: </configuration> 35: 其中eas/configurations中配置的内容供EAS.Configuration.Config对象进行读取的一些基本配置,供开发人员在处理系统的一些配置参数时候,在AgileEAS.NET SOA 平台内部没有使用。 其中eas/objects中配置的内容供EAS.Objects.ComponentConfig对象进行读取的IOC框架的对象配置信息,因为AgileEAS.NET SOA中间件平台在设计时支持多种数据库系统以及连接、分布式结构,所以系统的主体结果是不会变的,当换不同的数据的时候,只需要改变一下IOC之中的数据库连接对象的配置信息就能随便的切换,同样,系统在进行直连与分布式切换的时候,只需要通过修改配置文件就可以达到这样的目录。 本例的配置文件之中,以下配置内容,定义了系统使用的数据库连接对象为EAS.Data.Access.SqlClientDbProvider,即为SQLServer的连接: 1: <object name="DbProvider" assembly="EAS.Data" type="EAS.Data.Access.SqlClientDbProvider" LifestyleType="Thread"> 2: <property name="ConnectionString" type="string" value="Data Source=.;Initial Catalog=eas_demo;User ID=sa;Password=sa1q2w3e4r;Connect Timeout=0" /> 3: </object> 如需要切换其数据库我们只需要改变对象“DbProvider”的类库信息及修改数据库的连接字符串描述,比如做如下修改: 1: <object name="DbProvider" assembly="EAS.Data.Provider" type="EAS.Data.Access.SqliteProvider" LifestyleType="Thread"> 2: <property name="ConnectionString" type="string" value="Data Source=..\db\Chat.db;" /> 3: </object> 就变成了基于Sqlite数据库的定义了,当然了,改变数据库光改编“DbProvider”的定义还不够,还需要改变一下“DataAccessor”对象的属性“Language”定义,即需要把以下配置内容: 1: <object name="DataAccessor" assembly="EAS.Data" type="EAS.Data.Access.DataAccessor" LifestyleType="Thread"> 2: <property name="DbProvider" type="object" value="DbProvider"/> 3: <property name="Language" type="object" value="TSqlLanguage"/> 4: </object> 5: <!--查询语言--> 6: <object name="TSqlLanguage" assembly="EAS.Data" type="EAS.Data.Linq.TSqlLanguage" LifestyleType="Thread"/> 改变为: 1: <object name="DataAccessor" assembly="EAS.Data" type="EAS.Data.Access.DataAccessor" LifestyleType="Thread"> 2: <property name="DbProvider" type="object" value="DbProvider"/> 3: <property name="Language" type="object" value="SqliteLanguage"/> 4: </object> 5: <!--Linq查询语言--> 6: <object name="SqliteLanguage" assembly="EAS.Data.Provider" type="EAS.Data.Linq.SqliteLanguage" LifestyleType="Thread"/> 这样我们就把基于SQLServer的数据环境改变为基于Sqlite数据库的数据环境了。 另外一个很重要的配置是系统是工做于数据库直联还是工作于分布式,其决定是由“ServiceBridger”对象所决定,直练环境使用如下配置信息: 1: <object name="ServiceBridger" assembly="EAS.MicroKernel" type="EAS.Services.DirectServiceBridger" LifestyleType="Singleton" /> 分布式环使用如下配置: 1: <object name="ServiceBridger" assembly="EAS.Distributed" type="EAS.Distributed.ServiceBridger" LifestyleType="Singleton"/> 当然了,变不是只改变这一个对象,改变为分布式是还需要改变“DataAccessor”、“OrmAccessor”对象的定义,在些就不做一一界面,愿意的朋友请使用AgileEAS.NET SOA中间件平台的配置文件定义工具(EAS.Configure.exe)多试试。 五、联系我们 为了完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台了开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 技术团队成员都是合作多年的老朋友,因为这个平台是免费的,我们的营运开支主要靠为客户提供咨询服务所得,我们都是因为程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友和一直支持我们工作的客户、朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381 AgileEAS.NET QQ群: 113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、AgileEAS.NET SOA 中间件简介 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、下载 AgileEAS.NET SOA 中间件平台5.2 版本 打开AgileEAS.NET SOA 中间件平台官方网站最新下载栏目: 通过半年时间的客户反馈,我们对AgileEAS.NET SOA中间件进行了部分修改, 形成了5.2版本,相对于之前的5.1版本,我们做了以下的改动: 1).重新设计了ORM的缓存体系,增加了一套ORM对象的增量缓存体系。 2).为ORM体系提供了懒加载机制,懒加载可以从数据库也可以从缓存进行懒加载。 3).修改了一些Linq语言实现上的Bug。 4).对SOA服务、分布式体系进行了精简和整合,合并和裁减了几个有关于分布式通信的程序集。 5).增加了对SOA服务进行负载均衡的支持。 6).重构和简化了Sockt/Tcp通信框架。 7).SOA、分布式通信系统支持Socket通信模式。 8).SOA服务及NLB服务增加了对X64架构的支持。 9).集成对lua脚本语言引擎及配套的编码调试工具。 10).从资源管理平台BLL.Host之中分离了对BPM的支持到独立的程序集,以隔离工作流不能工作对管理功能的影响。 11).调整了Grid++报表系统的部分功能、增加对子报表的功能支持。 12).强化了数据初始化工具、系统配置工具。 13).增加了SOA服务、NLB服务的监控工具。 14).增加了WinForm开发中辅助扩展组件:字典快速录入、自动焦点跳转。 15).增加了DataGridView控件CRUD自动持久化组件,即只需要向DataGridView绑定一个数据源,只可以自动实现当DataGridView增加、删除、修改后数据自动写回功能。 16).调整了工作流部分的API设计。 17).调整了日志系统的部分设计。 18).调整了ActiveXForm运行容器、改变了ActiveXForm的组件升级方式、把原先独立一套的升级改变为使用平台统一的升级工具进行升级,运行服务器容器由原来的IIS环境该由AgileEAS.NET 平台SOA服务容器运行。 19).调整了Silverlight运行容器的设计、服务端运行容器由原来的IIS环境该由AgileEAS.NET 平台SOA服务容器运行。 总结一下就是,5.2与5.1之间没有对平台做过涉及结构上的重大调整,而是把重点放在了对系统稳定性、高性能、应用开发的简单性这些方面,即希望本平台能达到上手执容易、开发方便的目标。 三、AgileEAS.NET SOA 中间件平台5.2 版本发布内容 在AgileEAS.NET SOA 中间件2013第四季度发布计划一文之中曾经简单的向大家介绍了AgileEAS.NET SOA 5.2版本发布的大概时间及大概介绍,AgileEAS.NET SOA 中间件平台5.2版本最大的亮点是在发布平台的同时将会向大家发布部分平台的开源代码及三套平台的案例。 包括以下开发源代码: 1).AgileEAS.NET SOA 中间件平台Silverlight运行容器的源代码、Silverlight版本的工作流系统源代码。 2).AgileEAS.NET SOA 中间件平台采用的RDL 报表系统源代码,包括报表引擎、报表控件、报表设计器,已经过我们的汉化和改进,大量应用于医疗、物流、铁路、电力等行业。 同时,案例源代码由原来的一个增加为3个: 1).AgileEAS.NET SOA 中间件平台-药品商店管理信息系统(DrugShop)源代码,做了大量修改和优化,同步更新到AgileEAS.NET SOA 中间件最新平台。 2).新增加了一个-小型ERP系统(电脑分销)系统(SmartERP),本案例原为某客户为某电脑经销商所开发,后来贡献给我们做为例子之用。 3).AgileEAS.NET SOA 中间件平台Socket通信框架-在线聊天室系统(ChatRoom)源代码,为快速掌握AgileEAS.NET 中间件平台Socket消息通信框架所必备。 四、AgileEAS.NET SOA 中间件平台5.2 开发包介绍 4.1 目录结构 开发人员从AgileEAS.NET官方http://www.smarteas.net网站或者敏捷软件工程实验室网站http://www.agilelab.cn下载到的AgileEAS.NET开发包名称为AgileEAS.NET 5.0.rar。 解压后包含以下文件目录结构: 下面我把各目录做个简单的说明: Bin目录 Bin目录中包含着AgileEAS.NET平台中的所有程序集文件,插件定义、WinForm、SmartClient运行容器、基础类库、开发辅助、配置工具都在这里面。 AppServer目录 发布是其中只有Bin和xClient两个空目录,用于做为SOA服务的运行目录、自动升级的服务端目录。 documents目录 Document目录中包含着AgileEAS.NET SOA中间件平台的介绍、开发指南、使用说明书、类库参考手册等一系列的文档。 example目录 AgileEAS.NET SOA中间件平台提供的一组开发例子,我会用专门的文档对里面的例子介绍。 ActiveXForm.Web目录 ActiveXForm运行容器的部署站点,包含EAS.ActiveXForm的运行站点,以及ActiveXForm运行所必须的客户端IE扫描件、IE插件客户段运行所必须的X509根证书、AcriveXForm客户端运行所必须的配置文件。 Silverlight.src目录 AgileEAS.NET SOA中间件平台Silverlight运行容器的所有源代码,本部分已开源。 RDL Project 3.96目录 AgileEAS.NET SOA中间件平台所集成的RDL报表系统的所有源代码、本部分已开源。 4.2 程序集介绍 在AgileEAS.NET SOA中间件平台开发包的bin目录中提供了70个左右程序集,其涵盖了AgileEAS.NET SOA中间件平台的方方面面,下面我对程序集做一个简单的分类。 基础程序集: EAS.MicroKernel.dll 微内核程序集,包含接口契约、IOC、SL、及服务容器的定义。 EAS.Data.dll 提供统一的数据访问和ORM。 EAS.Web.dll Web开发扩展(针对应用程序和模块接口)。 EAS.Windows.dll WinForm/WFP开发扩展、及一些预定义控件。 资源管理平台: EAS.Explorer.dll 资源管理平台基础组件。 EAS.Explorer.Entities.dll 资源管理平台实体定义。 EAS.Explorer.BLL.Contracts.dll 资源管理平台业务/服务接口契约 EAS.Explorer.BLL.Host.dll 资源管理平台业务/服务实现 EAS.Explorer.Res.dll 外壳资源(可替换)。 EAS.Explorer.Web.dll 运行容器之Web基础。 EAS.Explorer.WinUI.dll 基于WinForm的平台管理功能实现。 EAS.WinClient.dll WinForm/WPF运行容器。 EAS.WinClient.Start.exe WinForm/WPF运行容器引导程序。 ActiveXForm: EAS.ActiveXForm.ClientClasp.dll 客户端钩子(包含IE中运行的三个ActiveX控件)。 EAS.ActiveXForm.ClientClasp.AddIn.dll 客户端插件。 智能升级: EAS.SmartUpdater.exe 智能升级引导程序。 EAS.SmartUpdate.Config.exe 智能升级配置程序。 分布式服务: EAS.Distributed.dll 分布式访问客户端。 EAS.Monitor.dll SOA服务、负载均衡服务监控定义。 EAS.SOA.Server.exe SOA服务主程序。 EAS.SOA.Server.X64.exe SOA服务64位主程序。 EAS.NLB.Server.exe 负载均衡服务主程序。 EAS.SOA.Monitor.exe SOA服务监控程序。 EAS.NLB.Monitor.exe 负载均衡服务监控程序。 报表系统: RdlEngine.dll RDL引擎(开源项目)。 RdlViewer.dll RDL展示组件(开源项目)。 RdlDesigner.dll RDL设计组件。 EAS.Report.Controls.dll 报表打印组件。 EAS.GReport.Controls.dll Grid++打印组件。 开发辅助: EAS.OrmDesigner.exe 数据对象(ORM)设计器。 EAS.FormDesigner.exe 快速界面设计器。 初始化、配置工具: EAS.DbInitializer.exe 平台数据库初始化工具。 EAS.Configure.exe 快速配置文件定义工具。 工作流平台: EAS.BPM.Activities.dll 工作流活动定义。 EAS.BPM.Host.dll 工作流服务实现。 EAS.BPM.WinUI.dll 工作流平台管理UI。 Silverlight平台: EAS.MicroKernel.dll 微内核。 EAS.Data.dll 数据访问、Linq。 EAS.Controls.dll 基础控件。 EAS.ReportViewer.dll 报表浏览控件。 其他: EAS.Data.Provider.dll 数据访问提供者扩展,通过扩展实现ORACLE、MySql、Sqlite数据库的支持。 第三方组件: System.Workflow.Activities.dll WF3.5基础组件。 System.Workflow.ComponentModel.dll WF3.5基础组件。 System.Workflow.Runtime.dll WF3.5基础组件。 EAS.ThirdParty.Controls.dll 第三方开源控件源代码 NetronGraphLib.dll 图像组件。 ICSharpCode.AvalonEdit.dll.dll Microsoft.Data.ConnectionUI.Dialog.dll Microsoft.Data.ConnectionUI.dll Microsoft.XmlNotepad.dll 4.3 文档部分 AgileEAS.NET SOA中间件平台是一个快速开发平台,是一组中间件,业主要目录的是提供开发人员的开发效率,要充分了解并且学习AgileEAS.NET平台的快速开发实践和充分的利用AgileEAS.NET平台所提供的快速开发工具。 如何快速去学习和理解AgileEAS.NET SOA中间件平台呢,我们提供了大量的文档和例程,文档是AgileEAS.NET SOA中间件平台的组成部分,更是程序员熟悉AgileEAS.NET SOA中间件平台的窗户。AgileEAS.NET平台开发包中提供了《AgileEAS.NET SOA中间件平台技术说明书 》、《AgileEAS.NET SOA中间件平台开发指南》、《AgileEAS.NET SOA中间件平台系统管理使用教程》、《AgileEAS.NET SOA中间件平台开发辅助工具使用教程》、《AgileEAS.NET SOA中间件平台安装说明书》、《AgileEAS.NET SOA中间件平台数据库设计说明书(SQLServer)》、《AgileEAS.NET SOA中间件平台数据库设计说明书(Oracle)》等文档以及AgileEAS.NET SOA中间件平台基础类库参考手册。 4.4 示例部分 AgileEAS.NET SOA中间件平台5.2版本将会发布三个应用案例,但是这三个案例都不会和AgileEAS.NET 5.2发布包打包在一进行下载,而是在AgileEAS.NET SOA 中间件平台官方网站最新下载栏目设有专门的下载链接进行下载。 五、学习和配置文档 AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(一):下载平台并基于直连环境运行 AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(二):配置WinClient分布式运行环境 AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(三):配置ActiveXForm运行环境 AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(四):开源的Silverlight运行容器的编译、配置 六、联系我们 为了完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台了开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 技术团队成员都是合作多年的老朋友,因为这个平台是免费的,我们的营运开支主要靠为客户提供咨询服务所得,我们都是因为程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友和一直支持我们工作的客户、朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381 AgileEAS.NET QQ群: 113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台.Net Socket通信框架-介绍一文之中我们对AgileEAS.NET SOA中间Socket/Tcp框架进行了总体的介绍,我们知道 AgileEAS.NET SOA中间件Socket/Tcp框架是一套Socket通信的消息中间件: 二、多人在线聊天室系统 在文章AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答给大家实例介绍了有关于AgileEAS.NET SOA 中间件Socket通信框架的简单应用之后,我们通过文章AgileEAS.NET SOA 中间件平台.Net Socket通信框架-完整应用例子-在线聊天室系统-下载配置向大家展示了一个完整成熟的.NET Socket 通信框架的应用案例,一个从在线聊天室系统,通过文章向大家讲解了如何下载和编译安案例源代码、以及如何配置服务端和客户段。 相对于简单的客户端==》服务端消息请求与应答的例子而言,在线多人聊天室系统的复杂度都要超过客户端==》服务端消息请求例子N多倍,但是限于文章篇幅的原因,我们没有在文章AgileEAS.NET SOA 中间件平台.Net Socket通信框架-完整应用例子-在线聊天室系统-下载配置这中为大家介绍这个案例的具体代码。 下面我将为大家介绍这个案例的关键代码及阅读、理解、修改完善所需要注意的地方。 三、关于代码编译环境及其他的地些设置 本案例的源代码在下载压缩包的Code目录之中,所有的引用AgileEAS.NET SOA 中间件平台的程序集及客户端、服务端运行所必须的文件都在下载压缩包的Publish目录之中,所有项目的编译输出路径也都是在Publish目录,也就是所有项目不管是在Debug编译环境还是在Release编译环境都是输出在Publish目录之中,有关具体的设置请看下图: 四、解决方案之中的项目说明 ChatRoom解决方案之是共有ChatRoom.Entities、ChatRoom.BLL.Contracts、ChatRoom.BLL.Host、ChatRoom.Messages、ChatRoom.Socket、ChatingRoom.MainClient、ChatingRoom.UserManage共七个项目,其中: ChatRoom.Entities:是聊天室注册用启的数据存储实体,其中只包括一个实体User,即注册用户信息。 ChatRoom.BLL.Contracts:为用户管理、登录验证、密码找回修改等功能的分布式服务定义契约,其中仅包括一个服务契约定义IUserService(用户服务)。 ChatRoom.BLL.Host:为ChatRoom.BLL.Contracts所定义的服务契约的功能实现。 ChatRoom.Messages:服务端与客户端通信消息的定义,包括聊天消息、用户登录请求、登录结果、在线用户清单消息、用户上下线状态通知消息。 ChatRoom.Socket:为服务端的业务代码、包括AgileEAS.NET SOA服务进程的SocketService插件以及服务端收到客户端各种消息的消息处理器代码。 ChatingRoom.MainClient:为客户端代码、包括客户段界面以及客户端收到通信消息的消息处理器代码。 五、关于SOA服务SocketService插件 如果对比AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答,细心的朋友一定会发现本案例中没有了类似Socket.Demo.Server功能的项目,而是多了ChatRoom.Socket项目。 关于这个问题就涉及到了AgileEAS.NET SOA 中间件平台的SOA服务实例及Socket框架的设计,在SOA服务实例本身被设计成为了一个可以运行WCF、WS、Socket等各吃点通信及其他应用服务的运行容器,那么我们的Socket服务端也可以在此服务实例之中运行,同时在我们的AgileEAS.NET SOA中间件平台的微内核程序集EAS.MicroKernel.dll之中定义了SocketService插件的实现标准: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using EAS.Distributed; 6: 7: namespace EAS.Sockets 8: { 9: /// <summary> 10: /// SocketService服务接口定义。 11: /// </summary> 12: /// <remarks> 13: /// 一个Socket服务器可以承载多种/个Socket服务,一个Socket服务处理一种业务。 14: /// 如IM SocketService 处理IM相关的即时通讯业务,而WF SocketService 处理工作流相关的服务,这两种Socket服务可以同时运行在一个Socket服务器之中。 15: /// </remarks> 16: public interface ISocketService:IAppService 17: { 18: /// <summary> 19: /// 使用ServerEngine初始化SocketService。 20: /// </summary> 21: /// <param name="socketServer">Socket服务器对象。</param> 22: void Initialize(ISocketServerBase socketServer); 23: } 24: } ISocketService接口中定义了一个初始化方法:void Initialize(ISocketServerBase socketServer),用于SOA服务实例完成对ISocketService实例的初始化,其中传入参数为一个ISocketServerBase对象,其本质的含义为SOA服务实例调用ISocketService实例对象把SOA服务实例之中的SocketServer对象做为参数传入,那么我们就可以在ISocketService对象之中针对SocketServer做一些初始化工作,其中最重要的工作是,挂载与之相关的消息对象器IMessageHandler。 ChatRoom.Socket项目之中包括了一个ISocketService的实现ChatRoom.Socket.MessageService 1: using EAS.Loggers; 2: using EAS.Sockets; 3: using System; 4: using System.Collections.Generic; 5: using System.Linq; 6: using System.Text; 7: 8: namespace ChatRoom.Socket 9: { 10: /// <summary> 11: /// 聊天室消息服务,由EAS.SOA.Server.Exe引擎的Socket初始化程序。 12: /// </summary> 13: public class MessageService : ISocketService 14: { 15: #region ISocketService 成员 16: 17: public void Initialize(EAS.Sockets.ISocketServerBase socketServer) 18: { 19: try 20: { 21: socketServer.AddHander(new ChatMessageHandler()); 22: socketServer.AddHander(new LoginMessageHandler()); 23: ChatRoomContext.Instance.SocketServer = socketServer; 24: } 25: catch (System.Exception exc) 26: { 27: Logger.Error(exc); 28: } 29: 30: socketServer.SessionStarted += socketServer_SessionStarted; 31: socketServer.SessionAbandoned += socketServer_SessionAbandoned; 32: } 33: 34: void socketServer_SessionStarted(object sender, NetSessionEventArgs e) 35: { 36: Logger.Info(string.Format("Session:{0} Started", e.Session.SessionID)); 37: } 38: 39: void socketServer_SessionAbandoned(object sender, NetSessionEventArgs e) 40: { 41: Logger.Info(string.Format("Session:{0} Abandoned", e.Session.SessionID)); 42: } 43: 44: //void socketServer_MessagerReceived(object sender, EAS.Sockets.MessageEventArgs e) 45: //{ 46: // Logger.Info(string.Format("MessagerReceived:{0}", e.Message.ToString())); 47: //} 48: 49: 50: //void socketServer_MessageSend(object sender, EAS.Sockets.MessageEventArgs e) 51: //{ 52: // Logger.Info(string.Format("MessageSend:{0}", e.Message.ToString())); 53: //} 54: 55: public void Start() 56: { 57: 58: } 59: 60: public void Stop() 61: { 62: 63: } 64: 65: #endregion 66: } 67: } 其中最重要的代码是Initialize函数之中挂载ChatMessage、LoginMessage两个消息的消息处理器代码: 1: socketServer.AddHander(new ChatMessageHandler()); 2: socketServer.AddHander(new LoginMessageHandler()); Socket插件服务的定义除了代码定义之外,还需要在AgileEAS.NET SOA 中间件有SOA服务实例配置文件之中进行定义,因为SOA服务实例程序有32位和64位版本,分别为EAS.SOA.Server.exe和EAS.SOA.Server.x64.exe,所以要根据自身的机器条件和自己喜欢的运行环境修改EAS.SOA.Server.exe.config或EAS.SOA.Server.x64.exe.config: 1: <?xml version="1.0"?> 2: <configuration> 3: <configSections> 4: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel"/> 5: </configSections> 6: <!--支持混合程序集--> 7: <startup useLegacyV2RuntimeActivationPolicy="true"> 8: <supportedRuntime version="v4.0"/> 9: </startup> 10: <eas> 11: <configurations> 12: <item name="Key" value="Value"/> 13: </configurations> 14: <appserver> 15: <channel> 16: <wcf enable="true"> 17: <config tcpPort="6907" httpPort="6908"/> 18: <serviceThrottling maxConcurrentCalls="128" maxConcurrentInstances="128" maxConcurrentSessions="256"/> 19: <wcfServices> 20: <wcfService key="Key" type="Value"/> 21: </wcfServices> 22: </wcf> 23: <socket enable ="true"> 24: <config tcpPort="6906"/> 25: <serviceThrottling maxConcurrence="8196"/> 26: <socketServices> 27: <socketService key="MessageService" type="ChatRoom.Socket.MessageService,ChatRoom.Socket"/> 28: </socketServices> 29: </socket> 30: </channel> 31: <appServices> 32: <service key="Key" type="Value"/> 33: </appServices> 34: </appserver> 35: <objects> 36: <!--数据访问提供者对象--> 37: <object name="DbProvider" assembly="EAS.Data.Provider" type="EAS.Data.Access.SqliteProvider" LifestyleType="Thread"> 38: <property name="ConnectionString" type="string" value="Data Source=..\db\Chat.db;" /> 39: </object> 40: <!--数据访问器--> 41: <object name="DataAccessor" assembly="EAS.Data" type="EAS.Data.Access.DataAccessor" LifestyleType="Thread"> 42: <property name="DbProvider" type="object" value="DbProvider"/> 43: <property name="Language" type="object" value="SqliteLanguage"/> 44: </object> 45: <!--ORM访问器--> 46: <object name="OrmAccessor" assembly="EAS.Data" type="EAS.Data.ORM.OrmAccessor" LifestyleType="Thread"> 47: <property name="DataAccessor" type="object" value="DataAccessor"/> 48: </object> 49: <!--本地服务桥--> 50: <object name="ServiceBridger" assembly="EAS.MicroKernel" type="EAS.Services.DirectServiceBridger" LifestyleType="Singleton" /> 51: <!--Linq查询语言--> 52: <object name="SqliteLanguage" assembly="EAS.Data.Provider" type="EAS.Data.Linq.SqliteLanguage" LifestyleType="Thread"/> 53: <!--日志记录--> 54: <object name="Logger" assembly="EAS.MicroKernel" type="EAS.Loggers.TextLogger" LifestyleType="Singleton"> 55: <property name="Path" type="string" value="..\logs" /> 56: </object> 57: <!--分布式服务上下文参数定义。--> 58: <object name="EAS.Distributed.ServiceContext" type="EAS.Distributed.ServiceContext,EAS.SOA.Server" LifestyleType="Singleton"> 59: <property name="EnableLogging" type="bool" value="false" /> 60: </object> 61: </objects> 62: </eas> 63: <startup> 64: <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> 65: </startup> 66: </configuration> 需要在 <eas/appserver/channel/socket/socketServices>配置节中之中增加了一端: 1: <socketService key="MessageService" type="ChatRoom.Socket.MessageService,ChatRoom.Socket"/> 用于告诉SOA服务实例在启动的时候加载并初始化类型为“ChatRoom.Socket.MessageService,ChatRoom.Socket”的SocketService。 六、注册用户数据库及Sqlite介绍 在线多人聊到室系统之中有登录、用户,那么也就必须有数据库,要存储这些注册用户的信息,为了方便这案例的使用和部署,我们选择了轻量级的Sqlite文件数据库,其特别是简单方便,对于小数据量存储非常好用,有关于Sqlite的知识请自己从网上学习,本人使用的sqlite管理工具为SQLite Expert。 注册用户表结构如下: Ø CHAT_USER(聊天室用户表) 表名 CHAT_USER 所有者 dbo 列名 数据类型 空 说明 LOGINID NVARCHAR(64) N 登录ID Name NVARCHAR(64) Y 用户名 PASSWORD NVARCHAR(64) Y 密码 MAIL VARCHAR(128) Y 邮件 SafeKey NVARCHAR(64) Y 密码找回问题 SafeResult NVARCHAR(64) Y 密码找回答案 STATE BIT Y 状态 REGTIME DATETIME Y 注册时间 有关针对CHAT_USER表的数据访问使用了AgileEAS.NET SOA中间件平台的ORM及与之配套的Linq进行访问,其对应的ORM实体对象为ChatRoom.Entities.User: 1: using System; 2: using System.Linq; 3: using System.ComponentModel; 4: using System.Data; 5: using EAS.Data; 6: using EAS.Data.Access; 7: using EAS.Data.ORM; 8: using EAS.Data.Linq; 9: using System.Runtime.Serialization; 10: 11: namespace ChatRoom.Entities 12: { 13: /// <summary> 14: /// 实体对象 User(聊天室用户表)。 15: /// </summary> 16: [Serializable()] 17: [Table("CHAT_USER","聊天室用户表")] 18: partial class User: DataEntity<User>, IDataEntity<User> 19: { 20: public User() 21: { 22: this.RegTime = DateTime.Now; 23: } 24: 25: protected User(SerializationInfo info, StreamingContext context) 26: : base(info, context) 27: { 28: } 29: 30: #region O/R映射成员 31: 32: /// <summary> 33: /// 登录ID 。 34: /// </summary> 35: [Column("LOGINID","登录ID"),DataSize(64),PrimaryKey] 36: [DisplayName("登录ID")] 37: public string LoginID 38: { 39: get; 40: set; 41: } 42: 43: /// <summary> 44: /// 用户名 。 45: /// </summary> 46: [Column("Name","用户名"),DataSize(64)] 47: [DisplayName("用户名")] 48: public string Name 49: { 50: get; 51: set; 52: } 53: 54: /// <summary> 55: /// 密码 。 56: /// </summary> 57: [Column("PASSWORD","密码"),DataSize(64)] 58: [DisplayName("密码")] 59: public string Password 60: { 61: get; 62: set; 63: } 64: 65: /// <summary> 66: /// 邮件 。 67: /// </summary> 68: [Column("MAIL","邮件"),DataSize(128)] 69: [DisplayName("邮件")] 70: public string Mail 71: { 72: get; 73: set; 74: } 75: 76: /// <summary> 77: /// 密码找回问题 。 78: /// </summary> 79: [Column("SafeKey","密码找回问题"),DataSize(64)] 80: [DisplayName("密码找回问题")] 81: public string SafeKey 82: { 83: get; 84: set; 85: } 86: 87: /// <summary> 88: /// 密码找回答案 。 89: /// </summary> 90: [Column("SafeResult","密码找回答案"),DataSize(64)] 91: [DisplayName("密码找回答案")] 92: public string SafeResult 93: { 94: get; 95: set; 96: } 97: 98: /// <summary> 99: /// 状态 。 100: /// </summary> 101: [Column("STATE","状态")] 102: [DisplayName("状态")] 103: public int State 104: { 105: get; 106: set; 107: } 108: 109: /// <summary> 110: /// 注册时间 。 111: /// </summary> 112: [Column("REGTIME","注册时间")] 113: [DisplayName("注册时间")] 114: public DateTime RegTime 115: { 116: get; 117: set; 118: } 119: 120: #endregion 121: } 122: } 针对CHAT_USER表的用户登录、注册验证、找回密码等代码的实现在ChatRoom.BLL.Host.UserService之中: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using EAS.Services; 6: using ChatRoom.Entities; 7: using EAS.Data.ORM; 8: using EAS.Data.Linq; 9: 10: namespace ChatRoom.BLL 11: { 12: /// <summary> 13: /// 账号服务。 14: /// </summary> 15: [ServiceBind(typeof(IUserService))] 16: public class UserService : IUserService 17: { 18: public void AddUser(User user) 19: { 20: using (DbEntities db = new DbEntities()) 21: { 22: user.RegTime = DateTime.Now; 23: int count = db.Users.Where(p => p.LoginID == user.LoginID).Count(); 24: if (count>0) 25: { 26: throw new System.Exception(string.Format("已经存在账号为{0}的用户", user.LoginID)); 27: } 28: 29: db.Users.Insert(user); 30: } 31: } 32: 33: public User UserLogin(string loginID, string password) 34: { 35: using (DbEntities db = new DbEntities()) 36: { 37: var v = db.Users.Where(p => p.LoginID == loginID).FirstOrDefault(); 38: if (v == null) 39: { 40: throw new System.Exception(string.Format("不存在登账号称为{0}的用户", loginID)); 41: } 42: 43: if (v.Password != password) 44: { 45: throw new System.Exception("密码不正确定"); 46: } 47: 48: return v; 49: } 50: } 51: 52: public bool UserExists(string loginID) 53: { 54: using (DbEntities db = new DbEntities()) 55: { 56: int count = db.Users.Where(p => p.LoginID == loginID).Count(); 57: return count > 0; 58: } 59: } 60: 61: public string GetSafeKey(string loginID) 62: { 63: using (DbEntities db = new DbEntities()) 64: { 65: var v = db.Users.Where(p => p.LoginID == loginID).FirstOrDefault(); 66: if (v != null) 67: { 68: return v.SafeKey; 69: } 70: else 71: { 72: return string.Empty; 73: } 74: } 75: } 76: 77: public string GetSafeResult(string loginID) 78: { 79: using (DbEntities db = new DbEntities()) 80: { 81: var v = db.Users.Where(p => p.LoginID == loginID).FirstOrDefault(); 82: if (v != null) 83: { 84: return v.SafeResult; 85: } 86: else 87: { 88: return string.Empty; 89: } 90: } 91: } 92: 93: 94: public void ChangePassword(string loginID, string password) 95: { 96: using (DbEntities db = new DbEntities()) 97: { 98: db.Users.Update(p => new User { Password = password }, p => p.LoginID == loginID); 99: } 100: } 101: } 102: } 七、关于在线用户清单的管理 系统中如何知道目有那些用户在线,参考以上六节的内容我们可以知道,用户的主键是账号ID,与SocketServer之中在线清单NetSession没有特定的关系,那么如何建立这种关系,多而得到目前有那些用户在线呢,在ChatRoom.Socket项目之中我们定义了LoginInfo对象: 1: using EAS.Sockets; 2: using System; 3: using System.Collections.Generic; 4: using System.Linq; 5: using System.Text; 6: using ChatRoom.Entities; 7: 8: namespace ChatRoom.Socket 9: { 10: /// <summary> 11: /// 消息信息类。 12: /// </summary> 13: public class LoginInfo 14: { 15: /// <summary> 16: /// 登录账号。 17: /// </summary> 18: public string LoginID 19: { 20: get; 21: set; 22: } 23: 24: /// <summary> 25: /// 用户对象。 26: /// </summary> 27: public User User 28: { 29: get; 30: set; 31: } 32: 33: /// <summary> 34: /// 会话。 35: /// </summary> 36: public NetSession Session { get; set; } 37: } 38: 39: } 我们看源代码就可以明确的知道,他是一个用于建立NetSession与登录用户LoginID/User对象的影射类,即某个登录用户是在那个网络会话这上,我们在ChatRoom.Socket项目之中定义了一个ChatRoomContext上下文辅助类: 1: using EAS.Sockets; 2: using ChatRoom.Messages; 3: using System; 4: using System.Collections.Generic; 5: using System.Linq; 6: using System.Text; 7: using System.Runtime.CompilerServices; 8: 9: namespace ChatRoom.Socket 10: { 11: class ChatRoomContext 12: { 13: #region 单例模式 14: 15: private static object m_Lock = new object(); 16: private static ChatRoomContext m_Instance = null; 17: 18: public static ChatRoomContext Instance 19: { 20: get 21: { 22: if (m_Instance == null) 23: { 24: lock (m_Lock) 25: { 26: if (m_Instance == null) 27: { 28: m_Instance = new ChatRoomContext(); 29: } 30: } 31: } 32: 33: return m_Instance; 34: 35: } 36: } 37: 38: ChatRoomContext() 39: { 40: this.m_LoginInfos = new List<LoginInfo>(); 41: this.m_OnLineMessage = new OnLineMessage(); 42: } 43: 44: #endregion 45: 46: ISocketServerBase m_SocketServer = null; 47: List<LoginInfo> m_LoginInfos = null; 48: OnLineMessage m_OnLineMessage = null; 49: 50: /// <summary> 51: /// Socket服务器。 52: /// </summary> 53: public ISocketServerBase SocketServer 54: { 55: get 56: { 57: return this.m_SocketServer; 58: } 59: set 60: { 61: this.m_SocketServer = value; 62: } 63: } 64: 65: /// <summary> 66: /// 会话集合。 67: /// </summary> 68: public List<LoginInfo> LoginInfos 69: { 70: get 71: { 72: return this.m_LoginInfos; 73: } 74: } 75: 76: /// <summary> 77: /// 在线清单信息。 78: /// </summary> 79: public OnLineMessage OnLineMessage 80: { 81: get 82: { 83: return this.m_OnLineMessage; 84: } 85: } 86: 87: /// <summary> 88: /// 根据Socket会话求上下文信息。 89: /// </summary> 90: /// <param name="sessionID"></param> 91: /// <returns></returns> 92: public LoginInfo GetLoginInfo(Guid sessionID) 93: { 94: LoginInfo v = null; 95: lock (this.m_LoginInfos) 96: { 97: v = this.m_LoginInfos.Where(p => p.Session.SessionID == sessionID).FirstOrDefault(); 98: } 99: 100: return v; 101: } 102: 103: /// <summary> 104: /// 根据账号求上下文信息。 105: /// </summary> 106: /// <param name="LoginID"></param> 107: /// <returns></returns> 108: public LoginInfo GetLoginInfo(string LoginID) 109: { 110: LoginInfo v = null; 111: lock (this.m_LoginInfos) 112: { 113: v = this.m_LoginInfos.Where(p => p.LoginID == LoginID).FirstOrDefault(); 114: } 115: 116: return v; 117: } 118: 119: /// <summary> 120: /// 登录注册上下文。 121: /// </summary> 122: /// <param name="info"></param> 123: public void Add(LoginInfo info) 124: { 125: lock (this.m_LoginInfos) 126: { 127: int count = this.m_LoginInfos.Where 128: (p => p.Session.SessionID == info.Session.SessionID 129: && p.LoginID == info.LoginID 130: ).Count(); 131: 132: if (count == 0) 133: { 134: this.m_LoginInfos.Add(info); 135: info.Session.ClientClosed += Session_ClientClosed; 136: } 137: } 138: 139: this.CreateOnLineMesssage(); 140: } 141: 142: /// <summary> 143: /// 链接关机上下文。 144: /// </summary> 145: /// <param name="session"></param> 146: public void Remove(Guid session) 147: { 148: lock (this.m_LoginInfos) 149: { 150: LoginInfo info = this.m_LoginInfos.Where(p => p.Session.SessionID == session).FirstOrDefault(); 151: 152: if (info != null) 153: { 154: this.m_LoginInfos.Remove(info); 155: info.Session.ClientClosed -= new EventHandler(Session_ClientClosed); 156: } 157: } 158: } 159: 160: /// <summary> 161: /// 生成在线清单信息。 162: /// </summary> 163: [MethodImpl(MethodImplOptions.Synchronized)] 164: void CreateOnLineMesssage() 165: { 166: this.m_OnLineMessage = new OnLineMessage(); 167: lock (this.m_LoginInfos) 168: { 169: foreach (var item in this.m_LoginInfos) 170: { 171: OnLine onLine = new OnLine(); 172: onLine.LoginID = item.LoginID; 173: onLine.Name = item.User.Name; 174: this.m_OnLineMessage.OnLines.Add(onLine); 175: } 176: } 177: } 178: 179: /// <summary> 180: /// 客户段连接断开,用户下线。 181: /// </summary> 182: /// <param name="sender"></param> 183: /// <param name="e"></param> 184: private void Session_ClientClosed(object sender, EventArgs e) 185: { 186: NetSession session = sender as NetSession; 187: LoginInfo loginInfo = this.GetLoginInfo(session.SessionID); 188: this.Remove(session.SessionID); 189: this.CreateOnLineMesssage(); 190: 191: //向其他用户发生下线通稿。 192: UserStateMessage userState = new UserStateMessage(); 193: userState.OnLine = false; 194: userState.User = loginInfo.User; 195: 196: lock (this.m_LoginInfos) 197: { 198: foreach (var item in this.m_LoginInfos) 199: { 200: ChatRoomContext.Instance.SocketServer.Send(item.Session.SessionID, userState); 201: } 202: } 203: } 204: } 205: } 其中public List<LoginInfo> LoginInfos属性即为当前在线的用户与网络会话(NetSession)的映射清单。 八、服务端处理登录/上线、下线流程 客户端在处理用户登录时执行以下流程: 执行本流程的具体代码在ChatRoom.Socket项目之中的登录消息处理器LoginMessageHandler之中: 1: using EAS.Sockets; 2: using EAS.Sockets.Messages; 3: using System; 4: using System.Collections.Generic; 5: using System.Linq; 6: using System.Text; 7: using System.Data; 8: using EAS.Data.Access; 9: using ChatRoom.Messages; 10: using EAS.Loggers; 11: using ChatRoom.BLL; 12: using ChatRoom.Entities; 13: using EAS.Services; 14: 15: namespace ChatRoom.Socket 16: { 17: /// <summary> 18: /// 用户登录消息处理程序。 19: /// </summary> 20: public class LoginMessageHandler : AbstractMessageHandler<LoginMessage> 21: { 22: public override void Process(NetSession context, uint instanceId, LoginMessage message) 23: { 24: LoginResultMessage result = new LoginResultMessage(); 25: IUserService services = ServiceContainer.GetService<IUserService>(); 26: try 27: { 28: result.User = services.UserLogin(message.LoginID, message.PassWord); 29: } 30: catch (System.Exception exc) 31: { 32: result.Error = exc.Message; 33: } 34: 35: //X.登录失败。 36: if (!string.IsNullOrEmpty(result.Error)) 37: { 38: context.Reply(result); 39: return; 40: } 41: 42: //A.登录成功,做如下处理 43: 44: #region //1.向其发送登录成功消息 45: 46: context.Reply(result); 47: 48: #endregion 49: 50: #region //2.向其他用户发送上线通告 51: 52: UserStateMessage userState = new UserStateMessage(); 53: userState.OnLine = true; 54: userState.User = result.User; 55: 56: var vList = ChatRoomContext.Instance.LoginInfos; 57: if (vList.Count > 0) 58: { 59: lock (vList) 60: { 61: foreach (var item in vList) 62: { 63: ChatRoomContext.Instance.SocketServer.Send(item.Session.SessionID, userState); 64: } 65: } 66: } 67: 68: #endregion 69: 70: #region //3.注册到上下文环境 71: 72: LoginInfo loginInfo = new LoginInfo(); 73: loginInfo.LoginID = message.LoginID; 74: loginInfo.User = result.User; 75: loginInfo.Session = context; 76: ChatRoomContext.Instance.Add(loginInfo); 77: #endregion 78: 79: #region //4.向客户段发送在线清单 80: 81: context.Reply(ChatRoomContext.Instance.OnLineMessage); 82: 83: #endregion 84: } 85: } 86: } 当客户端下线/断开链接之后服务端会向其他在线的客户段发送一个UserStateMessage状态通告消息,告诉其他在线客户端,某人已经下线。 九、服务端聊天消息转发流程 当服务端接收到客户端发来的聊天消息之后,如何转发呢,请参见下图: 关于这一部分的代码请参考ChatRoom.Socket项目之中的聊天消息处理器ChatMessageHandler之中:: 1: using EAS.Sockets; 2: using EAS.Sockets.Messages; 3: using ChatRoom.Messages; 4: using System; 5: using System.Collections.Generic; 6: using System.Linq; 7: using System.Text; 8: 9: namespace ChatRoom.Socket 10: { 11: /// <summary> 12: /// 服务器收到聊天消息处理程序。 13: /// </summary> 14: public class ChatMessageHandler : AbstractMessageHandler<ChatMessage> 15: { 16: public override void Process(NetSession context, uint instanceId, ChatMessage message) 17: { 18: if (!message.Secret) //广播消息。 19: { 20: lock (ChatRoomContext.Instance.LoginInfos) 21: { 22: foreach (var p in ChatRoomContext.Instance.LoginInfos) 23: { 24: context.Server.Send(p.Session.SessionID, message); 25: } 26: } 27: } 28: else 29: { 30: LoginInfo loginInfo = ChatRoomContext.Instance.GetLoginInfo(message.To); 31: if (loginInfo != null) 32: { 33: context.Server.Send(loginInfo.Session.SessionID, message); 34: } 35: } 36: } 37: } 38: } 关于这一部分的代码请参考: 十、客户端界面的异步处理 因为AgileEAS.NET SOA 中间件平台Socket 通信框架何用的是异步消息处理模式,所以当客户端收到服务器发回的消息的时候其工作线程与界面UI线呢不一致,那么UI界面处理的时候我们就需要异步处理,比如在显示收到的ChatMessage的时候: 1: /// <summary> 2: /// 显示聊天消息。 3: /// </summary> 4: /// <param name="chat"></param> 5: internal void ShowMessage(ChatMessage chat) 6: { 7: Action action = () => 8: { 9: string form = "你"; 10: string to = "你"; 11: 12: //其他人。 13: if (chat.From != AppContext.User.LoginID) 14: { 15: var v = this.m_OnLines.Where(p => p.LoginID == chat.From).FirstOrDefault(); 16: if (v != null) 17: form = v.Name; 18: else 19: form = chat.From; 20: } 21: 22: //所有人 23: if (string.IsNullOrEmpty(chat.To)) 24: { 25: to = DEFAULT_ALL_USER; 26: } 27: else // 28: { 29: var v = this.m_OnLines.Where(p => p.LoginID == chat.To).FirstOrDefault(); 30: if (v != null) 31: to = v.Name; 32: else 33: to = chat.From; 34: } 35: 36: string face = string.IsNullOrEmpty(chat.Face) ? string.Empty : string.Format("{0}地", chat.Face); 37: string Text = string.Format("【{0}】{1}{2}对【{3}】说:{4}", form, chat.Action, face, to, chat.Content); 38: 39: ListViewItem item = new ListViewItem(new string[] { string.Empty, Text }); 40: item.ForeColor = Color.FromArgb(chat.Color); 41: item.Tag = chat.From; 42: 43: if (chat.Secret) //密聊 44: { 45: this.lvSecret.Items.Add(item); 46: this.lvSecret.EnsureVisible(item.Index); 47: } 48: else 49: { 50: this.lvAll.Items.Add(item); 51: this.lvAll.EnsureVisible(item.Index); 52: } 53: }; 54: 55: this.Invoke(action); 56: } 我们定义了一个名称为action的匿名方法,使用this.Invoke(action)进行界面的消息显示。 十一、联系我们 为了完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台了开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA中间Socket/Tcp框架进行了总体的介绍,我们知道 AgileEAS.NET SOA中间件Socket/Tcp框架是一套Socket通信的消息中间件: 二、简单的服务器客户段消息应答 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架-简单例子-实现简单的服务端客户端消息应答中我们实现了一个简单的客户端消息请求==>服务端应答的简单的Socket应用。 三、完整的应用-实现完整的聊天室 本文我们将实现一个多人聊天室的应用,类似于早年的网络聊天室或者当年的QQ网络聊天室或者游戏里面的聊天功能,聊到室主界面如下: 聊天室支持公聊和私聊频道,理论上可以支持几百甚至几千人,具体上限没有经过测试,在这个案例之中,大家将会掌握基于AgileEAS.NET SOA中间件Socket/Tcp框架的比较复杂的消息定义及消息处理及消息协调,同时还会掌握如何管理服务端的链接、聊天室用户在线状态、消息的多目标转发等功能。 本案例的可执行客户端程序和服务端已经在我们的服务器上为大家部署了一套,大家可以下载客户段http://42.121.30.77/downloads/eas/examples/chat.client.rar体验,下载客户端压缩包之后解压缩,注册一个账号就可以使用这个账号登录我们为大家搭建的聊天室服务端。 三、下载源代码编译配置运行 本案例源代码请通AgileEAS.NET SOA中间件官方网站的最新下载中的栏目进行下载或者从SVN中获取最新版本的源代码: 下载或者SVN-OUT得到代码之后我们来看一下代码文建构: 一级目录 二级目录 说明 Code 程序源代码 Entities 实体(ORM)代码 BLL.Contracts 业务契约定义代码 BLL.Host 数据实现代码 Messages Socket通信消息定义 Services Socket服务定义 ChatRoom 客户段程序代码 UserManage 注册用户管理代码 db 用户数据库文件,Sqlite数据库 Documents 文档,用户模型文档 Publish 引用程序集及编译输出 然后用VS2010或者VS2012打开Code目录之中的ChatRoom解决方案进行编译,编译写成之后我们开始进行配置。 打开Publish目录之中的EAS.SOA.Server.exe.config进行服务端配置: 其中最重要的配置就是配置服务端sqlite数据库文件的路径,以及端口号,当然端口号是可以不用修改的,配置完成之后我们启动Publish目录之中的soaserver.start.bat指指理文件来启动聊天室服务端: 启动聊天室服务端的本质是启动AgileEAS.NET SOA 中间件SOA服务,在SOA服务之中我们集成了Socket插件服务系统,我们的聊天室做为一个SOA的Socket插件服务被进行加载和处理,需要说明的是如果你的运行环境是Win7或者Win2008操作系统,需要以管理员权限运行启动脚本: 接下来我们配置客户段,打开ChatingRoom.MainClient.exe.config文件,修改以下地方: 这样我们变完成了聊天室客户端的配置,运行ChatingRoom.MainClient.exe程序启动客户端的登录窗口: 点用户注册注册一个新用户: 注册成功之后使用这个用户登录聊天室: 到时为止,聊天室案例的配置过程到此完成! 四、源代码学习 要学习和研究本案例的源代码,请参考: 1.AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍 2.AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架-简单例子-实现简单的服务端客户端消息应答 在之后的文章之中我们将会对本案例源代码进行分析。 五、特别感谢 感谢团队成员计文忻同学为大家编写了本案例的第一版本,之后我在通信和界面上做了一些小的调整,也感谢王涛同学为本应用案例提供了Banner图片和一些界面美工建议,也感谢在此案例进行测试和提出建议的客户和小伙伴们。 六、联系我们 为了完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台了开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、讨论主题与观点 写一篇文章、发现一次自觉得有意思的SOA架构方面的讨论,源于昨天AgileEAS.NET SOA 平台群(113723486)里几个群友的一次关于ESB的一次讨论。 大家的讨论观点主要集成在:对于ESB的定义也有类观点,一类观点是把ESB定位于SOA架构之中的基础服务设施(书上都这么讲),还有一类观点就是ESB做为异构系统之间的集成和整合之间,其实ESB本身都能实现两种观点的功能,只是觉得在时下,应该更偏重于那一方面,两者的本质上最大的区别是,同一系统内部的功能是否需要经过ESB进行调用。 ESB是SOA架构的基础服务设施的观点,我们可以用买下图来表示: 这个图应该是最符合SOA架构和ESB的一些书籍之间的ESB架构图,我们可以简单的解释一上,即史是A系统调用A系统的服务,也必须经过ESB系统,那么有ESB系统的规划和建设就是一个必须早期考虑的问题,即我们必须先建立SOA的基础架构和ESB体系,并且在这个架构上面开发A系统、B系统、C系统,这是一种观点,那么在目前我们国内,政府、企业领导应答是很喜欢这样的结构的,统一规划、场面宏大,这里面就出现一个问题,整体系统被规划的非常完美,但是实际上这更好像一个用远也不能完全的梦(永远都没有完美的东西),实现成本就不可估量。 ESB最好是做为异构系统之间的集成整合之用,我们可以用买下图来表示: 这个观点是我的观点为,即我认识这是一种比较现实和比较经济的观点,ESB用被做于异构系统之间的整合,他是支持异构系统的整合的基础设施,而不是基于统计规划下的基础服务设施,基于这个观点的原因是,企业内部各种各样的系统不可能全部推翻了,全部规划和重来,很多企业的供应商在某一领域也做的很专业,博众家之长并进行集成应该是一个比较现实和可取的做法,一个系统一个系统稳定有序的实现,应该是比全部重新规划具体更小的风险。 二、聊天记录摘抄 金靓(123140395) 13:40:58 大家好 金靓(123140395) 13:41:34 想做服务的统一调用 也就是说所有的业务系统都走服务总线 通过总线来进行业务服务的调用 简单的消息交换模式没问题 请求/响应 但是双向交换模式下如何实现呢 何戈州<hotdefans@qq.com> 13:52:15 双工吗? 金靓(123140395) 13:52:23 对的 何戈州<hotdefans@qq.com> 13:52:36 那也没问题 金靓(123140395) 13:52:57 能否给点思路 何戈州<hotdefans@qq.com> 13:53:05 socket 问老魏 金靓(123140395) 13:53:14 基于WCF 魏琼东(47920381) 14:19:02 @纳尼 双工模式貌似ESB实现不了吧。 纳尼(123140395) 14:19:27 BIZTALK里也不能吗 纳尼(123140395) 14:19:48 @魏琼东 貌似可以的 魏琼东(47920381) 14:21:06 但是全双工的通论,让ESB通知应用这事难了点 纳尼(123140395) 14:21:23 所以我有点郁闷 纳尼(123140395) 14:21:41 其实本来没去设计双向通信 魏琼东(47920381) 14:21:46 实现全双方都是socket吧 魏琼东(47920381) 14:22:10 除非用ESB回调某个系统的服务 纳尼(123140395) 14:22:27 对的 魏琼东(47920381) 14:22:32 即应用掉用===》ESB===》应用的服务 魏琼东(47920381) 14:22:40 那你说的是ESB的服务路由了 纳尼(123140395) 15:35:20 虽然没有什么含量,而且是在H.O.T指导下才弄明白的,但还是应该分享一下给大家 纳尼(123140395) 15:36:06 刚才我说的那个客户端需要调用服务实现双向通信,基于ESB 纳尼(123140395) 15:36:52 ESB提供双向接口服务 纳尼(123140395) 15:37:54 其实我想做的ESB,要实现服务的统一调用 纳尼(123140395) 15:38:09 所有的客户端都通过ESB来调用业务服务 纳尼(123140395) 15:38:39 这样的话,势必需要ESB对客户端公开的接口都要相对稳定 纳尼(123140395) 15:38:47 自己要做 纳尼(123140395) 15:39:24 也就是说A->ESB->B->ESB->A 纳尼(123140395) 15:38:39 这样的话,势必需要ESB对客户端公开的接口都要相对稳定 纳尼(123140395) 15:38:47 自己要做 纳尼(123140395) 15:39:24 也就是说A->ESB->B->ESB->A 过错 <wang2650@sohu.com> 15:39:36 java 不怕麻烦用mule 哈哈 魏琼东(47920381) 15:39:37 这个做法算是ESB的滥用吧 纳尼(123140395) 15:39:51 基于WCF下实现,也就是ESB公开一个回到契约 魏琼东(47920381) 15:40:21 WCF本身在TCP通信下本身就回回调 魏琼东(47920381) 15:40:28 但是是要选择TCP通信的前提 纳尼(123140395) 15:40:28 @魏琼东 您指的是统一调用吗? 纳尼(123140395) 15:43:12 ME TOO 魏琼东(47920381) 15:43:18 这说明在找抽 纳尼(123140395) 15:43:30 我也这么觉得 魏琼东(47920381) 15:43:34 是在搞为了ESB搞ESB 魏琼东(47920381) 15:43:42 是没有需求搞有ESB 魏琼东(47920381) 15:43:47 真正企业有很多不同的系统 魏琼东(47920381) 15:43:53 比如PB开发的,VB开发的 魏琼东(47920381) 15:43:56 JAVA开发的的 魏琼东(47920381) 15:44:00 .NET开发的 魏琼东(47920381) 15:44:04 数据库跑在ORACLE上的 魏琼东(47920381) 15:44:08 SQLServer上的 冯永博(309805629) 15:44:10 sharepoint 搞么 魏琼东(47920381) 15:44:11 还有MYSQL的 纳尼(123140395) 15:44:12 是的 魏琼东(47920381) 15:44:28 那么在这种情况下ESB就是解决问题的存在的先决条件之一 魏琼东(47920381) 15:44:39 ESB是因为大家做接口做郁闷了,才上的。 魏琼东(47920381) 15:44:42 不是一开始就上的。 纳尼(123140395) 15:44:54 是的 魏琼东(47920381) 15:45:01 ESB的设计更多的是解决不修改各个系统而实现与系统的对接 纳尼(123140395) 15:45:14 但是ESB更多的是更好的管理服务 魏琼东(47920381) 15:45:18 不是了你把所有服务都通过ESB,所有系统都修改一通 纳尼(123140395) 15:45:27 您说的是系统的集成 魏琼东(47920381) 15:45:29 那不是没事找抽嘛 纳尼(123140395) 15:45:58 您说的正在做,只不过是其他人 魏琼东(47920381) 15:46:04 ESB的做用不就是做这事的嘛 魏琼东(47920381) 15:46:21 当然,ESB也可以是SOA的基础设施 魏琼东(47920381) 15:46:26 所有的服务都经由 魏琼东(47920381) 15:46:28 ESB 魏琼东(47920381) 15:46:31 这个也没错 纳尼(123140395) 15:46:38 是的 纳尼(123140395) 15:46:53 一个完整得SOA平台 魏琼东(47920381) 15:47:06 是啊 纳尼(123140395) 15:47:12 服务的管理需要禁得其考研 魏琼东(47920381) 15:47:16 @纳尼 把你的ESB Show一下 纳尼(123140395) 15:47:32 如果不走ESB,那么服务很难管好 魏琼东(47920381) 15:47:35 “需要禁得其考研“,这个好 纳尼(123140395) 15:47:38 对不起,我刚刚开始 纳尼(123140395) 15:47:47 魏琼东(47920381) 15:47:56 现实之中就没有这样的需要 纳尼(123140395) 15:47:58 等我把这个做差不多了 魏琼东(47920381) 15:48:06 为了轮子造轮子 纳尼(123140395) 15:48:06 我会共享出来的 纳尼(123140395) 15:48:17 SOA是骗人的 魏琼东(47920381) 15:48:22 我定位做异构系统的集成之用 魏琼东(47920381) 15:48:27 也不是骗人的 魏琼东(47920381) 15:48:44 SOA架构是服务于合作伙伴的 纳尼(123140395) 15:48:48 那毕竟只是SOA的一部分 魏琼东(47920381) 15:48:55 内部一系统搞的那么复杂就有问题了 纳尼(123140395) 15:49:29 但是对于庞大的企业,业务很大 纳尼(123140395) 15:49:39 所有的业务都要是发布成服务的 纳尼(123140395) 15:50:07 如果随便的去调用服务,那么是很杂乱的 纳尼(123140395) 15:50:19 我也很赞同您说的 纳尼(123140395) 15:50:36 就是系统内的服务不走ESB 纳尼(123140395) 15:50:48 但是,什么又是系统内的呢 纳尼(123140395) 15:51:01 很多数据慢慢会被公有化 ....(879621940) 15:51:13 请问一下,如果一套系统,包括HR,CMR,ERP,OA,BI等要实现数据共享,是不是也可以用SOA技术呢? 纳尼(123140395) 15:51:41 至少中石油正在做 纳尼(123140395) 15:51:53 @。。。 如上回答 纳尼(123140395) 15:52:09 包括国内的拥有 纳尼(123140395) 15:52:12 用友 ....(879621940) 15:52:26 就是说都是使用SOA技术对吧? 纳尼(123140395) 15:52:37 他们的平台也是基于SOA的(2010年前,现在不知) 纳尼(123140395) 15:52:50 SOA更多是个理念 魏琼东(47920381) 15:52:50 你有一个假设已经错了 纳尼(123140395) 15:52:55 “骗人的” 魏琼东(47920381) 15:53:03 你假设企业内部系统是统一的 纳尼(123140395) 15:53:06 @魏琼东 您说 魏琼东(47920381) 15:53:12 纳尼(123140395) 15:49:29 但是对于庞大的企业,业务很大 所有的业务都要是发布成服务的 如果随便的去调用服务,那么是很杂乱的 我也很赞同您说的 魏琼东(47920381) 15:53:30 你的假设就是要早一部非常完美的东西 魏琼东(47920381) 15:53:39 比如说你的服务是完美的 纳尼(123140395) 15:53:42 对 魏琼东(47920381) 15:53:59 而事实是当系统庞大到这个份上就有一个问题 魏琼东(47920381) 15:54:05 这个东西永远都不成熟 魏琼东(47920381) 15:54:07 OK 魏琼东(47920381) 15:54:09 明白 纳尼(123140395) 15:54:15 SOA的理念不仅仅是关注现在,还要展望未来(说出这种话,有点恶心) 魏琼东(47920381) 15:54:19 那么更实现做的做法是什么 纳尼(123140395) 15:54:43 @魏琼东 BPM可能会解决您所说的 魏琼东(47920381) 15:54:51 更现实的做法是企业内部的系统都是由不同的供应商来供应和开发 纳尼(123140395) 15:54:54 快速应对需求的变化 纳尼(123140395) 15:55:06 赞同 冯永博(309805629) 15:55:13 这个应该没法避免,要信息化建设有个规划和统筹 魏琼东(47920381) 15:55:15 因为比始做HR的对HR业务一定是擅长的 魏琼东(47920381) 15:55:28 做PLM的也是擅长PLM的 魏琼东(47920381) 15:55:41 并且这样的成本也就会低很多 魏琼东(47920381) 15:55:49 就如同软件工程之中的敏捷方法一样 魏琼东(47920381) 15:55:57 拆成小的,一个一个人搞 纳尼(123140395) 15:55:58 非常赞同 ....(879621940) 15:55:59 如果这些系统都是自己开发呢? 魏琼东(47920381) 15:56:08 一个搞坏也只是一个 魏琼东(47920381) 15:56:16 不是一个搞坏全搞完完了 冯永博(309805629) 15:56:22 自己开发的也不一样就用的好 魏琼东(47920381) 15:56:26 我为什么支持这些观点呢 魏琼东(47920381) 15:56:34 是因为我做10多年的医疗业务 魏琼东(47920381) 15:56:38 大家都走过一个过程 魏琼东(47920381) 15:56:48 前些年大家都追求一个医院全是一家的 纳尼(123140395) 15:56:57 嗯 魏琼东(47920381) 15:56:59 但是企业做的累,医院觉得都不专业 魏琼东(47920381) 15:57:04 所以现在慢慢的都是开放式的 魏琼东(47920381) 15:57:10 专业的各做各的 纳尼(123140395) 15:57:51 我觉得BPM足够用了 魏琼东(47920381) 15:57:57 客户也觉得这样挺好 冯永博(309805629) 15:58:05 现在的趋势是越做越大 纳尼(123140395) 15:58:14 但是领导玩的都是趋势 纳尼(123140395) 15:58:24 政府上SOA 魏琼东(47920381) 15:58:30 @刺客 哥们,你的脑袋在想什么呢 纳尼(123140395) 15:58:34 移动、联通 魏琼东(47920381) 15:58:44 领导的事咱不想了 纳尼(123140395) 15:58:45 还有中石油 魏琼东(47920381) 15:58:50 反正 你做出ESB那样搞也行。 纳尼(123140395) 15:59:13 领导从别人那抄点想法,害苦我们啊 冯永博(309805629) 15:59:19 比如 SAP的ERP 集成的子系统是越来越多 纳尼(123140395) 15:59:22 我是这么想的 过错 <wang2650@sohu.com> 15:59:31 soa通常解决是服务发布的问题 esb通常解决的是异构通信的问题 纳尼(123140395) 15:59:42 最好是适应特定的场景 过错 <wang2650@sohu.com> 16:00:53 有的时候目的不同 但是会用同一样的东西 过错 <wang2650@sohu.com> 16:02:04 soa不过是esb的一部分罢了 纳尼(123140395) 16:02:49 @过错 呵呵 那么在建设和使用ESB到底是偏向那一个重点呢,欢迎各位博客园朋友讨论本话题。
一、AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA中间Socket/Tcp框架进行了总体的介绍,我们知道 AgileEAS.NET SOA中间件Socket/Tcp框架是一套Socket通信的消息中间件: 二、简单例子-实现简单的服务器客户段消息应答 我们接下来实现一个简单的例子,例子的场景非常的简单,客户端向服务端发送一个请求消息,服务段收到消息之后显示消息内容,并对客户端发送一个应答消息,客户端收到应答消息之后显示这个应答消息,对于本例子,我们使用WinForm应用来实现。 三、一步一步实现 首先我们下载AgileEAS.NET SOA 中间件最新版本5.0/5.1,下载地址:http://www.smarteas.net/page/EAS_NET_Downloads.aspx。 首先我们打开VS2010或者VS2010创建一个类为项目Socket.Demo.Messages: 删除默认的Class1.cs,引用AgileEAS.NET SOA 中间件的EAS.MicroKernel.dll程序集文件,然后添加一个类请求消息类RequestMessage: 1: [Serializable] 2: [Message("14DB99D2-190C-48E9-879A-EA833247F24A", "请求消息")] 3: public class RequestMessage:IMessage 4: { 5: /// <summary> 6: /// 消息内容。 7: /// </summary> 8: public string Content 9: { 10: get; 11: set; 12: } 13: 14: public void Load(EAS.IO.BufferReader reader) 15: { 16: this.Content = reader.ReadString(); 17: } 18: 19: public void WriteTo(EAS.IO.BufferWriter writer) 20: { 21: writer.Write(this.Content); 22: } 23: } 以上代码我们定义了一个请求消息,消息ID为"14DB99D2-190C-48E9-879A-EA833247F24A",Load方法实现从消息读取器之中读出消息内容,WriteTo方法实现把消息内容写入消息编写器,转换为字节流供通信引擎进行收发,接下来我们再增加一个应答消息类ResponseMessage: 1: [Serializable] 2: [Message("D94C51C4-8423-4BF6-A011-184265BBA62C", "应答消息")] 3: public class ResponseMessage : RequestMessage, IMessage 4: { 5: } 在本例子之中应答消息与请求消息其内容没有本质的区别,都是文本通信,所以就直接继承了RequestMessage,变更了MessageID和消息说明。 到此为止,我们已经完成了请求消息与应答消息的定义Socket.Demo.Messages项目结构下: 接下来我们来实现服务端程序,向解决方案添加一个Socket.Demo.Server的Windows窗体应用程序: 同样,我们要引用AgileEAS.NET SOA 中间件的EAS.MicroKernel.dll程序集文件,并且还要引用Socket.Demo.Messages项目,然后重命名Form1为MainForm,并做以下界面布局: 接下来我们向服务端加载请求消息的处理器RequestMessageHandler,用于服务端收到请求消息之后的处理动作: 1: class RequestMessageHandler:AbstractMessageHandler<RequestMessage> 2: { 3: public override void Process(NetSession context, uint instanceId, RequestMessage message) 4: { 5: //1.显示消息。 6: MainForm.Instance.ShowMessage(message); 7: 8: //2.向客户端回复一条应当消息。 9: string content = string.Format("{0}已收到,OK!", message.Content); 10: ResponseMessage responseMessage = new ResponseMessage { Content = content }; 11: context.Reply(responseMessage); 12: } 13: } 然后我们实现MainForm窗体的功能代码: 1: using System; 2: using System.Collections.Generic; 3: using System.ComponentModel; 4: using System.Data; 5: using System.Drawing; 6: using System.Linq; 7: using System.Text; 8: using System.Windows.Forms; 9: using EAS.Sockets; 10: using Socket.Demo.Messages; 11: 12: namespace Socket.Demo.Server 13: { 14: public partial class MainForm : Form 15: { 16: public static MainForm Instance = null; 17: private SocketServer m_SocketServer = null; 18: 19: public MainForm() 20: { 21: InitializeComponent(); 22: Instance = this; 23: 24: //实例化对象。 25: this.m_SocketServer = new SocketServer(); 26: 27: //端口号为6610 28: this.m_SocketServer.Port = 6610; 29: 30: //注册消息处理器。 31: this.m_SocketServer.AddHander<RequestMessage>(new RequestMessageHandler()); 32: 33: this.m_SocketServer.ServerStarted += new EventHandler(m_SocketServer_ServerStarted); 34: this.m_SocketServer.ServerStopped+=new EventHandler(m_SocketServer_ServerStopped); 35: } 36: 37: void m_SocketServer_ServerStarted(object sender, EventArgs e) 38: { 39: this.btnStart.Enabled = false; 40: this.btnStop.Enabled = true; 41: } 42: 43: void m_SocketServer_ServerStopped(object sender, EventArgs e) 44: { 45: this.btnStart.Enabled = true; 46: this.btnStop.Enabled = false; 47: } 48: 49: internal void ShowMessage(Messages.RequestMessage message) 50: { 51: Action UI = () => 52: { 53: this.tbMessage.AppendText(message.Content); 54: this.tbMessage.AppendText("\r\n"); 55: this.tbMessage.ScrollToCaret(); 56: }; 57: 58: this.Invoke(UI); 59: } 60: 61: private void btnStart_Click(object sender, EventArgs e) 62: { 63: if (this.m_SocketServer.ServerState == ServerState.Stoped) 64: { 65: this.m_SocketServer.StartServer(); 66: } 67: } 68: 69: private void btnStop_Click(object sender, EventArgs e) 70: { 71: if (this.m_SocketServer.ServerState != ServerState.Stoped) 72: { 73: this.m_SocketServer.StopServer(); 74: } 75: } 76: } 77: } 其中代码this.m_SocketServer.AddHander<RequestMessage>(new RequestMessageHandler());完成向服务器注册请求消息的处理器对象,internal void ShowMessage(Messages.RequestMessage message)方法用于显示服务器收到的请求消息。 接下来我们来实现客户端程序,向解决方案添加一个Socket.Demo.Client的Windows窗体应用程序,同前面一样样,我们要引用AgileEAS.NET SOA 中间件的EAS.MicroKernel.dll程序集文件,并且还要引用Socket.Demo.Messages项目,然后重命名Form1为MainForm,并做以下界面布局: 接下来我们向客户端加载应答消息的处理器ResponseMessageHandler,用于客户端收到应答消息之后的处理动作: 1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using EAS.Sockets.Messages; 6: using Socket.Demo.Messages; 7: using EAS.Sockets; 8: 9: namespace Socket.Demo.Client 10: { 11: class ResponseMessageHandler : AbstractMessageHandler<ResponseMessage> 12: { 13: public override void Process(NetSession context, uint instanceId, ResponseMessage message) 14: { 15: //1.显示消息。 16: MainForm.Instance.ShowMessage(message); 17: } 18: } 19: } 然后我们实现MainForm窗体的功能代码: 1: using System; 2: using System.Collections.Generic; 3: using System.ComponentModel; 4: using System.Data; 5: using System.Drawing; 6: using System.Linq; 7: using System.Text; 8: using System.Windows.Forms; 9: using EAS.Sockets; 10: using Socket.Demo.Messages; 11: 12: namespace Socket.Demo.Client 13: { 14: public partial class MainForm : Form 15: { 16: public static MainForm Instance = null; 17: SocketClient m_SocketClient; 18: 19: public MainForm() 20: { 21: InitializeComponent(); 22: Instance = this; 23: this.m_SocketClient = new SocketClient(); 24: this.m_SocketClient.IPAddress = "127.0.0.1"; 25: this.m_SocketClient.Port = 6610; 26: this.m_SocketClient.AddHander<ResponseMessage>(new ResponseMessageHandler()); 27: 28: this.m_SocketClient.Connected += new EventHandler(m_SocketClient_Connected); 29: this.m_SocketClient.Closed += new EventHandler(m_SocketClient_Closed); 30: } 31: 32: void m_SocketClient_Connected(object sender, EventArgs e) 33: { 34: this.btnConnect.Enabled = false; 35: this.btnClose.Enabled = true; 36: this.btnSend.Enabled = false; 37: } 38: 39: void m_SocketClient_Closed(object sender, EventArgs e) 40: { 41: this.btnConnect.Enabled = true; 42: this.btnClose.Enabled = false; 43: this.btnSend.Enabled = true; 44: } 45: 46: internal void ShowMessage(ResponseMessage message) 47: { 48: Action UI = () => 49: { 50: this.tbMessage.AppendText(message.Content); 51: this.tbMessage.AppendText("\r\n"); 52: this.tbMessage.ScrollToCaret(); 53: }; 54: 55: this.Invoke(UI); 56: } 57: 58: private void btnConnect_Click(object sender, EventArgs e) 59: { 60: if (this.m_SocketClient.ClientState == ClientState.Closed) 61: { 62: this.m_SocketClient.Connect(); 63: } 64: } 65: 66: private void btnClose_Click(object sender, EventArgs e) 67: { 68: if (this.m_SocketClient.ClientState != ClientState.Closed) 69: { 70: this.m_SocketClient.Connect(); 71: } 72: } 73: 74: private void btnSend_Click(object sender, EventArgs e) 75: { 76: if (this.tbSend.Text.Trim().Length == 0) 77: { 78: MessageBox.Show("不能发空消息"); 79: return; 80: } 81: 82: if (this.m_SocketClient.ClientState != ClientState.Closed) 83: { 84: RequestMessage rm = new RequestMessage(); 85: rm.Content = this.tbSend.Text.Trim(); 86: this.m_SocketClient.Send(rm); 87: } 88: } 89: } 90: } OK,这个简单的例子我们已经开发完成了,接下来,我们来编译、测试一下这个例子! 四、运行测试 首先我们启动服务端程序、启动服务器,然后启动客户段并连接服务器,从客户段向服务器发送消息,服务端会显示客户端发送的消息会向客户端发送一个应答消息。 五、本例源代码下载 本文例子源代码请通过http://42.121.30.77/downloads/eas/examples/Socket.Demo.rar进行下载,有关于AgileEAS.NET SOA 中间件平台请通过AgilleEAS.NET SOA 中站件平台官方网站的最新下载页面下载。 六、联系我们 为了完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台了开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、关于Socket/Tcp框架的需求 在AgileEAS.NET SOA 中间件平台在大量客户的使用过程之中,有的客户提出了一些基于“消息推”、和应用系统事件通知的需求,比如在“医院信息系统”、“电子病历系统‘、”区域公共卫生平台“、等系统之中就提供了这样的需求,比如当大夫为病人开立了医嘱之后、需要在相关护理人员即时提示,之前大家都使用数据库刷新,数据库的压力都比较大,所以迫切的提出了这样的需求。 另外一个原因是AgileEAS.NET SOA 中间件平台之前一直使用WCF、WS、Romotinig通信做为SOA分布式架构的通信基础,我们在考虑WS、WCF的某些协议并不能提供给我们非常高效的通信,所以我们也需要有一套直接基于Socket/TCP的通信体系用于支撑我们的SOA分布式服务业务体系。 三、AgileEAS.NET SOA 中间件Socket/Tcp框架结构 AgileEAS.NET SOA中间件需要的Socket/Tcp框架严格意思是需要的基于Socket的通信消息中件间,其所提供的功能本质是对消息的处理,所以其所提供的API有三大类、Socket框架本身、消息框架及消息处理框架,以下是AgileEAS.NET SOA中间件的Socket/Tcp的应用框架结构: 各上图我们可以看到AgileEAS.NET SOA中间件需要的Socket/Tcp框架实现了这么一件有意思的事,把原生的Socekt基于数据流的流式通信模式转换为基于消息的消息通信模式,让开发人员多复杂的系统Socket通信和数据流处理之中解放出来,转而关心高层通信消息的设计和消息处理的业务设计与实现。 三、AgileEAS.NET SOA 中间件Socket/Tcp框架重要的接口和类 AgileEAS.NET SOA中间件需要的Socket/Tcp框架严格意思是需要的基于Socket的通信消息中件间,其所提供的功能本质是对消息的处理,所以其所提供的API有三大类、Socket框架本身、消息框架及消息处理框架,以下是AgileEAS.NET SOA中间件的Socket/Tcp的应用框架结构: 其中ISocketCient接口为客户段功能封装,其定义大体如下: 1: /// <summary> 2: /// Tcp客户端接口。 3: /// </summary> 4: public interface ISocketClient : ISocketEngine 5: { 6: /// <summary> 7: /// 客户端状态。 8: /// </summary> 9: ClientState ClientState 10: { 11: get; 12: } 13: 14: /// <summary> 15: /// 连接Tcp服务器。 16: /// </summary> 17: bool Connect(); 18: 19: /// <summary> 20: /// 关闭与服务器的连接。 21: /// </summary> 22: void Close(); 23: 24: /// <summary> 25: /// 发送消息。 26: /// </summary> 27: /// <param name="message">消息。</param> 28: void Send(IMessage message); 29: 30: /// <summary> 31: /// 调用消息,用于服务器/客户端应用中的请示==》响应消息的应用。 32: /// </summary> 33: /// <param name="request">请示消息。</param> 34: /// <returns>服务器返回的响应消息。</returns> 35: IMessage Invoke(IMessage request); 36: 37: /// <summary> 38: /// 异步调用消息,用于服务器/客户端应用中的请示==》响应消息的应用。 39: /// </summary> 40: /// <param name="request">请示消息。</param> 41: /// <returns>包含响应消息的异步任务。</returns> 42: NetInvokeTask BeginInvoke(IMessage request); 43: 44: /// <summary> 45: /// 服务器发生错误时触发。 46: /// </summary> 47: event ErrorEventHandler Error; 48: 49: /// <summary> 50: /// 连接服务器后触发。 51: /// </summary> 52: event EventHandler Connected; 53: 54: /// <summary> 55: /// 断开服务器连接后触发。 56: /// </summary> 57: event EventHandler Closed; 58: } 其是最重要方法为void Send(IMessage message)方法,即发送一个消息到服务器,这个方法也是对使用者开放的最重要方法,在这里发送的不是字节流,而是一个实现了IMessage接口的消息对象,当服户段接收到IMessage对象之后会调用与其对应的消息处理器(IMessageHandler)对象进行消息处理,反之客户段收到IMessage也会调用与其相关的消息处理器(IMessageHandler)对象进行处理。 ISocketServer、ISocketServerBase接口: 1: /// <summary> 2: /// Socket服务器基类接口。 3: /// </summary> 4: public interface ISocketServerBase : ISocketEngine 5: { 6: /// <summary> 7: /// 客户端会话集合。 8: /// </summary> 9: IList<NetSession> Sessions 10: { 11: get; 12: } 13: 14: /// <summary> 15: /// 注册了一个新会话后发生。 16: /// </summary> 17: event NetSessionEventHandler SessionStarted; 18: 19: /// <summary> 20: /// 某一个会话结束后发生。 21: /// </summary> 22: event NetSessionEventHandler SessionAbandoned; 23: 24: /// <summary> 25: /// 发送消息。 26: /// </summary> 27: /// <param name="target">消息接收方ID(会话ID)。</param> 28: /// <param name="message">消息。</param> 29: void Send(Guid target, IMessage message); 30: 31: /// <summary> 32: /// 发送网络消息。 33: /// </summary> 34: /// <param name="target">消息接收方ID(会话ID)。</param> 35: /// <param name="netMessage">网络消息。</param> 36: void Send(Guid target, NetMessage netMessage); 37: 38: /// <summary> 39: /// 发送网络报文(仅网关模式有效)。 40: /// </summary> 41: /// <param name="target">消息接收方ID(会话ID)。</param> 42: /// <param name="netPacket">网络报文。</param> 43: void Send(Guid target, NetPacket netPacket); 44: 45: /// <summary> 46: /// 发送网络数据(仅网关模式有效)。 47: /// </summary> 48: /// <param name="target">消息接收方ID(会话ID)。</param> 49: /// <param name="buffer">网络数据。</param> 50: void Send(Guid target, byte[] buffer); 51: } 1: /// <summary> 2: /// Socket服务器接口。 3: /// </summary> 4: public interface ISocketServer : ISocketServerBase 5: { 6: /// <summary> 7: /// 客户端连接数。 8: /// </summary> 9: int ClientCount 10: { 11: get; 12: } 13: 14: /// <summary> 15: /// 服务器状态。 16: /// </summary> 17: ServerState ServerState 18: { 19: get; 20: } 21: 22: /// <summary> 23: /// 开始Tcp服务器。 24: /// </summary> 25: void StartServer(); 26: 27: /// <summary> 28: /// 停止Tcp服务器。 29: /// </summary> 30: void StopServer(); 31: 32: /// <summary> 33: /// 关闭指定客户的连接。 34: /// </summary> 35: /// <param name="client">客户Guid。</param> 36: void AbandonSession(System.Guid client); 37: 38: /// <summary> 39: /// 服务器发生错误时触发。 40: /// </summary> 41: event ServerErrorEventHandler ServerError; 42: 43: /// <summary> 44: /// 服务器启动后触发。 45: /// </summary> 46: event System.EventHandler ServerStarted; 47: 48: /// <summary> 49: /// 服务器停止后触发。 50: /// </summary> 51: event System.EventHandler ServerStopped; 52: } 这两个接口定义了SocketServer的一些行为和属性,其中最重要的方法还是void Send(Guid target, IMessage message),实现向某个特定客户段连接发送应用消息,别外定义了一个IList<NetSession> Sessions属性,表示目前连接到此SocketServer的所有客户端会话信息。 NetSession表示服务器的一个客户段连接会话,包括连接上下文信息和连接的Socket通信对象,当某个SocketClient发送给SocketServer的信息都会被与其应对的NetSession进行处理,NetSession定义两个重要的方法public void Reply(uint requestID, IMessage message)和public void Abandon(),其中Reply表示向客户端回复一个消息,Abandon表示服务器强制中止此会话。 在整个Socket/tcp框架之中进行通信的最基本单元都是IMessage,那么SocketClient、SocketServer接收到IMessage如何处理呢,答案是由与之配对的IMessageHandler进行处理,所以SocketClient、SocketServer都实现了一个基础接口ISocketEngine: 1: /// <summary> 2: /// Socket引擎,Socket网络通信基础类。 3: /// </summary> 4: public interface ISocketEngine : IDisposable 5: { 6: /// <summary> 7: /// 通信引擎的全局唯一标识符号。 8: /// </summary> 9: System.Guid Guid 10: { 11: get; 12: } 13: 14: /// <summary> 15: /// IP地址和端口号。 16: /// </summary> 17: IPEndPoint IPEndPoint 18: { 19: get; 20: set; 21: } 22: 23: /// <summary> 24: /// IP地址。 25: /// </summary> 26: string IPAddress 27: { 28: get; 29: set; 30: } 31: 32: /// <summary> 33: /// 端口号。 34: /// </summary> 35: int Port 36: { 37: get; 38: set; 39: } 40: 41: /// <summary> 42: /// 报文最大长度。 43: /// </summary> 44: int MessageMaxSize 45: { 46: get; 47: } 48: 49: /// <summary> 50: /// 注册消息处理器。 51: /// </summary> 52: /// <typeparam name="T">消息类型。</typeparam> 53: /// <param name="hander">消息处理器。</param> 54: void AddHander<T>(IMessageHandler<T> hander) where T : IMessage; 55: 56: /// <summary> 57: /// 通过Socket发送数据之后触发。 58: /// </summary> 59: event SocketDataHandler SocketDataSend; 60: 61: /// <summary> 62: /// 通过Socket接收数据之后触发。 63: /// </summary> 64: event SocketDataHandler SocketDataReceived; 65: 66: /// <summary> 67: /// 发送报文完成之后触发。 68: /// </summary> 69: event PacketHandler PacketSend; 70: 71: /// <summary> 72: /// 报文接收完成之后触发。 73: /// </summary> 74: event PacketHandler PacketReceived; 75: 76: /// <summary> 77: /// 载送完一个NetMessage之后触发。 78: /// </summary> 79: event NetMessageHandler NetMessageSend; 80: 81: /// <summary> 82: /// 接收完一个NetMessage之后触发。 83: /// </summary> 84: event NetMessageHandler NetMessageReceived; 85: 86: /// <summary> 87: /// 消息发送完成之后触发。 88: /// </summary> 89: event MessageHandler MessageSend; 90: 91: /// <summary> 92: /// 接收消息完成之后触发。 93: /// </summary> 94: event MessageHandler MessageReceived; 95: } 其中方法void AddHander<T>(IMessageHandler<T> hander) where T : IMessage实现对消息处理器的注册,以便收到IMessage之后选择合适的处理器进行处理。 四、消息和消息处理器 从以上的介绍我们可以明确的知道AgileEAS.NET SOA中间件Socket/Tcp框架是的一个基于消息对象的消息通信框架,那么其最核心的业务就是定义消息及消息的处理思路,我们称之为消息及消息处理器结构: 其中IMessage接口为Socket/Tcp框架中最重要的接口,所有高层的应用消息都需要实现本接口: 1: /// <summary> 2: /// 消息接口定义。 3: /// </summary> 4: /// <remarks> 5: /// 这里所说的消息是指业务处理的最小单元,而不是传输于网络之间的网络消息。 6: /// </remarks> 7: public interface IMessage 8: { 9: /// <summary> 10: /// 从指定的 MessageReader加载消息对象。 11: /// </summary> 12: /// <param name="reader">消息读取器。</param> 13: void Load(BufferReader reader); 14: 15: /// <summary> 16: /// 将消息对象保存到指定的MessageWriter。 17: /// </summary> 18: /// <param name="writer">消息编写器。</param> 19: void WriteTo(BufferWriter writer); 20: } 其中Load和WriteTo实现IMessage消息对象实例与字节流之间进行相互转换,Load消息用于从字节流之中读取并实例化消息、WriteTo把消息转换为流写入消息流之中,在应用开发过程之中必须实现这两个方法并且在消息类上打上MessageAttribute标记: 1: /// <summary> 2: /// 消息ID属性。 3: /// </summary> 4: /// <remarks> 5: /// 标记网络消息,确定其唯一的ID。 6: /// </remarks> 7: [AttributeUsage(AttributeTargets.Class)] 8: public class MessageAttribute : Attribute 9: { 10: /// <summary> 11: /// 初始化MessageAttribute对象实例。 12: /// </summary> 13: /// <param name="messageID">消息ID。</param> 14: public MessageAttribute(string messageID) 15: :this(messageID,string.Empty) 16: { 17: 18: } 19: 20: /// <summary> 21: /// 初始化MessageAttribute对象实例。 22: /// </summary> 23: /// <param name="messageID">消息ID。</param> 24: /// <param name="description">消息说明。</param> 25: public MessageAttribute(string messageID, string description) 26: { 27: this.MessageID = new Guid(messageID); 28: this.Description = description; 29: } 30: 31: /// <summary> 32: /// 消息ID。 33: /// </summary> 34: public Guid MessageID 35: { 36: get; 37: set; 38: } 39: 40: /// <summary> 41: /// 消息说明。 42: /// </summary> 43: public string Description 44: { 45: get; 46: set; 47: } 48: } MessageAttribute标记用于向已实现IMessage接口的具体消息的消息ID与消息说明,即向Socket通信框架声音本消息的唯一性之用,其中MessageID为一个GUID对象,GUID对象理论上是唯一的,我们可以表示消息的唯一性,以下是一个具体的消息例子: 1: /// <summary> 2: /// 用户登录消息。 3: /// </summary> 4: [Message("F42433DF-2D4D-4514-9523-2FE911E63CAA", "登录消息")] 5: [Serializable] 6: public class LoginMessage : IMessage 7: { 8: /// <summary> 9: /// 用户名。 10: /// </summary> 11: public string LoginID 12: { 13: get; 14: set; 15: } 16: 17: /// <summary> 18: /// 密码。 19: /// </summary> 20: public string PassWord 21: { 22: get; 23: set; 24: } 25: 26: #region IMessage 成员 27: 28: /// <summary> 29: /// 30: /// </summary> 31: /// <param name="reader"></param> 32: public void Load(EAS.IO.BufferReader reader) 33: { 34: LoginID = reader.ReadString(); 35: PassWord = reader.ReadString(); 36: } 37: 38: /// <summary> 39: /// 40: /// </summary> 41: /// <param name="writer"></param> 42: public void WriteTo(EAS.IO.BufferWriter writer) 43: { 44: writer.Write(LoginID); 45: writer.Write(PassWord); 46: } 47: 48: #endregion 49: } 以上是一个具体消息的例子,其表明消息ID为“F42433DF-2D4D-4514-9523-2FE911E63CAA”,其作用是登录消息,用于实现类似登录业务。 五、可靠的消息中间件 AgileEAS.NET SOA中间件Socket/Tcp框架是一个可靠的消息中间件,在设计过程之初就选择了完成端口模型进行开发,以保证服务的高并发和吞吐量,在底层消息通信上,我们选择了不超过8K的可变大小通信报文,比如当一个高层的IMeesage只有512字节内容的时候,会取转成一个一个远小于8K的报文进行发送,如果一个高层IMeesage为66K时,会被分解成为9条消息报文进行通信,前8条消息报文长度为8K,最后一条不满足8K,接收文收到这9条报文后组合并转换为IMeesage对象之后交由消息处理器IMeeesgaHandler进行处理。 在进行消息报文收发过程之中,经过长期测试、验证、设计和选择了高性能的防粘包设计,避免应用开发者头疼的消息粘包问题。 六、AgileEAS.NET SOA中间件需要的Socket/Tcp框架下载 AgileEAS.NET SOA中间件Socket/Tcp框架包含在AgileEAS.NET SOA中间件平台之中,具体定义在EAS.MicroKernel.dll程序集之中,要使用AgileEAS.NET SOA中间件Socket/Tcp框架进行基于Socket的通信开发,请通过AgilleEAS.NET SOA 中站件平台官方网站的最新下载页面下载。 七、联系我们 为了完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台了开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台。用于帮助中小型软件企业建立一条适合市场快速变化的开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的。 AgileEAS.NET SOA中间件平台提供了敏捷快速开发软件工程的最佳实践,通过提供大量的基础支撑功能如IOC、ORM、SOA、分布式体系及敏捷并发开发方法所支撑的插件开发体系,以及提供了大量的实体、数据模型设计生成工具、代码生成工具,用于帮助中小软件开发商快速成长。 AgileEAS.NET平台充分把握目前软件行业快速发展的新趋势,基于敏捷并行开发、快速适应市场这样淳朴的软件工程实践,采用业界广泛使用的Microsoft .Net构件(组件)开发技术实践了这种开发思想,帮助软件企业实现“敏捷变化、快速适合”的目标,从而帮助软件企业在激烈的市场竞争中赢得先机并获得更高的回报。 二、AgileEAS.NET SOA 中间件平台5.1反馈 在2013年早些时候,我们向大家发布了AgileEAS.NET SOA 5.1版本,并且提供了一个基于”分布式SOA-SAAS-架构的药品商店”的案例供大家参考,目前有很多的客户和朋友基于AgileEAS.NET SOA平台开发了医疗、铁路、电力、农林、房地产、物联网、物流、教育、钢铁、企业信息化领域的产品,通过大家的反馈来看还是暴露出了如下的问题和不足: 1).大家一致反馈AgileEAS.NET SOA中间件平台是一个非常不错的基础平台,但是入门难度很高,初次拿到平台不知道如何下手,比如不知道如何建立和配置数据库、SOA服务端和客户配置。 2).案例较少,一直以来只有一个DrugShop案例。 3).对Web开发支持不够。 从以上三点总的来看,一切的根源是AgileEAS.NET SOA 中间件是一个自成体系的一个不小的综合体,很多配置、使用缺乏有效的文档和指引,很多朋友都希望我们能给大家提供一些视频教程。 三、2013年第四季度发布计划 AgileEAS.NET SOA中间件平台一直以来入门门槛过高的根本原因是在我们AgileEAS.NET SOA开发团队自身,在我们的想法之中一直是努力给大家提供更好、更多的功能,但是易用性和如何降低入门门槛一直没有引起我们的重视,或许这与我们的团队的运作有一定的关系,因为AgileEAS.NET SOA中间件平台产品是免费的,并且我们也承诺一下会免费下去,所以我们团队的运作经费都来源于为软件企业所做的咨询服务上面,我们这些付费的服务客户因为都由我们进行指导开发,所以入门门槛过搞的原因也一直没有被引起重视。 AgileEAS.NET SOA 5.2版本,也就就即将准备发布的版本我们将来会作太多功能性的调整,但是会想办法在入门门槛上想办法降低,将会为大家提供更多的案例、进多的文档学习资料,也会考虑会平台之中的某些内容进行开源。 以下是AgileEAS.NET SOA 中间件平台5.2的发布计划: 1).AgileEAS.NET 5.2会把ActiveXForm运行容器一并发布,以某些客户满足使用Winform/WPF开发CS、BS兼容应用的能力。 2).在提供药品商店DrugShop应用案例的同时,还会向大家提供一个基于WinForm应用的小型EPR/进销存的案例/开源提供。 3).会向大家提供Web应用案例/开源提供。 4).会向大家介绍AgileEAS.NET SOA中间件的Socket通信框架。 5).会向大家提供一个基于AgileEAS.NET SOA中间件Socket通信框架的案例”聊天室案例”/开源提供。 除此之外,我们还会把AgileEAS.NET SOA中间件平台之中的以下几部分内容以开源形式向大家提供: 1).AgileEAS.NET SOA 中间件的Silverlight应用容器的源代码及插件功能、权限和等一系列的管理功能以源代码向大家提供,供大家开发参考。 2).AgileEAS.NET SOA 中间件集成的RDL报表系统、已经过我们汉化和Bug修改、广泛应用于医疗、铁路、电力等领域,将会以源代码形式向大家共享,以供更多有需要的朋友使用。 四、联系我们 为了完善、改进和推广AgileEAS.NET而成立了敏捷软件工程实验室,是一家研究、推广和发展新技术,并致力于提供具有自主知识产权的业务基础平台软件,以及基于业务基础平台了开发的管理软件的专业软件提供商。主要业务是为客户提供软件企业研发管理解决方案、企业管理软件开发,以及相关的技术支持,管理及技术咨询与培训业务。 AgileEAS.NET平台自2004年秋呱呱落地一来,我就一直在逐步完善和改进,也被应用于保险、医疗、电子商务、房地产、铁路、教育等多个应用,但一直都是以我个人在推广,2010年因为我辞职休息,我就想到把AgileEAS.NET推向市场,让更多的人使用。 我的技术团队成员都是合作多年的老朋友,因为这个平台是免费的,所以也没有什么收入,都是由程序员的那种理想与信念坚持,在此我感谢一起奋斗的朋友。 团队网站:http://www.agilelab.cn, AgileEAS.NET网站:http://www.smarteas.net 官方博客:http://eastjade.cnblogs.com QQ:47920381,AgileEAS.NET QQ群:113723486(AgileEAS SOA 平台)/上限1000人 199463175(AgileEAS SOA 交流)/上限1000人 120661978(AgileEAS.NET 平台交流)/上限1000人 212867943(AgileEAS.NET研究)/上限500人 147168308(AgileEAS.NET应用)/上限500人 172060626(深度AgileEAS.NET平台)/上限500人 116773358(AgileEAS.NET 平台)/上限500人 125643764(AgileEAS.NET探讨)/上限500人 193486983(AgileEAS.NET 平台)/上限500人 邮件:james@agilelab.cn,mail.james@qq.com, 电话:18629261335。
一、AgileEAS.NET SOA平台简介 AgileEAS.NET SOA平台是一套应用系统快速开发平台,用于帮助中小软件开发商快速构建自己的企业信息管理类开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的,AgileEAS.NET应用开发平台包含基础类库、资源管理平台、运行容器、开发辅助工具等四大部分,资源管理平台为敏捷并行开发提供了设计、实现、测试等开发过程的并行。 AgileEAS.NET SOA平台基于软件过程改进以及构件化快速开发两方面达到这方面的目标,在软件过程改进实践方面,提出了独有的“敏捷并行开发方法”开发方法,其目的是在软件的管理之中提出符合国内中小软件企业实际情况并且可操作的软件工程实践、软件过程改进思想、及相配套的项目管理系统。 在快速开发方面,AgileEAS.NET SOA平台提供了企业应用开发所需的诸如ORM、IOC、分布式通信、插件与平台基础结构以及一系统的快速生成工具,涵盖开发过程中的设计、编码、集成、部署、运维等各个环节。 AgileEAS.NET SOA平台是一套基于微软dotNET技术体系的企业级快速开发平台/中间件/框架,我们一直一来努力为国内中心软件开发商、创业团队、独立开发者提供最好的企业应用快速开发工具帮助大家成长,在最新的AgileEAS.NET‘ 5 .0版本中对Winform/WPF/Silverlight/WebForm都提供运行支撑平台,我们努力提供一套Winform/WPF/Silverlight/WebForm不同展现与统一的后端支撑的多层分布式架构体系。 二、AgileEAS.NET SOA平台5.1版本变化 AgileEAS.NET SOA平台 5.0版本在5.0,版本的基础上做了非常大的变动和提高: 1.完成了大部分Linq表达式的实现,5.0版本的Linq,仅实现了针对单对象的查询、分页、排序等操作,5.1版本则实现了90%的linq表达式,包括多实体(表)链接、分组汇总、聚合处理,使用linq即可以实现大部分的业务功能。 2.进一步优化了ORM的性能,重点优化了ORM对象加载、分布式架构之中的处理和影响速度。 3.新增加对Mysql、Sqlite数据库的支持,目前AgileEAS.NET SOA平台共支持SQL Server、ORACLE、Mysql、Sqlite四种数据库。 4.优化了SOA服务器的响应性能。 5.增加AgileIM.NET即时通讯产品并和平台进行了深度整合。 6.扩展了工作流,实现了多人审批、和分级组织权限的控制。 7.强化WinClient运行容器,增加了Desktop样式。 8.开放更多WinClient运行容器接口,开发人员可以定制主界面。 9.增加了数制库初始化工作,让学习者更容易入门。 10.增加了配置定义工具,让开发和部署更方便。 11.新版本集成了Grid++报表,让报表开发和报表打印有了更多的选择。 12.增加一个快速字典录入工具,快速实现类似DataWindow的功能,帮助开发人员实现各种字典的快速辅助录入。 13.增加快速动态报表功能,让系统的实使人员、系统维护人员快速的根据客户需求实现各种自定义了报表,不修改任何程序即向使用者提供各种扩展报表。 三、AgileEAS.NET SOA 5.1下载 AgileEAS.NET SOA平台 51版本目前可以在AgileEAS.NET SOA 官方网站http://wwww.smarteas.net网站最新下载栏目进行下载。 这里需要注意的是最新版本的下载不带任何数据库文件或者数据库脚本,请下载之后执行数据库初始化工具EAS.DbInitializer.exe创建AgileEAS.NET SOA平台运行所必须的数据库结构和数据。 与5.1版本配套的案例DruShop也提供了下载,请大家通过官网的最新下载栏目进行下载。 下一篇文章我将会向大家介绍如何初始化配置AgileEAS.NET SOA 平台及搭建基本的开发环境。 四、如何联系我们 如果您在使用AgileEAS.NET开发平台中有什么问题,请使用如下几种联系方式或者沟通方式。 1、官方网站: AgileEAS.NET平台:http://www.smarteas.net/ 敏捷软件工程实验室:http://www.agilelab.cn/
在说这个案例之前先向大家转发一个简单的招聘信息,我们团队目前需要招聘两名技术助理人员,跟随我们做一些产品开发和技术咨询工作,欢迎有志同道合的朋友与我们合作:http://job.cnblogs.com/offer/19632/。 一、案例业务流程说明 在前一篇文章AgileEAS.NET SOA 中间件平台工作流系统介绍之中我简单的向大家介绍了AgileEAS.NET SOA平台工作流系统的基本介绍,本文我将向大家以一个真实的案例向大家介绍AgileEAS.NET SOA平台工作流系统的应用。 今天我们的例子来自于医疗信息化之中的一个简单案例,关于医院药库/药房药品报损业务的处理过程,现实业务流程如以定义: 目前的业务流程是这么要求的,由药房管理人员发起一个报损申请,然后由药房负责人审批,早批不通过则由药房管理人员修改后再次提交,通过则由药剂科长审核,审核通过之后由药房管理人员确认报损,否则终止本次报损业务处理。 对于不同地域、不同规模、不同经营性质的医院来说,对于药品的报损处理流程都可能不一样,那么摆在医疗开发商面前的一个很麻烦问题就是业务流程的定制处理,对于此类问题使用传统方法一直是一个非常棘手的问题,可能不同医院的业务流程的变动必须会导致程序代码的变动,进行造成医疗软件开发商产品版本管理混乱、产品实施周期过长进而导致开发商的间接管理成本和项目总体成本急剧提高。 二、应用AgileEAS.NET SOA平台工作流重组流程 对于上述问题,我们可以使用AgileEAS.NET SOA平台所提供的工作流系统进行业务流程自定义,使用工作流平台驱动业务数据达到业务流程再造的目的。 我们来仔细看上述业务流程就会发现,这是一个及其经典的“申请-早批-确认”业务处理流程,对于“申请”和“确认”都是一个比较固定的操作,但是对于“申请-早批-确认”的处理过程,则是一个极不确定的过程,比如一个小型医疗机构可以就需要一个简单的审批即可,但是对于一个大型的医疗机构,其审批可以不止二级审批,可能会有三级或多级审批处理。 如果我们开发两个功能模块“药房报损申请/申批”、“药房报损确认”以及定义一个工作流“药房报损申批流程”,并让“药房报损申批流程”与“药房报损申请/申批”相结合,由工作流驱动“药房报损申请/申批”按照“药房报损申批流程”进行处理,并在处理完成之由“药房报损确认”完成药品报损,那么我们是否就可以实现这种高度灵活的流程自定义呢,回答当然是OK,那么接下来我们来看看怎么办到这样的效果吧。 三、如果做?一步一步来 我们来先开始模块“药房报损申请/申批”,其最终效果如下: 接下来模块“药房报损确”,其最终效果如下: 接下来我们来定义工作流“药房报损申批流程”: 流程权限设定: 流程权限设定中包含流程发起权限及各状态的处理权限,其设置方式都一样,同AgileEAS.NET SOA平台中的模块权限设置保持一致,我们在些为账号xyf设定流程发起权限和“审请状态”的处理权限,给帐号zhx设定“审请状态”的处理权限,给账号Administrator设置“审请状态”的处理权限。 接下来需要绑定工作流与其驱动的业务模块之间的关联关系: 同时也需要在模块代码之中完成与工作流的绑定: 在功能模块中需要做两个地方的绑定,第一个在模块的头部需要标记明确WorkflowAddIn属性,用于声明这是一个受工作流驱动的功能模块,另一个是需要在功能模块中的声音一个类型为Guid的属性,并且标记WorkflowInstanceId属性,用于工作流向功能模块写入当前工作流实例,至此为止,工作流定义及流程自定义工作完成,接下来我们看看运行效果吧。 四、如果做?一步一步来 首先,我们使用帐号xyf登录,我们会看到如下功能: 我们打开“发起流程”: 或者直接打开“药房报损申请”模块发起工作流: 提交完成之后打开“我的申请”会看到刚才我们所发起的实例: 接下来,我们切换到账号“zhx”登录,并且打开我的待办: 完成一级审批“药房报损申请”: 打开已办事宜: 接下来,我们切换到账号“888888”登录,并且打开我的待办: 完成二级审核“药房报损申请”: 打开已办事宜: 最后我们切换到账号“xyf”,并打开 “药房报损确认”模块: 至此,药房药品报损业务处理演示完成,若审批流程发生变更,则只需要项目实施人员根据客户的业务流程修改工作流定义,而不需要修改程序代码,实现流程的自定义。 五、AgileEAS.NET 4.0 下载 有关于平台最新版本的最新发布版本的程序集、类库手册、相关资料,请大家从AgileEAS.NET平台的官网http://www.smarteas.net/进行下载,官网设有独立的下载页面,从这里下载:官网下载页面。 六、如何联系我们 如果您在使用AgileEAS.NET开发平台中有什么问题,请使用如下几种联系方式或者沟通方式。 1、官方网站: AgileEAS.NET平台:http://www.smarteas.net/ 敏捷软件工程实验室:http://www.agilelab.cn/
一、AgileEAS.NET SOA平台简介 AgileEAS.NET SOA平台是一套应用系统快速开发平台,用于帮助中小软件开发商快速构建自己的企业信息管理类开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的,AgileEAS.NET应用开发平台包含基础类库、资源管理平台、运行容器、开发辅助工具等四大部分,资源管理平台为敏捷并行开发提供了设计、实现、测试等开发过程的并行。 AgileEAS.NET SOA平台基于软件过程改进以及构件化快速开发两方面达到这方面的目标,在软件过程改进实践方面,提出了独有的“敏捷并行开发方法”开发方法,其目的是在软件的管理之中提出符合国内中小软件企业实际情况并且可操作的软件工程实践、软件过程改进思想、及相配套的项目管理系统。 在快速开发方面,AgileEAS.NET SOA平台提供了企业应用开发所需的诸如ORM、IOC、分布式通信、插件与平台基础结构以及一系统的快速生成工具,涵盖开发过程中的设计、编码、集成、部署、运维等各个环节。 AgileEAS.NET SOA平台是一套基于微软dotNET技术体系的企业级快速开发平台/中间件/框架,我们一直一来努力为国内中心软件开发商、创业团队、独立开发者提供最好的企业应用快速开发工具帮助大家成长,在最新的AgileEAS.NET‘ 5 .0版本中对Winform/WPF/Silverlight/WebForm都提供运行支撑平台,我们努力提供一套Winform/WPF/Silverlight/WebForm不同展现与统一的后端支撑的多层分布式架构体系。 二、AgileEAS.NET SOA平台工作流系统 AgileEAS.NET SOA平台的早期版本不包含业务流程平台,2010年以来,很多客户提出了有必要让我们提供工作流系统的想法,也就有了今天的产品,AgileEAS.NET SOA平台的工作流系统自2010年5月份开始至今,经历过一次失败及一次构建思想重大的变更之后变成趋于成熟,并且目前已应用于客户的几个项目之中。 在早期的时候,我们的开发人员借鉴了微软WF3.5的工作流技术但并没有使用WF3.5的工作流引擎,并且自己写了一套工作流引擎,采用与顺序工作流相类似的业务风格,但这次尝试失败了,失败的原因第一是自己写工作流引擎需要考虑很多的技术和业务细节,并且所引发的未知问题不可控制,第二是开发人员在思维理解及对于练习技术与为客户做需要需要的产品之间的巨大的差异没有仔细考虑,这里也说到一个关于技术人员值得思考的问题,那就是“你倒底是需要做出客户需要的产品还是你为了某项技术而淬炼技术,做出一个客户并不需要的产品或者说一个无法产品化的产品”我想这将会是技术人员应该深思的问题,我们很多的开发人员都在为了淬炼自己的技术在那做客户并不需要的产品或者说做出的产品Bug满地,更像是一个学习做品,远远达不到产品化的目标。 因为诸多原因,我放弃了原来的版本,转换采用了微软 WF3.5做为其工作流引擎,并对其做了高层封装,用于满足绝大数工作流应用中的“审批业务流程”,也就是说AgileEAS.NET SOA平台所提供的工作流将主要是为了满足企业申请-审批业务流程的后期灵活而服务。 在经过长期的需求及技术调研之后,最终我们决定以微软的WF3.5为基础实现AgileEAS.NET SOA平台业务流程平台,引擎直接采用微软的WF3.5工作流引擎,工作流设计器参考微软给出的例子使用DesignSurface技术自行完成,自行实现了工作流的运行监控、持久化服务,并结合AgileEAS.NET SOA平台的权限模型实现了工作流发起及各个状态运行的权限控制,并结合AgileEAS.NET SOA平台构件开发的底子实现了工作流与业务构件的完美结合。 AgileEAS.NET SOA平台工作流系统主要涵盖工作流的设计与定义、流程实例的发起与运行、业务流程的监控与管理、工作流系统与业务系统的集成与协作等内容。 AgileEAS.NET SOA平台工作流: 工作流定义: 流程实例监控: 流程实例处理记录: 流程实例对应的业务表单: AgileEAS.NET SOA平台工作流的功能就简单介绍到这儿,接下来的文章我将会以一个具体的例子为大家演示一下AgileEAS.NET SOA平台工作流的使用。 三、关于AgileEAS.NET SOA 5.0 去年8月我就曾向大家预示过要发布AgileEAS.NET SOA平台5.0版本,但是截至到目前为止5.0版本还没有公开提供过,在此我向一直关注和支持AgileEAS.NET SOA平台发布的各位同行和朋友们说声抱歉,也向大家解释一下延迟发布的原因,这里面有两个原因,第一个是因为我对产品的成熟和发展过于乐观,第二个原因是我对于开发团队的引导和监控不力,因为去年现在不只是我一个人在完善这个平台,计划5.0发布中涉及的两个极其重要的部分工作流系统和界面设计器这两个工具在发布之间发现其根本没有达到我的计划目的,包含大量的Bug甚至在某个产品方向上有重大的错误,第三个原因呢主要是项目太多,我们一方面要完善AgileEAS.NET SOA平台,另一方面还需要为客户提供大量的技术咨询和项目指导服务,所以AgileEAS.NET SOA平台5.0版本的发布一直无限的延迟,一方面是继续完善产品,使其达到可用的程度,另一方面是AgileEAS.NET SOA平台5.0在我们向客户提供技术咨询与指导服务的同时,优先向客户提供,以便更早的被应用于生产环境,更早的发现产品中存在的问题,因为我们都在客户现场,产品中的bug或者说设计上的缺陷我们都可以及时的处理和修正,但是对于公开发布而言,当发现产品的缺陷的时候,其处理和修正的成本将会是极其巨大的,我们目前也没有太多的技术人员为大家提供此类服务,新产品的发布所以才会一直被延期,我们希望向客户提供的产品不是一个满地bug的产品,而是一个极其严谨可以的商业产品,虽然AgileEAS.NET SOA平台平台是免费向大家提供,但是我们还是希望提供商业化的品质。 目前想了解和学习AgileEAS.NET SOA平台的朋友请大家还是先下载4.0版本及其相关的例子,对4.0有充分的了解和认识,学习5.0将会更加的简单,5.0和4.0在技术上并没有太多的改变,只是增加了工作流平台、数据表单/界面设计工具、SAAS引擎和支持了Oracle、Mysql、SQLite三种新的数据库系统。 四、AgileEAS.NET 4.0 下载 有关于平台最新版本的最新发布版本的程序集、类库手册、相关资料,请大家从AgileEAS.NET平台的官网http://www.smarteas.net/进行下载,官网设有独立的下载页面,从这里下载:官网下载页面。 五、如何联系我们 如果您在使用AgileEAS.NET开发平台中有什么问题,请使用如下几种联系方式或者沟通方式。 1、官方网站: AgileEAS.NET平台:http://www.smarteas.net/ 敏捷软件工程实验室:http://www.agilelab.cn/
构件化软件开发模式快速响应客户需要的一个非常重要的方式,通过构件对功能的隔离,从而把需要的变更对系统整合的影响降低到最底限度,通过构件的不同版本管理不同客户对同一需要的不同个性化差异,进行降低系统的快速市场适应能力,通过实施企业级构件的开发实践达到提高软件企业有效生产效率的目的,进市提高企业的综合实力。 敏捷软件工程实验室通过了解行业领先的软件工程理念,结合多年的软件开发技术与开发管理咨询实际,总结出一套适合中国特色的软件工程实践与朴素的软件工程言论论:“构件并行开发”、“敏捷并行开发”,用于帮助中小软件企业构件自己的快速开发团队,以适应多变的外部市场。 我们提出了一个严禁、新颖的构建化开发思想,即通过对目标系统(系统需求)的解构--》应用构件思想进行快速开发--》组装配置整合出一个完整的系统,这样一个完整的企业级软件生产新模式。 企业应用构件开发思想进行应用开发实践,必须要建立一个构件支撑平台/系统,为业务构件提供一个运行环境,为其提供构件契约、总线、通过的基础支撑,以及对应用构建进行监控、管理、配置等功能。 我们为中小软件企业提供了一套经过多年运行验证的构件化基础解决方案AgileEAS.NET平台(AgileEAS.NET敏捷构件开发平台),以帮助中小软件企业快速成长。 AgileEAS.NET平台不仅仅是一套构件基础支撑平台,AgileEAS.NET平台同时也提供了一个中小软件企业的的开发管理解决方案,以敏捷并行开发方法为其过程理论依据、以AgileEAS.NET平台为过程实践与指导、以AgilePM.NET为其项目管理工具,在开发技术、软件工程、技术架构、管理工具等方面帮助中小软件提供走向卓越。 PPT下载:面向构件的组织级开发模式探讨.ppt 如何联系我们 如果您在使用AgileEAS.NET开发平台中有什么问题,请使用如下几种联系方式或者沟通方式。 1、官方网站: AgileEAS.NET平台:http://www.smarteas.net/ 敏捷软件工程实验室:http://www.agilelab.cn/ 2、AgileEAS.NET平台交流群: AgileEAS.NET平台交流群:120661978(超级群)[已满] AgileEAS.NET平台交流群:172060626(高级群)[新建]
一、视频会议培训回顾 在前一周我们做了两次视频会议培训,内容分别为AgileEAS.NET平台的整体结构及开源药店系统的搭建演俩、基于AgileEAS.NET的插件开发过程演示,以上内容在AgileEAS.NET平台视频会议培训第一辑-AgileEAS.NET平台介绍及药品系统的SAAS搭建演练、AgileEAS.NET平台视频会议培训第二辑-简单插件开发应用演练(速度下载)做了详细的介绍。 二、本次会议培训的内容 本周星期的视频会议培训由我负责,主要向大家介绍AgileEAS.NET平台对系统的结构和结构过程,主要讲结构,即如何对开发好的插件进行装配、集成、配置、以及基于访问控件列表的权限管理系统(账户、角色、权限)。 本次视频会议培训的视我已经传到上115网盘,请大家下载观看,普通话实在太差,大家就忍忍吧。 下载地址:2011-07-25 视频会议培训 插件的安装、配置以及账户权限系统演练.wmv http://u.115.com/file/bh5ri7xc 五、平台发布下载 有关于平台最新版本的最新发布版本的程序集、类库手册、相关资料,请大家从AgileEAS.NET平台的官网http://www.smarteas.net/进行下载,官网设有独立的下载页面,从这里下载:官网下载页面。 六、如何联系 如果您在使用AgileEAS.NET开发平台中有什么问题,请使用如下几种联系方式或者沟通方式。 1、官方网站: AgileEAS.NET平台:http://www.smarteas.net/ 敏捷软件工程实验室:http://www.agilelab.cn/ 2、AgileEAS.NET平台交流群: AgileEAS.NET平台交流群:120661978(超级群)[新建] AgileEAS.NET平台交流群:125643764(高级群)[新建] AgileEAS.NET平台交流群:147168308(高级群)[新建] 3、系统架构交流群: 系统架构交流群:9105332(高级群)(已满) 系统架构交流群1:124825459(高级群)(已满) 系统架构交流群2:49124441(高级群)(已满) 系统架构交流群3:47025564(高级群)(已满) 链接 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET - 文章汇总及学习指南 AgileEAS.NET平台开发Step By Step系列-药店系统-索引
一、AgileEAS.NET 5.0预告 最近忙着准备AgileEAS.NET 5.0的东西,所以也忙的没有向大家分享有关于AgileEAS.NET平台及相关的快速开发技术,AgileEAS.NET 5.0版本将是一个具体里程碑意思的版本,如果说4.0版本是我创业以来发布的第一个商用版本的话,那么5.0的版本将是一个完整的企业级应用解决方案。 5.0版本在4.0版本的基础之上增加了表单/界面设计器、工作流系统、以及提供了对Silverlight技术的企业级应用支持,同时将会加强AgileEAS.NET平台在SOA/SAAS技术上的支持,5.0版本的完善增加了一组多租户应用的构建技术和管理工具。 二、AgileEAS.NET容易上手吗? AgileEAS.NET平台源于如果更好的解决“如何提高软件企业的有效生产效率”这个问题,我们为中小软件企业提供了一个涵盖软件壶过程、研发管理、技术体系相结合的的 一个中小软件企业的的开发管理解决方案,以敏捷并行开发方法为其过程理论依据、以AgileEAS.NET平台为过程实践与指导、以AgilePM.NET为其项目管理工具,在开发技术、软件工程、技术架构、管理工具等方面帮助中小软件提供走向卓越。 也就是说,AgileEAS.NET平台不是一个MDA平台,也不是解决所有问题的饮弹,我们基于软件工程实践提供了一系列的方法实践、过程改进体系及基于插件技术与构件复用技术的快速开发平台及相关的快速开发辅助工具,尽可能的提稿软件研发团队在技术、管理上的综合能力,但并不是给你包揽所有的工具,软件毕竟只是工作,项目还得需要研发人员的努力,至少需要在快速开发工作生成代码、文档的基础上进行工作。 AgileEAS.NET平台基于这么一个模式进行构建,那么就必然会有一个问题产品,AgileEAS.NET平台的入门门槛会有点高,因为AgileEAS.NET平台中涵盖了很多技术点,虽然我们在努力简化,但毕竟有一个限度,要使用AgileEAS.NET平台进行开发,就必然要学习IOC、ORM、插件、通信、架构等很多方面的知识。 那么,要使用AgileEAS.NET进行开发,就必须要花一些时间去学习,至少要读读相关的文章和案例,有很多的朋友总希望早上拿到手,然后问我,这是个什么东西,怎么用怎么配置,那么不好意思,我相信这有难度,如果你是这样一个开发人员,我建议你放弃使用AgileEAS.NET的想法。 三、为什么会采用视频会议培训? 之前我给大家发布了一个基于AgileEAS.NET平台并且使用了SOA/SAAS方案的一个小应用,很多朋友下载了但反馈学不知道怎么配,在之前,我写了AgileEAS.NET平台开发实例-药店系统-快速的SAAS开发体验、应用SAAS结构技术的开源药店管理系统-如何自己部署这种SOA/SAAS结构的在文中纤细的说了如何在线试用和下载源代码之后的配置过程,但可以有些抱歉,可能是我们的配置指导和文档写的并不那么明确和完善,上一周在QQ群和大家交流的过程之中,有一位朋友建议,可不可以搞在在线的视频培训,然后大家都讨论怎么实施方案,原定于在星期天晚上进行第一次培训,我尝试使用Live Meeting 但没有搞成功,之同由我的客户也是我的朋友兰州智威科技给我们提供了视频会议系统进行在线培训。 我相信在线的视频会议培训一定要强于根据文档进行一步一步的培训,大家可以根据视频一步一步的搭建药品系统。 四、本次视频会议培训的内容 原定于昨天晚上的在线视频会议培训主要向大家介绍一下AgileEAS.NET平台以及如何搭建基于SOA/SAAS模式的药店管理系统,计划时长1个小时左右,但明显是超出了这个时间,抱歉这个是我没有安排好的原因,视频培训的效果还倒是不错,只是感觉视频和音频有点不同步,还有一个比较悲剧的地方是,可以刚开始太过于兴奋了,导致忘记了开屏幕录想,结果在讲完AgileEAS.NET平台介绍之后才开始录想,这个有一些悲剧。 本次视频会议培训的视频及PPT我已经传到上115网盘,请大家下载观看,普通话实在太差,大家就忍忍吧。 下载地址:http://u.115.com/file/bh556y8c PPT下载:AgileEAS.NET平台应用开发实践 五、平台发布下载 有关于平台最新版本的最新发布版本的程序集、类库手册、相关资料,请大家从AgileEAS.NET平台的官网http://www.smarteas.net/进行下载,官网设有独立的下载页面,从这里下载:官网下载页面。 六、如何联系 如果您在使用AgileEAS.NET开发平台中有什么问题,请使用如下几种联系方式或者沟通方式。 1、官方网站: AgileEAS.NET平台:http://www.smarteas.net/ 敏捷软件工程实验室:http://www.agilelab.cn/ 2、AgileEAS.NET平台交流群: AgileEAS.NET平台交流群:120661978(超级群)[新建] AgileEAS.NET平台交流群:125643764(高级群)[新建] AgileEAS.NET平台交流群:147168308(高级群)[新建] 3、系统架构交流群: 系统架构交流群:9105332(高级群)(已满) 系统架构交流群1:124825459(高级群)(已满) 系统架构交流群2:49124441(高级群)(已满) 系统架构交流群3:47025564(高级群)(已满) 链接 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET - 文章汇总及学习指南 AgileEAS.NET平台开发Step By Step系列-药店系统-索引
一、AgileEAS.NET平台简介 AgileEAS.NET平台是一套应用系统快速开发平台,用于帮助中小软件开发商快速构建自己的企业信息管理类开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的,AgileEAS.NET应用开发平台包含基础类库、资源管理平台、运行容器、开发辅助工具等四大部分,资源管理平台为敏捷并行开发提供了设计、实现、测试等开发过程的并行。 AgileEAS.NET平台基于软件过程改进以及构件化快速开发两方面达到这方面的目标,在软件过程改进实践方面,提出了独有的“敏捷并行开发方法”开发方法,其目的是在软件的管理之中提出符合国内中小软件企业实际情况并且可操作的软件工程实践、软件过程改进思想、及相配套的项目管理系统。 在快速开发方面,AgileEAS.NET平台平台提供了企业应用开发所需的诸如ORM、IOC、分布式通信、插件与平台基础结构以及一系统的快速生成工具,涵盖开发过程中的设计、编码、集成、部署、运维等各个环节。 二、寿光市区域公共卫生平台 寿光区域公共卫生平台全称为“寿光市区域卫生一体化信息平台”,是由寿光市卫生局负责建议的寿光医疗信息化重大工程,项目由山东中印环球软件公司承担研发,其旨在解决城乡居民的看病贵、看病难的问题,合理统筹医疗资料,建立基于居民健康档案为区域公共卫生平台,整合城乡居民健康档案管理、新农村合作医疗信息系统、医院管理信息系统、社区公共卫生服务系统、医疗卫生行政办公系统等。 参考相关新闻:寿光市区域卫生一体化信息平台投入试运行,中印环球软件公司助力寿光医疗卫生改革信息。 三、如何基于AgileEAS.NET平台构建 寿光区域公共卫生平台由山东中印环球软件公司承担研发,山东中印环球软件公司公司是一家中印合资的软件企业,其主要涉及政府、公安、消防、电子政务与办公自动化、企业ERP等相关的行业与应用研发、实施业务,对于医疗卫生行业有一定的陌生,其后与国内提供医疗信息化的很多企业各组织考虑合作,经过多方考察,最后确定与我所带领的敏捷软件工程实验室合作,合作思路和解决方案如下: 由我们提供AgileEAS.NET 敏捷软件开发平台以及配套的开发技术咨询服务、同时也向他们提供医疗行业信息化方面的行业咨询,由山东中印环球软件公司开发公共平台的相关软件的一部分(健康档案平台及新型农村合作医疗平台)、由我们提供一套基于AgileEAS.NET平台的医院信息系统、电子病历系统,最后由山东中印环球软件公司进行整合和实施。 下面是寿光区域公共卫生平台的网络结构图: 下面是寿光区域公共卫生平台的应用组成结构: 从上面两个图我们可以看出寿光区域公共卫生平台是一个非常复杂的、涉及多个业务系统、多个机构的行业应用系统,其中包含关键的三个系统:健康档案管理系统、新型农村合作医疗、医院信息系统/社区公共卫生服务系统,以及这三个系统之间无缝集成将会是一个很麻烦的问题。 四、项目研发过程及进展、现状 我们山东中印环球软件公司的合作始于2010年12月底,在此之前,山东中印环球软件公司已经组织了一个需求调研小组也做了一部分需要调研工作,合作开始之后我们一边对开发人员进行技术培训(半个月),即基于AgileEAS.NET平台的企业应用开发技术演练,另一方面与整个开小组进行业务分析与架构设计。 得益于AgileEAS.NET平台良好的架构及其提供的大量开发辅助工作以及依赖于山东中印环球软件公司为项目配置了优秀而尽职的开发人员,在正式开发一个半月之后,就拿出了公卫平台中的第一部分:城先居民健康档案管理系统,并于4月初正式上线运行,项目开始2个月之后,完成了公卫平台平台的第二部分:新型农村合作医疗系统,之后我们向开发小组移交了医院信息系统系统电子病历系统,开始了健康档案、新型农村合作医疗、医院信息系统三大系统之间的整合。 可以说,整个寿光公共卫生平台在差不多半年时间之内,从无到有就诞生了,项目截至目前,公共卫生平台的三大系统:健康档案、新家合、医院信息系统都已经上线运行,整合和实施正在进行中,下面给大家给几个应用截图: 健康档案管理系统: 新型农村合作医疗系统: 医院管理信息系统: 五、寿光区卫的感想 寿光区域公共卫生平台这个项目可以说是非常成功的,对于本次合作的多方也都是非常的满意,本项目中应用了AgileEAS.NET平台所提供的诸多思想、技术与工具,也更加印证了AgileEAS.NET是非常可靠的用于构建企业级应用的快速开发中间件,通过本项目,也使山东中印环球软件公司在构建大型分布式企业应用的经验有长足的提高。 六、平台相关下载 有关于平台最新版本的最新发布版本的程序集、类库手册、相关资料,请大家从AgileEAS.NET平台的官网http://www.smarteas.net/进行下载,官网设有独立的下载页面,从这里下载:官网下载。 CallHot 写过一个系列的基于AgileEAS.NET平台的开发案例,请大家通过AgileEAS.NET平台开发Step By Step系列-药店系统-索引及AgileEAS.NET敏捷开发平台及案例下载(持续更新)-索引、AgileEAS.NET平台开发实例-药店系统-视频教程系列-索引一系列文章进行下载。 七、如何联系 如果您在使用AgileEAS.NET开发平台中有什么问题,请使用如下几种联系方式或者沟通方式。 1、官方网站: AgileEAS.NET平台:http://www.smarteas.net/ 敏捷软件工程实验室:http://www.agilelab.cn/ 2、AgileEAS.NET平台交流群: AgileEAS.NET平台交流群:120661978(超级群)[新建] AgileEAS.NET平台交流群:125643764(高级群)[新建] AgileEAS.NET平台交流群:147168308(高级群)[新建] 3、系统架构交流群: 系统架构交流群:9105332(高级群)(已满) 系统架构交流群1:124825459(高级群)(已满) 系统架构交流群2:49124441(高级群)(已满) 系统架构交流群3:47025564(高级群)(已满) 链接 AgileEAS.NET平台开发指南-文章索引 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET平台开发Step By Step系列-药店系统-索引
刚有一个朋友问一个算法问题,问题如下: 有一堆木棒长度在 1m - 21m之间(长度为整数),用户拥有的木棒长度也是用户自定义,的数量用户自定义 其中的一组样例数据是10m 的木棒 300跟, 14m 的木棒223跟, 18m 的木棒412跟, 2米的木棒301跟, 5米的木棒 48跟 我要求的是,这些木棒可以组成多少个 21米长的木棒?(木棒不可以切割,只可以拼接)。 这是一个典型的算法问题,类似在当年的C语言版本的数据结构与算法中的那个有100RMB买多少只公鸡、母鸡、小鸡的问题(各自价格不一),试问有多少种解法。 此类问题最简答的解法是穷举法,大家可以来试着写出其C#、java、c、php的算法,也可以开动脑袋用其他的算法进行解决,期待大家的参与,谢谢。
一、药店系统内容说明 在前些时间,我们发布了一个基于AgileEAS.NET平台的SAAS结构的案例-AgileEAS.NET平台开发实例-药店系统-快速的SAAS开发体验,在文章中同时向大家提供了基于SAAS部署安全的演示客户端下载,也向大家提供了包含全部源代码下载。 AgileEAS.NET平台是一套应用系统快速开发平台,用于帮助中小软件开发商快速构建自己的企业信息管理类开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的,AgileEAS.NET应用开发平台包含基础类库、资源管理平台、运行容器、开发辅助工具等四大部分,资源管理平台为敏捷并行开发提供了设计、实现、测试等开发过程的并行。 药店系统案例以及案例所提供的SAAS部署技术是依赖于AgileEAS.NET平台提供的,这个案例是一个规格比较小,但却很有代表性的一个案例,涵盖了在企业应用系统开发中的一系列技术、比如Orm技术、平台加插入技术、分布式通信技术/WCF/WebService、SAAS技术、SOA思想等。 之前的文章应用SAAS结构技术的开源药店管理系统-源代码结构说明给大家介绍了一下药店系统的源代码目录结构: 之后很有多的朋友希望我在写一篇文章向大家讲一个怎么使用这个源代码包自己部署SAAS结构的药店系统。 二、如何一步一步的部署 首先我们从AgileEAS.NET官网下载药品系统源代码压缩包DrugShop.rar,下载之后解压到本地文件,比如E:\DrugShop,在解开的压缩包之中,可以看不一个叫“药店系统-发布版本”的文件夹,这里面即为进行SAAS部署的必要文件。 “药店系统-发布版本”结构如下: 第一步:编译药店系统源代码 修改解压后根目录中的“build-all.bat”文件如下: 1: setlocal 2: 3: REM 设置路径 4: set dic=E:\DrugShop 5: 6: REM 编译解决方案 7: C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe %dic%\药店系统-源码-VS2010\DrugShop.sln /t:Rebuild /p:Configuration=Release 8: 9: REM 复制文件到发布版本/应用服务器 10: copy %dic%\药店系统-源码-VS2010\Publish\DrugShop.DAL.dll %dic%\药店系统-发布版本\AppServer\Bin /y 11: copy %dic%\药店系统-源码-VS2010\Publish\DrugShop.BLL.dll %dic%\药店系统-发布版本\AppServer\Bin /y 12: 13: REM 复制文件到发布版本/升级版本 14: copy %dic%\药店系统-源码-VS2010\Publish\DrugShop.*.dll %dic%\药店系统-发布版本\AppServer\xClient\Files /y 15: 16: REM 复制文件到发布版本/客户端 17: copy %dic%\药店系统-源码-VS2010\Publish\DrugShop.*.dll %dic%\药店系统-发布版本\WinClient /y 18: 19: pause 执行build-all.bat,编译全部源代码并完成向发布目录的文件复制。 第二步:创建/恢复数据库 在压缩包“药店系统-数据库备份”,包含数据库的备份文件、数据库文件和数据库脚本: 在早先的版本之中,没有提供SQL2000数据库的支持,我随后补充了SQL2000的建库、建表脚本,我们可以任选一种方式进行数据恢复,支持SQL2000/SQL2005/SQL2008,我在本例进行附加,本地安装SQL2008R2数据库。 第三步:安装业务/中间服务 修改“药店系统-发布版本\AppServer\Bin\install.bat,调整一下路径: 1: setlocal 2: set dic=E:\DrugShop 3: %dic%\药店系统-发布版本\AppServer\Bin\EAS.WindowsService /i /name=DrugShop 4: pause 执行install.bat脚本完成服务安装,我们可以在计算机管理: 我们看到一个命名实例为DrugShop的AgileEAS.NET Application Service,在这个服务实例之中运行药品系统的业务逻辑,可以通过服务管理进行启动和停止它。 第四步:启动业务/中间服务 在启动业务/中间服务之前,请先修改服务配置文件之中的数据库连接信息: 1: <?xml version="1.0"?> 2: <configuration> 3: <configSections> 4: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel"/> 5: </configSections> 6: <eas> 7: <windowsservices> 8: <config httpPort="8080" tcpPort="6688"/> 9: <services> 10: <service name="EAS.RMIService" key="EAS.RMIService"/> 11: <service name="EAS.SmartUpdateService" key="EAS.SmartUpdateService"/> 12: </services> 13: </windowsservices> 14: <objects> 15: <!--定义数据访问相关组件。--> 16: <object name="DataConnection" assembly="EAS.Data" type="EAS.Data.Access.SqlClientConnection" LifestyleType="Thread"> 17: <property name="ConnectionString" type="string" value="Data Source=.;Initial Catalog=drugshop;User ID=sa;Password=sa" /> 18: </object> 19: <object name="DataAccessor" assembly="EAS.Data" type="EAS.Data.Access.SqlClientAccessor" LifestyleType="Thread"> 20: <property name="Connection" type="object" value="DataConnection" /> 21: </object> 22: <object name="OrmAccessor" assembly="EAS.Data" type="EAS.Data.ORM.OrmAccessor" LifestyleType="Thread"> 23: <property name="DataAccessor" type="object" value="DataAccessor" /> 24: </object> 25: <object name="ServiceBridger" assembly="EAS.MicroKernel" type="EAS.Services.LocalServiceBridger" LifestyleType="Thread" /> 26: <!--日志组件。--> 27: <object name="Logger" assembly="EAS.MicroKernel" type="EAS.Services.TextLogger" LifestyleType="Singleton"> 28: </object> 29: <object name="EAS.RMIService" assembly="EAS.Distributed.ServiceHost" type="EAS.Distributed.RMIServiceAddIn" LifestyleType="Singleton"> 30: <property name="EnableLogging" type="bool" value="false" /> 31: </object> 32: <object name="EAS.SmartUpdateService" assembly="EAS.Distributed.ServiceHost" type="EAS.SmartUpdate.ServiceAddIn" LifestyleType="Singleton"/> 33: </objects> 34: </eas> 35: <startup> 36: <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> 37: </startup> 38: </configuration> 在本配置文件之中,请根据自己的数据库连接信息修改数据库连接,请根据自己的喜好,修改服务实例的通信端口,共包含两个端口http及tcp端口,默认http端口为8080,tcp端口为6688,请自行修改为两个未必点用的端口。 第五步:生成智能升级配置信息 在本例之中,程序自带了自动升级服务,下面简单介绍一下服务器上的配置: 客户端程序的自动升级及升级配置信息存放在应用服务程序的XClient目录之下: 其中Files目录之中存放客户端程序运行所需要的所有程序集及其他文件,config目录之中只包含用于控制程序集升级的文件清单信息,如下格式所示: 1: <?xml version="1.0" encoding="utf-8"?> 2: <SmartConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 3: <URI>http://www.smarteas.net/</URI> 4: <Name>AgileEAS.NET升级配置文件</Name> 5: <Description>用于AgileEAS.NET平台SmartClient/ActiveX运行容器模块升级之用</Description> 6: <StartEx /> 7: <Time>2011-05-17T20:14:27.6537091+08:00</Time> 8: <Files> 9: <SmartFile> 10: <FileName>DrugShop.BLL.dll</FileName> 11: <Version>1.0.0.0</Version> 12: <Time>2011-05-17T19:52:04.5989573+08:00</Time> 13: </SmartFile> 14: <SmartFile> 15: <FileName>DrugShop.DAL.dll</FileName> 16: <Version>1.0.0.0</Version> 17: <Time>2011-05-17T19:52:03.2296807+08:00</Time> 18: </SmartFile> 19: <SmartFile> 20: <FileName>DrugShop.Res.dll</FileName> 21: <Version>0.0.0.0</Version> 22: <Time>2011-05-17T19:52:07.8126581+08:00</Time> 23: </SmartFile> 24: <SmartFile> 25: <FileName>DrugShop.WinUI.dll</FileName> 26: <Version>1.1.0.0</Version> 27: <Time>2011-05-17T19:52:06.8200238+08:00</Time> 28: </SmartFile> 29: <SmartFile> 30: <FileName>EAS.Data.DataUIMapper.dll</FileName> 31: <Version>1.0.0.0</Version> 32: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 33: </SmartFile> 34: <SmartFile> 35: <FileName>EAS.Data.dll</FileName> 36: <Version>4.0.0.0</Version> 37: <Time>2011-05-16T13:57:51.7015166+08:00</Time> 38: </SmartFile> 39: <SmartFile> 40: <FileName>EAS.Develop.Debuger.dll</FileName> 41: <Version>4.0.0.0</Version> 42: <Time>2011-05-16T22:57:10.1958392+08:00</Time> 43: </SmartFile> 44: <SmartFile> 45: <FileName>EAS.Distributed.Client.dll</FileName> 46: <Version>3.0.0.0</Version> 47: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 48: </SmartFile> 49: <SmartFile> 50: <FileName>EAS.Distributed.Contracts.dll</FileName> 51: <Version>3.0.0.0</Version> 52: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 53: </SmartFile> 54: <SmartFile> 55: <FileName>EAS.Distributed.ServiceHost.dll</FileName> 56: <Version>3.0.0.0</Version> 57: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 58: </SmartFile> 59: <SmartFile> 60: <FileName>EAS.Explorer.AddIn.Assist.dll</FileName> 61: <Version>4.0.0.0</Version> 62: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 63: </SmartFile> 64: <SmartFile> 65: <FileName>EAS.Explorer.BLL.dll</FileName> 66: <Version>2.0.0.0</Version> 67: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 68: </SmartFile> 69: <SmartFile> 70: <FileName>EAS.Explorer.DAL.Interface.dll</FileName> 71: <Version>4.0.0.0</Version> 72: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 73: </SmartFile> 74: <SmartFile> 75: <FileName>EAS.Explorer.DAL.Oracle.dll</FileName> 76: <Version>4.0.0.0</Version> 77: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 78: </SmartFile> 79: <SmartFile> 80: <FileName>EAS.Explorer.DAL.SQLServer.dll</FileName> 81: <Version>4.0.0.0</Version> 82: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 83: </SmartFile> 84: <SmartFile> 85: <FileName>EAS.Explorer.dll</FileName> 86: <Version>3.0.0.0</Version> 87: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 88: </SmartFile> 89: <SmartFile> 90: <FileName>EAS.Explorer.Res.dll</FileName> 91: <Version>1.1.0.0</Version> 92: <Time>2011-05-16T10:57:51.5773604+08:00</Time> 93: </SmartFile> 94: <SmartFile> 95: <FileName>EAS.Explorer.Web.dll</FileName> 96: <Version>4.0.0.0</Version> 97: <Time>2011-05-16T15:31:33.6162114+08:00</Time> 98: </SmartFile> 99: <SmartFile> 100: <FileName>EAS.Explorer.WebClient.dll</FileName> 101: <Version>1.0.0.0</Version> 102: <Time>2011-05-16T10:57:59.0757893+08:00</Time> 103: </SmartFile> 104: <SmartFile> 105: <FileName>EAS.Explorer.WPF.Res.dll</FileName> 106: <Version>1.1.0.0</Version> 107: <Time>2011-04-23T16:22:55.2651826+08:00</Time> 108: </SmartFile> 109: <SmartFile> 110: <FileName>EAS.MicroKernel.dll</FileName> 111: <Version>4.0.0.0</Version> 112: <Time>2011-05-16T20:11:14.9469295+08:00</Time> 113: </SmartFile> 114: <SmartFile> 115: <FileName>EAS.OracleClient.dll</FileName> 116: <Version>1.1.0.0</Version> 117: <Time>2011-05-16T10:57:52.0613881+08:00</Time> 118: </SmartFile> 119: <SmartFile> 120: <FileName>EAS.OrmDesigner.exe</FileName> 121: <Version>2.0.0.0</Version> 122: <Time>2011-05-16T15:10:16.3558135+08:00</Time> 123: </SmartFile> 124: <SmartFile> 125: <FileName>EAS.Report.Controls.dll</FileName> 126: <Version>3.0.0.0</Version> 127: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 128: </SmartFile> 129: <SmartFile> 130: <FileName>EAS.SmartUpdateConfig.exe</FileName> 131: <Version>1.0.0.0</Version> 132: <Time>2011-05-16T15:10:16.3558135+08:00</Time> 133: </SmartFile> 134: <SmartFile> 135: <FileName>EAS.SmartUpdater.exe</FileName> 136: <Version>1.0.0.0</Version> 137: <Time>2011-05-16T15:10:16.3558135+08:00</Time> 138: </SmartFile> 139: <SmartFile> 140: <FileName>EAS.WinClient.exe</FileName> 141: <Version>4.1.0.0</Version> 142: <Time>2011-05-16T15:10:16.3558135+08:00</Time> 143: </SmartFile> 144: <SmartFile> 145: <FileName>EAS.Windows.Controls.dll</FileName> 146: <Version>4.0.0.0</Version> 147: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 148: </SmartFile> 149: <SmartFile> 150: <FileName>EAS.Windows.dll</FileName> 151: <Version>4.0.0.0</Version> 152: <Time>2011-05-16T15:31:25.0985964+08:00</Time> 153: </SmartFile> 154: <SmartFile> 155: <FileName>EAS.Windows.GuiTemplate.dll</FileName> 156: <Version>3.0.0.0</Version> 157: <Time>2011-05-16T15:34:26.4489149+08:00</Time> 158: </SmartFile> 159: <SmartFile> 160: <FileName>Fireball.CodeEditor.dll</FileName> 161: <Version>1.0.0.1</Version> 162: <Time>2006-04-20T17:49:27.578125+08:00</Time> 163: </SmartFile> 164: <SmartFile> 165: <FileName>Fireball.CodeEditor.SyntaxFiles.dll</FileName> 166: <Version>1.0.0.2</Version> 167: <Time>2006-04-20T17:49:28.34375+08:00</Time> 168: </SmartFile> 169: <SmartFile> 170: <FileName>Fireball.Core.dll</FileName> 171: <Version>1.1.0.1</Version> 172: <Time>2006-04-20T13:48:00.125+08:00</Time> 173: </SmartFile> 174: <SmartFile> 175: <FileName>Fireball.SyntaxDocument.dll</FileName> 176: <Version>1.0.0.0</Version> 177: <Time>2006-04-20T13:48:04.1875+08:00</Time> 178: </SmartFile> 179: <SmartFile> 180: <FileName>Fireball.Win32.dll</FileName> 181: <Version>1.0.0.0</Version> 182: <Time>2006-04-20T13:47:57.921875+08:00</Time> 183: </SmartFile> 184: <SmartFile> 185: <FileName>Fireball.Windows.Forms.dll</FileName> 186: <Version>1.9.0.0</Version> 187: <Time>2006-04-20T17:40:03.640625+08:00</Time> 188: </SmartFile> 189: <SmartFile> 190: <FileName>itextsharp.dll</FileName> 191: <Version>4.1.2.0</Version> 192: <Time>2011-04-19T10:03:15.1486735+08:00</Time> 193: </SmartFile> 194: <SmartFile> 195: <FileName>Microsoft.Data.ConnectionUI.Dialog.dll</FileName> 196: <Version>8.0.50727.42 (RTM.050727-4200)</Version> 197: <Time>2011-04-19T14:03:23.948859+08:00</Time> 198: </SmartFile> 199: <SmartFile> 200: <FileName>Microsoft.Data.ConnectionUI.dll</FileName> 201: <Version>8.0.50727.42 (RTM.050727-4200)</Version> 202: <Time>2011-04-19T14:03:23.9863596+08:00</Time> 203: </SmartFile> 204: <SmartFile> 205: <FileName>NetronGraphLib.dll</FileName> 206: <Version>2.2.3328.30433</Version> 207: <Time>2009-02-10T16:54:28.046875+08:00</Time> 208: </SmartFile> 209: <SmartFile> 210: <FileName>RdlEngine.dll</FileName> 211: <Version>3.9.7.0</Version> 212: <Time>2011-05-16T10:57:32.5537424+08:00</Time> 213: </SmartFile> 214: <SmartFile> 215: <FileName>RdlViewer.dll</FileName> 216: <Version>3.9.6.0</Version> 217: <Time>2011-05-16T10:57:34.8538739+08:00</Time> 218: </SmartFile> 219: <SmartFile> 220: <FileName>ReportDesigner.dll</FileName> 221: <Version>3.9.7.0</Version> 222: <Time>2011-05-16T10:57:48.085178+08:00</Time> 223: </SmartFile> 224: <SmartFile> 225: <FileName>ReportDesigner.Start.exe</FileName> 226: <Version>1.0.0.0</Version> 227: <Time>2011-05-16T10:57:50.9183227+08:00</Time> 228: </SmartFile> 229: </Files> 230: </SmartConfig> 本文件由智能升级配置程序EAS.SmartUpdateConfig.exe产生,我们打开XClient\Files目录下的EAS.SmartUpdateConfig.exe程序集: 点击文件右边的浏览按钮选择配置文件保存位置(Xclient\config\smartupdate.xml),升级文件目录选择Xclient\Files,点击“扫描文件夹”,然后“保存”完成升级配置信息的生成。 第六步:运行SAAS客户端 在“药店系统-发布版本”目录的Winclient目录之中,包含了药品系统SAAS运行的客户端程序集及配置信息,在运行之前,需要修改一下配置文件中的两个服务URL,一个是用于控制升级的服务、配置信息存放于update.inf文件之中: 1: # AgileEAS.Net 平台升级控制文件。 2: 3: [config] 4: 5: allow = 1 6: url = net.tcp://localhost:6688/EAS.SmartUpdateService 其中 allow为是否开启升级,1开启,0不开启,默认为1,url为升级服务位置,修改为net.tcp://localhost:6688/EAS.SmartUpdateService。 另一个是程序的SOA分布式通信服务url,这个通过EAS.WinClient.exe.config文件进行修改: 1: <?xml version="1.0" encoding="utf-8"?> 2: <configuration> 3: <configSections> 4: <section name="eas" type="EAS.ConfigHandler,EAS.MicroKernel" /> 5: </configSections> 6: <eas> 7: <configurations> <item name="WorkstationUser" value="Administrator;0001;0003" /> 8: <item name="LastUser" value="0003" /> 9: <item name="SmartLogin" value="true" /> 10: <item name="Startup" value="" /> 11: <item name="SystemStyle" value="MdiStyle" /> 12: <item name="NavigationStyle" value="TreeStyle" /> 13: <item name="NavigationExpand" value="true" /> 14: <item name="Desktop" value="Enable" /> 15: <item name="MultiInstance" value="Enable" /> 16: <item name="EnableSkin" value="false" /> 17: <item name="SkinStyle" value="MacOS" /> 18: </configurations> 19: <objects> 20: <!--分布式通信组件。--> 21: <object name="ServiceBridger" assembly="EAS.Distributed.Client" type="EAS.Distributed.ServiceBridger" LifestyleType="Singleton"> 22: <property name="ServiceName" type="string" value="RMIService" /> 23: </object> 24: <object name="DataAccessor" assembly="EAS.Distributed.Client" type="EAS.Distributed.DataAccessor" LifestyleType="Singleton"> 25: <property name="ServiceBridger" type="object" value="ServiceBridger" /> 26: </object> 27: <object name="OrmAccessor" assembly="EAS.Distributed.Client" type="EAS.Distributed.OrmAccessor" LifestyleType="Singleton"> 28: <property name="ServiceBridger" type="object" value="ServiceBridger" /> 29: <property name="DataAccessor" type="object" value="DataAccessor" /> 30: </object> 31: <!--日志管理--> 32: <object name="Logger" assembly="EAS.MicroKernel" type="EAS.Services.TextLogger" LifestyleType="Singleton" /> 33: <!--资源平台所需组件--> 34: <object name="EAS.Explorer.DAL" assembly="EAS.Explorer.DAL.SQLServer" type="EAS.Explorer.DAL.SQLServer.DALManager" LifestyleType="Singleton" /> 35: <object name="EAS.Explorer.Resource" assembly="DrugShop.Res" type="DrugShop.Res.Resources" LifestyleType="Singleton" /> 36: </objects> 37: <services> 38: <!--<service name="RMIService" service-type="WebService" singleton="true" url="http://www.agilelab.cn/xservice/rmiservice.asmx" />--> 39: <service name="RMIService" service-type="WcfService" singleton="true" url="net.tcp://localhost:6688/EAS.RMIService" /> 40: </services> 41: </eas> 42: </configuration> 其中:<service name="RMIService" service-type="WcfService" singleton="true" url="net.tcp://localhost:6688/EAS.RMIService" />即为服务地址。 完成以上修改之后,即可运行客户端程序,使用0001,0002,0003登录,密码都为空,管理员密码为“sa”。 三、平台发布下载 有关于平台最新版本的最新发布版本的程序集、类库手册、相关资料,请大家从AgileEAS.NET平台的官网http://www.smarteas.net/进行下载,官网设有独立的下载页面,从这里下载:官网下载页面。 四、如何联系 如果您在使用AgileEAS.NET开发平台中有什么问题,请使用如下几种联系方式或者沟通方式。 1、官方网站: AgileEAS.NET平台:http://www.smarteas.net/ 敏捷软件工程实验室:http://www.agilelab.cn/ 2、AgileEAS.NET平台交流群: AgileEAS.NET平台交流群:120661978(超级群)[新建] AgileEAS.NET平台交流群:125643764(高级群)[新建] AgileEAS.NET平台交流群:147168308(高级群)[新建] 3、系统架构交流群: 系统架构交流群:9105332(高级群)(已满) 系统架构交流群1:124825459(高级群)(已满) 系统架构交流群2:49124441(高级群)(已满) 系统架构交流群3:47025564(高级群)(已满) 链接 AgileEAS.NET平台开发指南-文章索引 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET平台开发Step By Step系列-药店系统-索引
一、药店系统内容说明 在前些时间,我们发布了一个基于AgileEAS.NET平台的SAAS结构的案例-AgileEAS.NET平台开发实例-药店系统-快速的SAAS开发体验,在文章中同时向大家提供了基于SAAS部署安全的演示客户端下载,也向大家提供了包含全部源代码下载。 AgileEAS.NET平台是一套应用系统快速开发平台,用于帮助中小软件开发商快速构建自己的企业信息管理类开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的,AgileEAS.NET应用开发平台包含基础类库、资源管理平台、运行容器、开发辅助工具等四大部分,资源管理平台为敏捷并行开发提供了设计、实现、测试等开发过程的并行。 药店系统案例以及案例所提供的SAAS部署技术是依赖于AgileEAS.NET平台提供的,这个案例是一个规格比较小,但却很有代表性的一个案例,涵盖了在企业应用系统开发中的一系列技术、比如Orm技术、平台加插入技术、分布式通信技术/WCF/WebService、SAAS技术、SOA思想等。 以下是药店系统的源代码目录结构,我给大家简要介绍一下: AgileEAS.NET平台-文档 这里面是AgileEAS.NET平台所提供的开发参考文档,包含类库参考手册、平台技术说明书 、平台开发指南、。平台自身的数据库结构设计书、平台辅助工具的使用说明书等。 AgileEAS.NET平台-AppServer 这里面是AgileEAS.NET平台分布式通信Windows服务程序,用于提供应用的分布式运行能力,即SAAS/SOA架构的服务端技术。 药店系统-源码-VS2010 这里面是药店系统案例的所有源代码,开发人员可以在还原药店系统-数据库备份之后修改、编译运行这部分源代码,这是一个独立、完整的案例。 药店系统-文档 这里面是药店系统案例的相关文档,包含案例的数据库模型定义、需求文档和数据库定义文档。 药店系统-完整开发教程PDF说明书系统 这里面是callhot写的如何使用AgileEAS.NET平台进行开发药店案例的系列教程。 药店系统-发布版本 这里面包含了一个可以可以直接部署为分布式结构的服务端和客户端的最终编译版本,AppServer为服务器部署部分,WinClient目录中提供了分布式/WCF通信的客户端程序,同AgileEAS.NET平台开发实例-药店系统-快速的SAAS开发体验一文中提供的下载一样。 二、案例源码下载 请大家从这里下载,也可以去AgileEAS.NET官方网站进行下载:官网下载页面。 三、如何使用案例源码 首先还原数据库,可以使用执行脚本、恢复数据库、附加数据库的方式进行处理,有关于如何使用备份还原技术还原数据库请参考“AgileEAS数据库还原及相关设计说明”文档。 对项目进行编译,可以选择使用VS2010打开药店系统-源码-VS2010中的DrugShop解决方案进行编译,也可以使用build-all.bat这个批处理脚本进行编译,使用前请先修改脚本中的相对路径 setlocal REM 设置路径 set dic=E:\AgileEAS.NET\药店系统-DrugShop REM 编译解决方案 C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe %dic%\药店系统-源′码?-VS2010\DrugShop.sln /t:Rebuild /p:Configuration=Release REM 复制文件到发布版本/应用服务器 copy %dic%\药店系统-源码-VS2010\Publish\DrugShop.DAL.dll %dic%\药店系统-发布版本\AppServer\Bin /y copy %dic%\药店系统-源码-VS2010\Publish\DrugShop.BLL.dll %dic%\药店系统-发布版本\AppServer\Bin /y REM 复制文件到发布版本/升级 copy %dic%\药店系统-源码-VS2010\Publish\DrugShop.*.dll %dic%\药店系统-发布版本\AppServer\xClient\Files /y REM 复制文件到发布版本/客户端 copy %dic%\药店系统-源码-VS2010\Publish\DrugShop.*.dll %dic%\药店系统-发布版本\WinClient /y pause 修改相关配置文件中的数据库连接参数,即可运行案例,系统初始管理员账户为“Administrator”、密码为“sa”。 四、平台发布下载 有关于平台最新版本的最新发布版本的程序集、类库手册、相关资料,请大家从AgileEAS.NET平台的官网http://www.smarteas.net/进行下载,官网设有独立的下载页面,从这里下载:官网下载页面。 五、如何联系 如果您在使用AgileEAS.NET开发平台中有什么问题,请使用如下几种联系方式或者沟通方式。 1、官方网站: AgileEAS.NET平台:http://www.smarteas.net/ 敏捷软件工程实验室:http://www.agilelab.cn/ 2、AgileEAS.NET平台交流群: AgileEAS.NET平台交流群:120661978(超级群)[新建] AgileEAS.NET平台交流群:125643764(高级群)[新建] AgileEAS.NET平台交流群:147168308(高级群)[新建] 3、系统架构交流群: 系统架构交流群:9105332(高级群)(已满) 系统架构交流群1:124825459(高级群)(已满) 系统架构交流群2:49124441(高级群)(已满) 系统架构交流群3:47025564(高级群)(已满) 链接 AgileEAS.NET平台开发指南-文章索引 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET平台开发Step By Step系列-药店系统-索引
在前几天的DotNET企业架构应用实践-企业管理软件架构(计算)的历史与发展(上)一文中,介绍了在企业管理软件架构发布中的主机-终端结构、以及客户机-服务器结构、浏览器-服务器结构,本文今天向大家介绍有关于分布式计算及SOA架构方面的知识。 广义分布式系统 分布式系统(distributed system)是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。内聚性是指每一个数据库分布节点高度自治,有本地的数据库管理系统。透明性是指每一个数据库分布节点对用户的应用来说都是透明的,看不出是本地还是远程。在分布式数据库系统中,用户感觉不到数据是分布的,即用户不须知道关系是否分割、有无复本、数据存于哪个站点以及事务在哪个站点上执行等。 在一个分布式系统中,一组独立的计算机展现给用户的是一个统一的整体,就好像是一个系统似的。系统拥有多种通用的物理和逻辑资源,可以动态的分配任务,分散的物理和逻辑资源通过计算机网络实现信息交换。系统中存在一个以全局的方式管理计算机资源的分布式操作系统。通常,对用户来说,分布式系统只有一个模型或范型。在操作系统之上有一层软件中间件(middleware)负责实现这个模型。一个著名的分布式系统的例子是万维网(World Wide Web),在万维网中,所有的一切看起来就好像是一个文档(Web 页面)一样。 以上内容是百度百科对分布式系统的定义,从理论的角度来讲,目前极大多数据企业管理应用都是属于分布式系统这一范畴,C/S、B/S是分布式结构、C/A/S、B/A/S也是分布式结构、智能客户端更是这种结构,分布式系统的本质是在网络条件下的协同作战。 狭义分布式系统 目前,在业界都不把C/S应用和B/S做为分布式应用,而之前文章中介绍的C/A/S、B/A/S结构我们可以认为是一个分布式体系结构,因为广义的分布式系统太过于宽泛,狭义的分布式体系如下图: 即物理上三层/多层(Tier)、逻辑上也是三层/多层结构(Layer),很多程序员都在喊,要搞三层架构的应用,但对于Tier和Layer两个概念还是不能混淆的。 三层/多层(Tier)技术 三层/多层(Tier)是一种物理部署结构,其与一系列的分布式通信技术分不开,常用的分布式通信技术如下: DCOM DCOM全称为分布式组件对象模型,是微软基于其自身的COM技术的分布式扩展,它支持不同的两台机器上的组件间的通信,而且不论它们是运行在局域网、广域网、还是Internet上。 DOCM提供了一系列的概念和程序接口,利用这个接口,客户端程序对象能够请求来自网络中另一台计算机上的服务器COM对象。COM提供了一套允许同一台计算机上的客户端和服务器之间进行通信的接口。 DCOM是早期的分布式通信技术,目前还有大量的应用运行于DCOM技术之上。 .NET Remoting 可以说Remoting就是DCOM的一种升级,它改善了很多功能,并极好的融合到.Net平台下,用于在.NET开发中代替DCOM技术,并且和DCOM技术相比,其更加灵活和方便。 .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架,而其技术本质是对象的跨越进程边界,具体的说,就是对象的代理技术,在目前企业管理应用系统之中,.NET Remoting应用的非常广泛。 Web Service 如果说DOCM和.NET Remoting都是微软的特有技术的话,那么Web Service技术就是一种标准,但是写到这,我无法确切的给出一个Web Service的定义,只好摘抄百科中的一段自认为还算严谨定义: Web services是建立可互操作的分布式应用程序的新平台。作为一个Windows程序员,你可能已经用COM或DCOM建立过基于组件的分布式应用程序。COM是一个非常好的组件技术,但是我们也很容易举出COM并不能满足要求的情况。 Web service平台是一套标准,它定义了应用程序如何在Web上实现互操作性。你可以用任何你喜欢的语言,在任何你喜欢的平台上写Web service ,只要我们可以通过Web service标准对这些服务进行查询和访问。 Web Service及其所使用的通信协议SOAP已经是国际标准,基于这些标准,不管是windows还是UNIX,也管你使用何种编程语言,都可以通过这么一个标准构建和使用WebService。 CORBA CORBA(Common Object Request Broker Architecture公共对象请求代理体系结构)是由OMG组织制订的一种标准的面向对象应用程序体系规范。或者说 CORBA体系结构是对象管理组织(OMG)为解决分布式处理环境(DCE)中,硬件和软件系统的互连而提出的一种解决方案。 通信技术分类 前面介绍了几种分布式通信技术,其规纳起来无外忽两种: 远程过程调用 这中技术也可以理解为对象代理技术,或者说远程过程调用也是对象代理技术的实现思路,从这种看法来分类,DCOM、.NET Remoting和COBRA都属性这一类,其本质是在客户端请求远程执行某个过程或者方法,微软的RPC或者JAVA RMI。 消息通信 通信双方都尊守某一个协议标准进行通信,各通信双方对消息进行处,比如Web Service 采用SOAP-XML做为标准的通信消息,服务提供者和调用者自行处理消息中的业务请求。 相关链接 DotNET企业架构应用实践-系列目录 AgileEAS.NET平台开发Step By Step系列-药店系统-索引 AgileEAS.NET应用开发平台介绍-文章索引 QQ群:125643764,120661978
一、AgileEAS.NET应用开发简介 在4月份,callhot写过一系列的有关于AgileEAS.NET平台的开发应用的系列AgileEAS.NET平台开发Step By Step系列-药店系统-索引,他通过一个接近于实际应用的案例,从头到尾的向大家展示了AgileEAS.NET平台在企业信息系统开发中的应用及其应用开发的过程。 AgileEAS.NET平台是一套应用系统快速开发平台,用于帮助中小软件开发商快速构建自己的企业信息管理类开发团队,以达到节省开发成本、缩短开发时间,快速适应市场变化的目的,AgileEAS.NET应用开发平台包含基础类库、资源管理平台、运行容器、开发辅助工具等四大部分,资源管理平台为敏捷并行开发提供了设计、实现、测试等开发过程的并行。 AgileEAS.NET平台基于软件过程改进以及构件化快速开发两方面达到这方面的目标,在软件过程改进实践方面,提出了独有的“敏捷并行开发方法”开发方法,其目的是在软件的管理之中提出符合国内中小软件企业实际情况并且可操作的软件工程实践、软件过程改进思想、及相配套的项目管理系统。 在快速开发方面,AgileEAS.NET平台平台提供了企业应用开发所需的诸如ORM、IOC、分布式通信、插件与平台基础结构以及一系统的快速生成工具,涵盖开发过程中的设计、编码、集成、部署、运维等各个环节。 在callhot的AgileEAS.NET平台开发Step By Step系列-药店系统的系统之中,他详细的向大家展示了AgileEAS.NET平台在企业信息系统中提供的强大支持,在短短的一个月时间之向,向大家贡献了一个完整的案例及配套的几十篇渐进式教程,我相信大家通过他的教程,都能应用AgileEAS.NET平台中小型企业应用。 二、药店系统的SAAS部署 Callhot接手了新的工作,我在他留下的代码的基础之上,采用了最新的AgileEAS.NET平台进行了一个重构和裁剪,并且通过互联网以SAAS结构向大家发布了这个应用,其总体结构如下。 数据库和分布式应用层我部署在我的互联网服务器上,客户端我将提供一个msi包给大家下载,客户端和应用服务器可以通过webservice、WCF(http/TCP)进行数据通信,最终运行界面如下: 三、客户端下载及使用说明 客户软编译版本我打开了rar压缩包,请大家通过这里下载,下载解压缩后运行EAS.WinClient.exe文件。 大家可以使用0001(采购员),0002(销售员),0003(店长)三个账号登录药店系统,所有密码均为空,三个账户操作权限不同,请大家不要修改密码。 在下载包中的EAS.Winclient.exe.config文件之中记录应用程序服务器的通信设置。 <services> <service name="RMIService" service-type="WebService" singleton="true" url="http://www.agilelab.cn/xservice/rmiservice.asmx" /> <!--<service name="RMIService" service-type="WcfService" singleton="true" url="net.tcp://202.100.84.179:6688/EAS.RMIService" />--> </services> 系统默认使用WebService通信,连接至http://www.agilelab.cn/xservice/rmiservice.asmx,我在http://www.agileleab.cn/网站以iis宿住部署了webservice方式部署了通信服务,业务层寄宿在iis之中运行。 使用者也可以替换为wcf/tcp通信,连接至net.tcp://202.100.84.179:6688/EAS.RMIService,我在202.100.84.179部署了一套独立的基于wcf/tcp通信的应用服务程序。 友情提示一下,webservice通信较慢,特别是在登录界面之上,点了登录可能要等一会,因为使用的是SericeLocator动态调用技术,涉及编译webservice的代理类,请大家理解。 四、关于自动升级 在AgileEAS.NET平台本次重构过程之中,废弃了原有的基于插件的静默升级形式,替换了比较通过的独立升级程序,升级参数通过客户端目录中的update.ini文件升级。 # AgileEAS.Net 平台升级控制文件 [config] allow = 1 url = http://www.agilelab.cn/xservice/smartupdateservice.asmx #url = net.tcp://202.100.84.179:6688/EAS.SmartUpdateService 升级技术同样也可以采用ws技术也可采用wcf技术,目前,为了避免多点升级维护的麻烦,只提供于ws的升级,升级服务地址http://www.agilelab.cn/xservice/smartupdateservice.asmx。 五、案例源代码 本案例源代码结构重构之后更加合理,代码结构如下: DrugShop.DAL为系统的数据访问层(充血模型),DrugShop.BLL为系统的业务层/服务层,DrugShop.WinUI为系统以WinForm为表现模式的UI层,DrugShop.Res为系统的可替换资源,包括自定义的登录、关于窗口、banner条和起始页模块,DrugShop.AssStart为开发过程中的平台插件容器调试环境的启动程序。 药店系统-案例的源代码、文档、数据库备份、最后发布都打进一个独立的Rar包中,其结构如下: 请大家从这里下载。 六、平台其他下载 有关于平台最新版本的最新发布版本的程序集、类库手册、相关资料,请大家从AgileEAS.NET平台的官网http://www.smarteas.net/进行下载,官网设有独立的下载页面,从这里下载:官网下载。 CallHot 写过一个系列的基于AgileEAS.NET平台的开发案例,请大家通过AgileEAS.NET平台开发Step By Step系列-药店系统-索引及AgileEAS.NET敏捷开发平台及案例下载(持续更新)-索引、AgileEAS.NET平台开发实例-药店系统-视频教程系列-索引一系列文章进行下载。 七、如何联系 如果您在使用AgileEAS.NET开发平台中有什么问题,请使用如下几种联系方式或者沟通方式。 1、官方网站: AgileEAS.NET平台:http://www.smarteas.net/ 敏捷软件工程实验室:http://www.agilelab.cn/ 2、AgileEAS.NET平台交流群: AgileEAS.NET平台交流群:120661978(超级群)[新建] AgileEAS.NET平台交流群:125643764(高级群)[新建] AgileEAS.NET平台交流群:147168308(高级群)[新建] 3、系统架构交流群: 系统架构交流群:9105332(高级群)(已满) 系统架构交流群1:124825459(高级群)(已满) 系统架构交流群2:49124441(高级群)(已满) 系统架构交流群3:47025564(高级群)(已满) 链接 AgileEAS.NET平台开发指南-文章索引 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET平台开发Step By Step系列-药店系统-索引
2010年总结 这时间真是好东西,在那闲的时候,在你无所事事的时候,它总是那么的缓慢以至于白天等不到晚上、晚上等不到白天,却在你最需要的时候,在你忙的时间,它总是那么的转瞬即逝,多少有些让人伤怀。 2010稀里糊涂的就过去了,想起2009、2010的某些小事与细节,历历在目,感觉一切都像是在昨天发生,时间不因你意愿而停下来或者缓慢起来,过去的总是要过去,新的时刻总是要来到,而不管你是否愿意接受。 简单的总结一下自己过去的一年的表现吧,套用一句简单的话来说:前天年消磨时光,后半年磨消时光,脑子中记忆7、8月份还偶尔在游戏中,此后就忙碌的不知道东南西北了,或许这也是一种生活吧,2010最成功的就是把AgileEAS.NET平台的一些东西介绍给大家,与大家共同分享与共同进步。 最近一个月以来,手头事实在太多,忙不过来,以至于一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列都没有写完就搁置下来了,在此对关心AgileEAS.NET平台的各们朋友们说声抱歉,明后我会和我的团队为大家准备一些更完整的教学案例。 在AgileEAS.NET平台方面,因为AgileEAS.NET平台从其诞生的第一天就是为实用而设计的,虽然其有诸多的缺陷,但其经历6年多的发展也是有目共睹的,在各们新老合作者的支持下越来越会完善和符合中小软件企业的现实需求。在此我感谢一直支持AgileEAS.NET平台的客户、合作伙伴和各位关于AgileEAS.NET平台的朋友。 再说AgileEAS.NET平台 在我博客中至少有70多篇文章关于AgileEAS.NET平台的,不过,就依目前文章所涉及的内容来看,所看到的内容也只是全部方案中的三分之一其多,那么完整的AgileEAS.NET平台到底是神马东西呢,都保护那些神马呢,AgileEAS.NET平台到底要达到什么目标呢,下面我简单的给大家说一下吧。 事情的起因还得从2004年说起吧,在2004年秋之前,我是使用VB开发医疗行业应用的,在工作中遇到很多的问题,开发技术方面的、开发组织中的,面对现实存在的问题去思考、去读相关的书籍,分布式体系的、并行计算方面的、软件工程方面的、软件过程改进方面的,其最根本的一个问题,那就是如何更有效的解决软件生产管理中的问题,更有效的提高软件的有效生产效率,期间也通过COM/COM+做过一些这方面的尝试。 在我博客中,还有一篇关于使用vb+asp实现的被我称之为ACWS的简单的分布式通信框架的东西,文章链接:ACWS Framework 简介。 2004处秋到了一家做农产品市场信息化的企业,使用.NET进行开发,接触了DotNET,学习了C#语言,同时也一步一步的用DotNET中的某些特点印证自己的某些想法,在当时我和我另一个朋友王胜强和当时的甘房网合作搞房地产网站的客户端软件,期间客户扔给我一张邦用PM2软件,我安装后仔细的学习了一下,发现其采用的是类似于我现在的这种插件结构,同时,我们的技术部领导刘平来也写出了一套插件结构的称之为“Information.Kernel”的一套Framework,我就在边学习边参考帮邦用PM2组织体系和“Information.Kernel”的数据库设计的基础上搞出了最基本的AgileEAS.NET平台第一版本,称之为ISDP(信息系统开发平台),最早的系统原型图如下: 图都是从邦用PM2上截下来的,不知道邦用是不是会找我的麻烦,这两天还翻出这个最老的原型,在这个原型之上使用Linq to EAS.NET ORM写出了HIS系统与甘肃农合接口的数据导出程序。 AgileEAS.NET平台发展到现在有点剑走偏锋的意思,最早的时候我的关注点是如何能有效的提高软件企业的有效生产效率,基于这个目标,我的关注点是软件过程改进和软件工程管理,即开始的关注点管理大于技术,2004年早先读过林锐的《软件工程思想》并了解到了这么一个牛人,并时刻关注其动态,2004林锐开始搞他的项目管理产品,开始的产品好名字应该是叫“基于Web的集成化项目管理系统Future ”,我电脑现在还保留期3.2版本的安装,最早的目标其实就是学习他的思想和产品,做一套更加轻便的项目管理系统。 然后事情的发展总不是那样的顺利,6年过去了,项目管理软件没搞来,一直在想搞,一直在策划,一直没有做出来,倒是做出来一套以.NET构件/组件技术来实现这种商品目的基础环境,或者说是基础中间件,严格的说是一套中间件产品,而不是什么应用开发平台。 那么完整的AgileEAS.NET中间件倒底包含那些东西呢,或者说,在我心中,这一整套解决方案都包含那些东西呢,我搞个简单的图来给大家介绍吧: 在这一整完整的中小企业软件开发解决方案之中,包含三大部分:敏捷并行开发实践、AgileEAS.NET和AgilePM.NET这三部分,当然,这三部分除了敏捷并行方法和另外两块有明显的界线,AgilEAS.NET和AgilePM.NET没有明显的界限,可以理解为AgileEAS.NET其上的一个应用,或者说一组用于软件开发管理的工作集,由AgilEAS.NET集成和粘合。 那么这三部分其职责各是什么呢: 第一、 敏捷并行开发提供一种朴素的软件工程实践,基于系统分析、设计对插件的分解,开发过程并且开发,部署过程组装集成的一种低成本、适合中小企业的软件开发模型,即完成一个系统的分解(解构)--->并行开发---->组合(结构)的一个过程,当然了,近几年也仔细的学习和吸引了敏捷开发方法特别是SCRUM中的某些优秀的思想,慢慢的和原有的思想体系融合在一起。 第二、 AgileEAS.NET平台以平台加插件技术实现了分解(解构)--->并行开发---->组合(结构)的一个完整流程并对其生命周期进行管理,同时,AgileEAS.NET平台也提供了大量的基础组件与快速开发技术及其相关的支持产品,如IOC、AOP、ORM/Linq、报表、SL、数据对象/模型设计工作、界面生成工具、分布式通信框架等等以提高应用开发效率。 第三、 AgilePM.NET项目管理工具提供对敏捷并行开发这一软件工程实践的工具化支持,让公司领导、各层负责人、客户、开发人员都知其项目之所以然、也知其工作之所以然。 这三部分的东西彼此联系、相互依赖又相互促进,从而形成一个完整的中小软件企业开发、管理解决之道,这是我的事业、也是我的团队的事业,也应该大家的共同事业。 在AgileEAS.NET平台发展过程之中,我们参考过或者说是学习过很多相关产品中优秀的东西,比如普元EOS中的某些理念、金蝶KIS中的某些元数据及其相关的一些处理机制、以及其他的诸元极致、UCML等相关产品,也大量的学习诸如Spring.NET、Castle相关的开源项目,这其中博客园带给我的帮助是最大的,我写出第一句C#代码即熟悉了博客园,也曾经在2005-2006年利于博客园修改版的.TEXT的基础上修改和搭建过博客系统,在此表示感谢! 关于行业 从理论上讲,AgileEAS.NET平台是可以应用于任何行业的,目前在医疗行业(医院信息系统/HIS、健康档案系统/EHR、新型农村合作医疗/NRCM、区域公共卫生平台)、房地产、农业、电子商务、电子政务、电力、铁路交通、ERP领域。 从我个人的经历来讲,我所从事的这9年近10年的经历之中80%的时间都在从事医疗行业,俗话说,靠山吃山,在今后很长的一个时间段中我的重点关注行业还是医疗行业,说起这事,还想起一档子事,在我从上家公司职称之后,我曾经打算放弃医疗行业,转而做企业信息化这块,原因主要是因为原先企业也是做医疗行业的,老板也算带我不薄,然后在今年秋我想通过了,不是我做这个行业就对不起他,我不去做,还有张三、还有李四去做,只要我们格守职业道德则行,并且我做的是行业业务领域咨询,再不是去直接做客户,从另一方面讲,放弃医疗行业,让我的那些行业经验从此就烂在我脑子中实在有些可惜,留着不用,分享出去别人或许就能少走很多的弯路。 在接下来的工作中,我还会加强我的团队在医疗行业的准备,包含新型的HIS系统、电子病历控件及电子病历系统、基于健康档案及基于健康档案的区域公共卫生平台的整合将会提供相应的解决方案。 当然了,这不意味着我和我的团队只将为医疗行业服务,我们还是希望更多的行业应用我们的AgilEAS.NET平台进行开发,我们也将会提供完整体系的技术咨询服务。 AgileEAS.NET发展方向 如何说AgileEAS.NET平台在以前的这些年关注于敏捷并行开发思想的实践并在.NET WinForm及WebForm方面的应用的话,那么2011年将会是AgileEAS.NET将会在Silverlight之上发力,我们将会基于Silverlight提供插件体系、数据通信、服务访问、报表打印等一系列的解决方案。 AgileEAS.NET现在版本提供了完整的ORM体系与其相配套的数据对象设计、代码生成、文档生成工具,最新版本集成对Linq的支持,我将在随后的文章中给大家展示,如何说现在版本在快速开发技术层对数据访问提供重点支持的话,那么2011年AgileEAS.NET将会在前层展示上为大家提供快速界面生成工具,帮助大家解决大早重复性劳动。 在2011年,AgileEAS.NET平台将会升级到.NET4.0并吸引4.0的新技术,当然基于.NET2.0版本也将继续支撑。 AgilePM.NET将在2011年实现并集成到这套解决方案之中,已经完成需要分析、初步决定采用Silverlight进行开发,到时将会给大家一个惊喜。 在AgileEAS.NET平台的技术支持与服务系统之中,我们将会在2011年中编写更为完善的SDK帮助文档、开发指导手册,同时将会提供基于实例项目的案例教学课程。 在医疗行业中,我们将会提供全新的电子病历编辑器,支持国家卫生部最新标准,XML导出和半结构化、支撑三级痕迹修改,同时,将会在AgileEAS.NET和电子病历之中融合电子证书的安全验证体系,同时在2011年我们将会和合作伙伴就移动医生站、移动护理站做出一个新的高度。 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划
回顾与说明 前面我们把“商品字典”、“商品入库”、“商品库存查询”、“商品入库查询”四个模块已经概括或者详细的演示了一个管理信息系统的典型应用场景,按照原来的打算,WinForm篇的例子系统中的几个模块就告一段落了。 由于好多朋友都问我,你的例子中大量使用ListView控件,很想知道是否可以支持DataGridView控件,所以我就有想到重新用DataGridView写一下“商品字典”模块。 本文内容 关于“商品字典”的实现及其业务应用场景请参见一步一步教你使用AgileEAS.NET基础类库进行应用开发-WinForm应用篇-实例一个模块(商品字典)一文。 今天本文的主要内容是AgileEAS.NET平台中的ORM对象与DataGridView的绑定,在AgileEAS.NET平台的ORM体系之中,有一个ITable接口,他继承了数据绑定接口IListSource,并且ITable的Rows属性为EntityCollection对象本身就是一个List<IEntity>,那么通过ITable.Rows也是可以实现数据绑定的。 本文的例子中,我只演示商品字典数据的绑定与修改,并且修改也使用了一个偷懒的方法,不是最优的实现,另外关于字典的删除和增加我也没有实现,有兴趣的朋友自己实现吧。 下面我们就来开始干活吧,第一件事,还是拖控件堆界面。 制做界面 首先,我们需要在UI项目中增加一个WinForm窗体ProductDictForm拖动控件达到如下效果: 在这里,我们需要注意的是需要向界面放一个dataGridView,并且设置一下他的列,当然了大家也可以直接使用BindingSource绑定到Product.DAL.Interface.IProduct之上。 编写绑定代码 下面我们来写“查询”、“打印”两个按钮的事件处理代码: 1: void LoadDictList() 2: { 3: currentDict = DALHelper.DALManager.CreateProduct(); 4: 5: dictList = DALHelper.DALManager.CreateProductList(); 6: dictList.GetProductList(this.tbSearch.Text); 7: 8: //两种方式都支持 9: this.dataGridView1.DataSource = dictList; 10: //this.dataGridView1.DataSource = dictList.Rows; 11: } 12: 13: private void btnSearch_Click(object sender, EventArgs e) 14: { 15: this.LoadDictList(); 16: } 17: 18: private void btnPrint_Click(object sender, EventArgs e) 19: { 20: if (dictList == null) 21: { 22: MessageBox.Show("没有需要打印的数据!", "提?示?", MessageBoxButtons.OK, MessageBoxIcon.Information); 23: return; 24: } 25: 26: if (this.printForm == null) 27: this.printForm = new PrintViewDialog(); 28: 29: // 30: System.IO.TextReader textReader = null; 31: try 32: { 33: string fileName = Path.Combine(Application.StartupPath, "Reports\\商品字典.rdl"); 34: textReader = new System.IO.StreamReader(fileName); 35: this.printForm.SourceRdl = textReader.ReadToEnd(); 36: } 37: finally 38: { 39: if (textReader != null) 40: textReader.Close(); 41: } 42: 43: this.printForm.DataObject = dictList; 44: this.printForm.PrintPreview(); 45: } 46: 接下来看看编辑处理代码: 1: private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) 2: { 3: if (this.dataGridView1.CurrentRow != null) 4: { 5: IProduct product = this.dataGridView1.CurrentRow.DataBoundItem as IProduct; 6: currentDict.Code = product.Code; 7: } 8: } 9: 10: private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) 11: { 12: IProduct product = this.dataGridView1.CurrentRow.DataBoundItem as IProduct; 13: 14: if (product.Code == currentDict.Code) 15: product.Update(); 16: else 17: { 18: product.Update(); 19: product.Idn = product.GetMaxNewIdn(); 20: currentDict.Delete(); 21: product.Insert(); 22: } 23: } 运行结果 编译并运行程序,我们看一下运行效果: 打印预览: 导出报表,选择导出Excel格式: 我写完这篇post,WinForm篇的例程即将就结束了,接下来,我会在WinForm篇之中安排几篇文章讲例程的部署问题,说是部署问题,其他也不是部署问题,而是例子是以何种方式运行,是直接连接数据库,还是通过服务桥接器连接到远程服务器进行业务处理。 本文我就说到这里,对AgileEAS.NET平台感兴趣的朋友呢,可以下载了完整代码之后自己看看,有问题请及时的和我联系。 有关本例所涉及的数据表结构请参考基于AgileEAS.NET平台基础类库进行应用开发-总体说明及数据定义一文,有关数据对象模型定义文件、文档、DDL脚本请下载:http://files.cnblogs.com/eastjade/demo.db.doc.sql.rar,本例完整代码下载:Product.Demo.rar。 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET官方网站 敏捷软件工程实验室 QQ群:116773358
回顾与说明 前面我们把“商品字典”、“商品入库”、“商品库存查询”三个模块已经概括或者详细的演示完了,这些模块涉及到简单数据的增、删、修,也涉及到复杂业务处理的事务、业务层提取,以及MIS系统中非常常见的查询、报表打印技术和基础字典的缓存查询技术。 本文内容 今天我们将以另外一种技术实现另一个模块“商品入库查询”,将采用何种技术呢,其实也是一个很简单的技术,在构建UI应用中使用报表技术,即我们把打印预览的报表技术使用在业务查询应用的主体UI之中,如下图所示一样的效果: 制做界面 首先,我们需要在UI项目中增加一个WinForm窗体ProductInQueryForm拖动控件达到如下效果: 在这里,我们需要注意的是需要向界面放一个报表预览控件,报表预览控件由EAS.Report.Controls程序集承载,类型EAS.Report.Controls.RDLReportViewer,打印预览控件工具条显示位置由属性ToolBoxDockStyle决定,我们设置为DockStyle.Bottom。 处理查询 接下来我们编写查询相关的代码,先在数据层接口项目中的IProductInList的分部类定义IProductInList.cs文件中增加如下代码: 1: /// <summary> 2: /// 表接口 IProductInList(产品入库)。 3: /// </summary> 4: public partial interface IProductInList 5: { 6: /// <summary> 7: /// 根据入库票据号查询入库明细。 8: /// </summary> 9: /// <param name="billCode">入库票据号。</param> 10: void GetProductInList(string billCode); 11: 12: /// <summary> 13: /// 根据入库时间及拼音简码查询入库明细。 14: /// </summary> 15: /// <param name="startTime">开始时间。</param> 16: /// <param name="endTime">结束时间。</param> 17: /// <param name="pyCode">拼音简码。</param> 18: void GetProductInList(DateTime startTime,DateTime endTime,string pyCode); 19: } 同样,我们需要在数据层实现项目中实现这个方法: 1: public void GetProductInList(DateTime startTime, DateTime endTime, string pyCode) 2: { 3: Condition condition = this.CreateCondition(); 4: 5: if (!startTime.Equals(endTime)) 6: { 7: List<DateTime> times = new List<DateTime>(2); 8: times.Add(startTime); 9: times.Add(endTime); 10: 11: condition.AddElement("InTime", times, ElementType.BetWeen); 12: } 13: 14: if (pyCode.Length > 0) 15: condition.AddElement("SqlText", "CODE in (select CODE from dbo.PRODUCT where PYCODE like '" + pyCode + "%')", ElementType.SqlCondition); 16: 17: this.Query(condition); 18: } 大家在这地方仔细看一下,因为在商品库存表中没有定义产品的拼音简码,所以我就使用了一个字查询,并以SQL条件的形式写了出来,在实现应用中,应该在产品库存表中增加拼音简码字典,以方便查询。 制作报表 这一步在前面的文章中已经有过详细的介绍了,在这就简单的走过,打开报表设计器,选择对象报表,数据对象为Product.DAL.SQLServer.ProductInList,我们做出如下样式的报表: 需要注意的是,在这个报表中,我增加了一个分组,按单据号进行分组并显示分组统计,完成报表设计之后,保存在编译目标目录中的Reports文件夹中并取名为“商品入库查询报表.rdl”。 集成代码 接下来我们修改程序,把报表挂载进来,编写“查询”按钮的事件处理代码: 1: private void btnSearch_Click(object sender, EventArgs e) 2: { 3: //加载报表 4: 5: if (this.reportViewer.SourceRdl==null) 6: { 7: System.IO.TextReader textReader = null; 8: try 9: { 10: string fileName = Path.Combine(Application.StartupPath, "Reports\\商品入库查询报表.rdl"); 11: textReader = new System.IO.StreamReader(fileName); 12: this.reportViewer.SourceRdl = textReader.ReadToEnd(); 13: } 14: finally 15: { 16: if (textReader != null) 17: textReader.Close(); 18: } 19: } 20: 21: //处理数据 22: IProductInList table = DALHelper.DALManager.CreateProductInList(); 23: table.GetProductInList(this.dtpStartTime.Value,this.dtpEndTime.Value, this.tbSearch.Text); 24: this.reportViewer.DataObject = table; 25: } 运行结果 编译并运行程序,我们看一下运行效果: 打印预览: 我们把报表导出来,选择导出Excel格式: 这里我们需要注意的是:导出Excel格式只支持Excel2007格式,这个让我很纠结,我不喜欢装备庞大的office2007,2010更是用一个月就用不成了,挺郁闷的,Wps自带的表格软件打不开这个格式。 至此,“商品入库查询”模块的相关处理就此结束,接下来我将介绍“商品字典”的另一个实现,同时演示ORM对象与DataGridView的绑定技术,希望大家感兴趣,对AgileEAS.NET平台感兴趣的朋友呢,可以下载了完整代码之后自己看看,有问题请及时的和我联系。 有关本例所涉及的数据表结构请参考基于AgileEAS.NET平台基础类库进行应用开发-总体说明及数据定义一文,有关数据对象模型定义文件、文档、DDL脚本请下载:http://files.cnblogs.com/eastjade/demo.db.doc.sql.rar,本例完整代码下载:Product.Demo.rar。 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET官方网站 敏捷软件工程实验室 QQ群:116773358
回顾与说明 前面我就用了大量的篇幅我讲解了“商品入库”模块,在商品入库模块之中,我们介绍 了与之相关的管理信息系统开发中的一个共性场景,以及这个应用场景中所涉及的缓存、业务处理、票据打印等相关的技术。 可以说,在WinForm篇中的示例代码之中,最有价值的模块就是“商品入库”,在真实的MIS应用场景中,有至少60%的应用与“商品入库”类似。 本文的内容 我们通过“商品入库模块”完成了商品的库操作,系统会写入数据库商品入库明细和商品库存信息,那么这些信息如何查呢,我们得提供“库存信息查询”和“入库记录查询”两个模块。 本文将详细的介绍“库存信息查询”模块实现过程,“库存信息查询”要实现的功能为:根据用户的输入码(拼音简码)和查询选项(是否显示零库存记录)查询商品库存信息(库存表)并显示在界面上,操作员也可以选择把查询结果打印出来。 制做界面 首先,我们需要在UI项目中增加一个WinForm窗体StoreQueryForm拖动控件达到如下效果: 处理查询 接下来我们编写查询相关的代码,先在数据层接口项目中的IProductStoreList的分部类定义IProductStoreList.cs文件中增加如下代码: 1: /// <summary> 2: /// 表接口 IProductStoreList(产品库存)。 3: /// </summary> 4: public partial interface IProductStoreList 5: { 6: /// <summary> 7: /// 查询商品库存。 8: /// </summary> 9: /// <param name="pyCode">拼音码。</param> 10: /// <param name="showZero">是否显示零库存记录。</param> 11: void GetProductStoreList(string pyCode,bool showZero); 12: } 同样,我们需要在数据层实现项目中实现这个方法: 1: public void GetProductStoreList(string pyCode, bool showZero) 2: { 3: Condition condition = this.CreateCondition(); 4: 5: if (pyCode.Length > 0) 6: { 7: condition.AddElement("SqlText", "CODE in (select CODE from dbo.PRODUCT where PYCODE like '" + pyCode + "%')", ElementType.SqlCondition); 8: } 9: 10: if (!showZero) 11: condition.AddElement("NUMBER", 0, ElementType.GreaterThan); 12: 13: condition.AddOrderElement("CODE"); 14: condition.AddOrderElement("IDN", true); 15: this.Query(condition); 16: } 大家在这地方仔细看一下,因为在商品库存表中没有定义产品的拼音简码,所以我就使用了一个字查询,并以SQL条件的形式写了出来,在实现应用中,应该在产品库存表中增加拼音简码字典,以方便查询。 接下来我们写编写UI中的“查询”按钮的事件处理代码如下: 1: private void btnSearch_Click(object sender, EventArgs e) 2: { 3: IProductStoreList table = DALHelper.DALManager.CreateProductStoreList(); 4: table.GetProductStoreList(this.tbSearch.Text, this.cnZero.Checked); 5: 6: decimal sumMoney = decimal.Zero; 7: 8: try 9: { 10: this.Cursor = Cursors.WaitCursor; 11: this.lvInfo.Tag = table; 12: 13: this.lvInfo.BeginUpdate(); 14: this.lvInfo.Items.Clear(); 15: 16: foreach (IProductStore ps in table.Rows) 17: { 18: decimal money = ps.Price * ps.Number; 19: sumMoney += money; 20: ListViewItem item = new ListViewItem(new string[] { string.Empty, ps.Code, ps.Name, ps.Spec, ps.Unit, ps.Price.ToString("F2"), ps.Number.ToString(), money.ToString("F2") }, 0); 21: this.lvInfo.Items.Add(item); 22: } 23: 24: } 25: finally 26: { 27: this.lvInfo.EndUpdate(); 28: this.Cursor = Cursors.Default; 29: } 30: 31: this.lblTip.Text = "汇总:共有记录" + table.Rows.Count + "条,总金额" + sumMoney .ToString("F2")+ "元"; 32: } 到这一步,我们就完成了数据查询并且显示在界面上的需求,下一步完成打开导出。 处理打印 首先,我们需要制作报表,这一步在前面的文章中已经有过详细的介绍了,在这我就不介绍了,选择对象报表,数据对象为Product.DAL.SQLServer.ProductStoreList,我们做出如下样式的报表: 把制作好的报表保存在编译目标目录中的Reports文件夹中并取名为商品库存查询报.rdl。 接下来我们修改程序,把报表挂载进来,编写“打印预览”按钮的事件处理代码: 1: private void btnPrint_Click(object sender, EventArgs e) 2: { 3: if (this.lvInfo.Items.Count == 0) 4: { 5: MessageBox.Show("没有需要打印的数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); 6: return; 7: } 8: 9: if (this.printForm == null) 10: this.printForm = new RDLViewDialog(); 11: 12: // 13: System.IO.TextReader textReader = null; 14: try 15: { 16: string fileName = Path.Combine(Application.StartupPath, "Reports\\商品库存查询报表.rdl"); 17: textReader = new System.IO.StreamReader(fileName); 18: this.printForm.SourceRdl = textReader.ReadToEnd(); 19: } 20: finally 21: { 22: if (textReader != null) 23: textReader.Close(); 24: } 25: 26: this.printForm.DataObject = this.lvInfo.Tag; 27: this.printForm.PrintPreview(); 28: } 修改程序,控制打印 编译并运行程序,我们看一下运行效果: 打印预览: 至此,“商品库存查询”模块的相关处理就此结束,接下来我将介绍“入库信息查询”,这个模块我将介绍大家直接使用报表做为UI呈现主体,希望大家感兴趣,对AgileEAS.NET平台感兴趣的朋友呢,可以下载了完整代码之后自己看看,有问题请及时的和我联系。 有关本例所涉及的数据表结构请参考一文,有关数据对象模型定义文件、文档、DDL脚本请下载:,本例完整代码下载:。 链接 QQ群:116773358
回顾与说明 首先给大家说声抱歉,上一周忙了一些其他的事,博客也就差不多一周没有更新,让关注AgileEAS.NET平台的朋友们久等了,希望大家能继续关注AgileEAS.NET平台,关注AgileEAS.NET平台所采用的架构设计实践和AgileEAS.NET平台背后的一些软件工程实践思考。 前面我用了至少两篇直接的文章对“商品入库”模块进行了详细的说明,我想大家已经很清楚的知道商品入库处理的流程、技术特别以及特别查询的缓存查询技术。为什么我要在这么一个简单的模块费多少大的口舌呢? 因为,“商品入库”是一个在管理信息系统(MIS)之中非常典型的应用场景,在这个很小的应用场景之中,我们涉及到了字典信息查询、中间结果保存、事务处理以及马上要进行的“票据打印”,可以说基本是一个信息系统中在线事务处理或者数据采集应用的一个缩影,当我们能熟练的能使用AgileEAS.NET平台开发这样的应用的时候,那么MIS系统将在我们面前没有一些难度。 本文的内容 前面的文章,我已经把“商口入库”模块之中的字典查询以及其中使用的缓存技术、中间数据记录、业务的处理及事务等进行了详细的介绍,今天本文的重点是入库单(票据)打印业务。 那么这是一个什么场景呢,当我们点击“入库”按钮完成入库今年的保存之后,我们需要点击“打印”按钮完成入库票据的打印,或者当我们完成入库按钮之后完成入库之后即打印本次业务的业务票据,操作界面上有“直接输出打印机”的选项,如果选中则不显示打印预览对话框。 准备报表,以备调用 首先我们制做报表,打开报表设计器ReportDesigner.Start.exe,通过菜单“文件”-->“新建”-->“对象报表”,打开“新建数据对象报表”对话框,然后选择“数据对象”Tab页,点击“浏览”选择编译目标目录中的“Product.DAL.SQLServer.dll”,在类型下接列表之选择Product.DAL.SQLServer.ProductInList: 现在我们单击“确定”按钮,使用报表设计器调整报表格式,达到以下样式: 我们可以在报表设计器中预览一下,注意:因为是基于数据对象的报表不能连接数据库,所以数据都是随机生成的,用于模拟显示。 现在报表已经做好,我们把报表定义保存在编译目标目录的Report文件夹中,名称为“商品入库单据.rdl”。 修改程序,控制打印 报表已经制作好了,现在的任务就是在程序中加载报表,并且绑定要打印的数据,那么数据从那来呢,我们已经完成了商品的入库并且我们知道刚刚完成的入库单号,我们可以通过入库单号来查询入库表,从来得到指定入库单中的入库记录,要达到这样的需求,我们需要在DAL层接口项目Product.DAL.Interface中的IProductInList中增加一个方法: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 /// <summary> 2 /// 表接口 IProductInList(产品入库)。 3 /// </summary> 4 public partial interface IProductInList 5 { 6 /// <summary> 7 /// 根据入库票据号查询入库明细。 8 /// </summary> 9 /// <param name="billCode">入库票据号。</param>10 void GetProductInList(string billCode);11 } 同时需要在DAL层SQLService实现项目Product.DAL.SQLServer中的ProductInList类中实现这个方法: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 /// <summary> 2 /// 表对象 ProductInList(产品入库)。 3 /// </summary> 4 public partial class ProductInList:EAS.Data.ORM.Table, IProductInList 5 { 6 public void GetProductInList(string billCode) 7 { 8 Condition condition = this.CreateCondition(); 9 condition.AddElement("BILLCODE", billCode);10 this.Query(condition);11 }12 } 接下来我们来写“打印”按钮的事件处理代码,实现数据提取与报表打印: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 private void btnPrint_Click(object sender, EventArgs e) 2 { 3 IProductInList productInList = DALHelper.DALManager.CreateProductInList(); 4 productInList.GetProductInList(this.previouBillCode); 5 6 if (productInList.Rows.Count == 0) 7 { 8 MessageBox.Show("没有需要打印的数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); 9 return;10 }11 12 if (this.printForm == null)13 this.printForm = new RDLViewDialog();14 15 //16 System.IO.TextReader textReader = null;17 try18 {19 string fileName = Path.Combine(Application.StartupPath, "Reports\\商品入库单据.rdl");20 textReader = new System.IO.StreamReader(fileName);21 this.printForm.SourceRdl = textReader.ReadToEnd();22 }23 finally24 {25 if (textReader != null)26 textReader.Close();27 }28 29 this.printForm.DataObject = productInList;30 31 if (this.cbPrinter.Checked)32 this.printForm.Print(); //直接打印33 else34 this.printForm.PrintPreview(); //打印预览35 } 现在,商品入库单-票据打印就解决了,我们来看一下效果吧: 注意:在实际应用中,在需要频繁的使用单根打印的过程之中会直接输出到打印机而不会使用打印预览对话框,比如在银行、电信、电力、医疗等各行业的窗口业务模块。 至此,“商品入库”模块的相关处理就此结束,接下来演示两个查询类模块“库存查询”与“入库信息查询”。对这东西感兴趣的朋友呢,可以下载了完整代码之后自己看看,有问题请及时的和我联系。 有关本例所涉及的数据表结构请参考基于AgileEAS.NET平台基础类库进行应用开发-总体说明及数据定义一文,有关数据对象模型定义文件、文档、DDL脚本请下载:http://files.cnblogs.com/eastjade/demo.db.doc.sql.rar,本例完整代码下载:Product.Demo.rar。 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET官方网站 敏捷软件工程实验室 QQ群:116773358
回顾与说明 本文是DotNET企业架构应用实践系列中的一篇文章,同时也是一步一步教你使用AgileEAS.NET基础类库进行应用开发系统中的一篇文章,所以本文应该还有一个副标题“一步一步教你使用AgileEAS.NET基础类库进行应用开发-WinForm应用篇-在商口入库业务中使用缓存与缓存查询”,为什么会是这样呢?这个原因主要是我希望我在讲企业架的时候有结合具体的实例进行讲解,而不是泛泛而谈,而在AgileEAS.NET平台的案例开发中也正好涉及这样的内容。 在前面的WinForm篇前面我用了四篇文章实例演示了一个基于AgileEAS.NET实现两个应用模块:商品字典的管理和商品入库模块,这两个模块是一个典型的进销存系统中的两个经典而必须存在的两个模块。 在前面DotNET企业架构应用实践系统中,我用了两篇文章简单的和大家了解了性能优化的基础知道与性能优化中的缓存技术,并且在前面一步一步教你使用AgileEAS.NET基础类库进行应用开发-WinForm应用篇-复杂业务的实现(商品入库)-附案例操作视频一文及其附加的案例,我们可以知道这么一个应用场景:商品入库模块中,系统根据操作员输入产品的拼音检索商品字典,并在此基础之上输入产品价格与入量数量以完成产品入库,我们从案例可以知道,每次检索商品字典都要访问数据库,同时我们知道,在进销存系统中,商品字典这样的基础数据的变更不是很频繁,那么我们是否根据这样的场景使用缓存与缓存查询进行性能优化呢?答案当然是肯定的,本文的目的就在于此,结合案例讲解一个典型的场景。 本文的内容 本文的内容是在DotNET企业架构应用实践-系统架构与性能-缓存技术与ORM中的缓存查询技术与一步一步教你使用AgileEAS.NET基础类库进行应用开发-WinForm应用篇-复杂业务的实现(商品入库)-附案例操作视频两篇文章基础之上进行的,主要完成以下三个目标: 1.结合缓存技术一文,在今天的本例中,实现了个极其简单的ICacheManager,其提供了基于Key-Value的对象缓存,只提供了最基本的缓存处理,不提供缓存技术中的同步写回机制,也不提供缓存技术中的命中也缓存淘汰机制,关于这些内容有兴趣的朋友可以找我私下交流。 2.结合案例我详细的介绍AgileEAS.NET平台中的ORM缓存查询的详细使用方法。 3.基于应用案例讨论缓存的典型应用场景,进而了解性能优化的一些原则和基本发点。 ICacheManager的最简单实现 我们来动手实现一个最简单的ICacheManager,在Product解决方案之中增加了一个Product.Cache项目,增加ICacheManager接口和一个简单的实现CacheManager,代码如下: Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> 1 public class CacheManager : ICacheManager 2 { 3 Dictionary<string, object> objectList = new Dictionary<string, object>(); 4 5 #region ICacheManager 成员 6 7 public void Set(string key, object value) 8 { 9 this.objectList.Add(key, value);10 }11 12 13 public object Get(string key)14 {15 if (this.Exist(key))16 return this.objectList[key];17 else18 return null;19 }20 21 public bool Exist(string key)22 {23 return this.objectList.ContainsKey(key);24 }25 26 public void Remove(string key)27 {28 if (this.Exist(key))29 this.objectList.Remove(key);30 }31 32 public void Clear()33 {34 this.Clear();35 }36 37 #endregion38 } 这个ICacheManager实现只提供最简单的Key-Value,提供最基本的缓存服务,缓存对象与取缓存,而不提供命中、淘汰、同步与写回技术。 案例中的缓存查询场景 本文的缓存查询优化场景是这样的,前面案例中在商品入库的过程中,系统根据操作员输入的拼音简码检索数据库,在产品字典输入选择界面中当检查输入的条件发生变动时就去访问数据库,这样呢会频繁的访问数据库,如果有大量的客户短使用数据库,那么因为频繁的数据库查询会严重的影响数据库服务器的性能,而我们今天改造这个案例达到什么目的呢,第一次使用系统时,客户段会把商品字典记录一次性取回来,缓存在缓存系统之中,而在其后的拼音码检索中,不再访问数据库,而是直接使用缓存中的字典记录执行缓存查询,为了这个场景的方便展示我做了一个简单的视频,我把视频简单的分为不使用缓存系统与使用缓存系统,并且在演示的过程中打开SQLServer的事件探查器进行对比: 从视频中我们可以看了使用缓存与缓存查询性能带来的提省,极大的减少了数据库服务器的SQL查询请求。 关于实现代码 在视频中,我也简单的给大家看了一个程序代码,在这次的代码之中,增加了一个Product.Cache,用于定义和实现了一个简单的缓存系统,在Product.UI中增加了一个关于缓存上下文的辅助类CacheContext,其他最主要是提供了商品字典的缓存处理,代码如下: Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> 1 static class CacheContext 2 { 3 /// <summary> 4 /// Orm访问器。 5 /// </summary> 6 public static ICacheManager CacheManager 7 { 8 get 9 {10 return ContextHelper.GetContext().Container.GetComponentInstance("CacheManager") as ICacheManager;11 }12 }13 14 /// <summary>15 /// 处理产品字典缓存。16 /// </summary>17 /// <returns></returns>18 public static IProductList GetProductListCache()19 {20 string key = "ProductList";21 if(!CacheManager.Exist(key))22 {23 IProductList table = DALHelper.DALManager.CreateProductList();24 table.Query();25 CacheManager.Set(key, table);26 }27 28 return CacheManager.Get(key) as IProductList;29 }30 } 在这里面,使用了IOC方面的知识,在此我就不详细的再给大家了解,大家可以参考前面的文章了解和学习配置,在使用ORM的缓存查询时,需要在系统配置文件的IOC配置信息中配置缓存查询访问器的信息: 配置文件 Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> 1 <?xml version="1.0" encoding="utf-8"?> 2 <configuration> 3 <configSections> 4 <section name="EAS.Objects" type="EAS.Objects.ConfigHandler,EAS.IOCContainer"/> 5 </configSections> 6 <EAS.Objects> 7 <object name="DataConnection" assembly="EAS.Data" type="EAS.Data.Access.SqlClientConnection" LifestyleType="Thread"> 8 <property name="ConnectionString" type="string" value="Data Source=vm2003;Initial Catalog=eas;User ID=sa" /> 9 </object>10 <object name="OrmAccessor" assembly="EAS.Data" type="EAS.Data.ORM.OrmAccessor" LifestyleType="Thread">11 <property name="DbConnection" type="object" value="DataConnection" />12 </object>13 <object name="DataAccessor" assembly="EAS.Data" type="EAS.Data.Access.SqlClientAccessor" LifestyleType="Thread">14 <property name="Connection" type="object" value="DataConnection" />15 </object>16 17 <!-- 18 缓存查询组件。19 -->20 <object name="CacheAccessor" assembly="EAS.Data" type="EAS.Data.ORM.CacheAccessor" LifestyleType="Thread"/>21 22 <!-- 23 缓存管理组件。24 -->25 <object name="CacheManager" type="Product.Cache.CacheManager,Product.Cache" LifestyleType="Singleton"/>26 27 <object name="Product.DAL" assembly="Product.DAL.SQLServer" type="Product.DAL.SQLServer.DALManager" LifestyleType="Singleton"/>28 </EAS.Objects>29 </configuration> 在现阶段的AgileEAS.NET平台中,内置了一个缓存查询访问器实现EAS.Data.ORM.CacheAccessor,大家可以在应用中直接使用上面的配置,当然了,不安排除在后面提供其他缓存查询访问器,敬请大家期待。 本文今天就到这儿,对这东西感兴趣的朋友呢,可以下载了完整代码之后自己看看,有问题请及时的和我联系。 有关本例所涉及的数据表结构请参考基于AgileEAS.NET平台基础类库进行应用开发-总体说明及数据定义一文,有关数据对象模型定义文件、文档、DDL脚本请下载:http://files.cnblogs.com/eastjade/demo.db.doc.sql.rar,本例完整代码下载:Product.Demo.rar。 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET官方网站 敏捷软件工程实验室 QQ群:116773358
性能优化介绍 在企业应用开发领域,企业架构与性能将会是一个恒久的话题,如何提高性能、性能优化也将是一个长期和不断改进的过程,有人在硬件投入上下功夫、有人在数据库系统、数据库设计上下功能、有人在系统架构中下功夫、有人在程序下功能,总的来说,性能优化系是一个多方面的综合技术。 性能优化的理论依据 在计算机领域,缓存技术应该是一个非常久远的技术,CPU设计中高速缓存技术和操作系统内存管理中的分页、分段技术应该是我们每一位开发人员都熟悉的技术,在计算机体系结构与操作系统中,这两个关键点的好坏影响着计算机的整体性能。 在计算机软件应用中,性能优化的基准原则和最标准的参考案例就是这两个,其他一切的性能化为方案都基于这两个案例的基础理论而展开,这一切的理论依据,也那最经典的“局部性理论”,在计算机世界中是这样触释的: “是指程序在执行时呈现出局部性规律,即在一段时间内,整个程序的执行仅限于程序中的某一部分。相应地,执行所访问的存储空间也局限于某个内存区域。局部性原理又表现为:时间局部性和空间局部性。时间局部性是指如果程序中的某条指令一旦执行,则不久之后该指令可能再次被执行;如果某数据被访问,则不久之后该数据可能再次被访问。空间局部性是指一旦程序访问了某个存储单元,则不久之后。其附近的存储单元也将被访问” 如果我们把局部性原理再更放得具体化或者更简单一些,就是著名的“二八定律”了,我们可以这么简单的理解:程序中80%的程序运行时间都在执行着20%的程序代码,80%的时间都在频繁的使用着部数据中的20%的数据。 其实局部性理论,也就是“二八定律”并不单单的存在于计算机世界,我们现实的这个世界也是广泛的遵守着这个规律,我打几个很简单的比喻,这个社会上20%的人持有全社会80%的财产,而剩余的20%的财富由80%的人来分配,再比如,一个企业中起中流砥柱的只有那20%的人,其他80%总是在平庸的渡过。 性能优化的过程 我们简单的介绍完了性能优化的理论依据,那性能优化应该怎么样去做呢,有没有终极的解决方案和办法,我想告诉大家的是,性能优化没有终极的解决方案和办法,没有能解决所有性能问题的银弹,性能优化将是一个长期坚持并且不段改进的过程,你要优化一个系统,你必须得了解这个系统的运行机制,分析影响当前性能的各个关键点:计算机硬件、网络、数据库、系统架构、程序代码,通过不断的分析找出影响性能的问题点并修正、运行检测并不断的改进的一个过程。 性能优化的相关技术 虽然说我们找不到性优化的终极解决方案,但也不是说我们说无从下手进行性能优化,软件系统的性能优化可以从以下几个方面进行考虑: A.计算机硬件,这里的计算机硬件是指在企业计算领域中的服务器硬件,如果服务器硬件的运行能力严重的不足,那么我们说性能优化也就是“巧妇难为无米之炊”了,从我的工作经历来看,影响服务器系统运行能力的主要是CPU、内存、IO这三快,在数据库服务器中IO尤为显得重要,这方面可能参考RAID技术,在应用程序服务器中,则是由CPU和内存制约着系统的运行性能。 B.数据库设计,在抛除了服务器硬件和操作系统,那么数据库系统及数据库的结构将是影响系统性能的一个非常重要的因素,数据表结构设计的好坏将会对系统产生直接的影响,在这个领域的优化将涉及到数据结构、索引优化和数据分区,其目的是最大限度的发布服务器的IO和运算资源。 C.应用程序,应用程序的设计将直接影响系统的性能,在性能优化上考虑周全的应用程序和没有考虑过性能优化的程序在这方面将会有天壤之别,在这个块的性能优化手段包含两部门内容,一部分在开发应用程序的时间的系统性能考虑、另一方面刚是运营之中的性能优化。 C.系统架构,我们知道系统架构是系统的一个骨架,他将融合计算机硬件、系统软件、数据库系统、应用程序等各个方面,并基于一个系统工程的统一范畴考试上三方面的性能问题,就其前面三个方面的关键点就是一个有机的整体,相关关联而又相互制作,应用决定了应用程序与数据库设计结构,应用程序必须与数据结构配合以发挥最大性能,而数据库与服务器硬件必须配合以最大化的应用硬件的计算能力。并且,系统架构以整体和统一的思考数据库服务器、应用服务器的的集群与负载均衡。 关于系统性能优化的这样一个话题我今天就讲到这里,在后续的文章中我会将从以上四个方面展开详细的论述性能优化的方方面面。 文末我附上我相关系列文章的链接和QQ群,欢迎大家。 链接 DotNET企业架构应用实践-系列目录 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 QQ群:116773358
系列回顾 WinForm篇前面我用了两篇文章实例演示了一个基于AgileEAS.NET实现一个简单的增加、删除、修改、查询与打印的典型的简单应用案例,这应该是一个典型的MIS系统的应用场景。 在前一篇文章一步一步教你使用AgileEAS.NET基础类库进行应用开发-WinForm应用篇-在UI中应用DataUIMapper组件完成了商品字典编辑界面中的代改造,由原来的显示与写回代码改成DataUIMapper组件的DataObject<==>UI控件的映射方式。 结合前面的两篇文章,示例中的第一个模块“产品字典”可以说是告一段落了,接下来的工作,我们将开始第二个模快“商品入库”的开发。 本文内容 “商品入库”模块将是一个典型的业务处理模块,在产品入库的过程中,我们要求“一张入库单可以包含1-N个入库记录,并且在同一入库单中不得存在两条同品种的商品记录”,在本模块中,我们将会涉及到入库业务的票价打印、事务处理、业务层编码、缓存查询等一些技术专注点。 下面我就以视频的方式展现一下我们要达到的目标(截取案例的运行结果)【第一次弄这玩意,效果比较差,大家理解一下】: 关于表的ID列和入库单据号 在这个简单的应用案例中,一共定义了三个表,产品字典db.PRODUCT,产品库存表dbo.PSTORE,产品入库记录表dbo.PIN,在三个表中都定义了一个与业务无关的列ID,产品表的主键为商品编码[Code],产品入库表的主键为单据号+商品编码[BillCode+Code],库存表为商品编码+价格[Code+Price]。所有表中的ID字段的取值参考DotNET企业架构应用实践-数据库表记录的唯一性设计的设计兼议主键设定原则一文,入库单位号由日期(yyyyMMdd)+6位最大序列号组成,所有最大号当前值记录由一个单独表存放,AgileEAS.NET平台中存储在表eas.IDENTITYVALUES中,在本示例中存储在表dbo.IDENTITYVALUES,取值和更新由过程dbo.GetIdentityValue/dbo.GetIdentityValue完成,在程序中采用以下方式读取最大号: Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> 1 /// <summary> 2 /// 取记录号。 3 /// </summary> 4 /// <returns></returns> 5 public int GetMaxNewIdn() 6 { 7 ParameterCollection pc = new ParameterCollection(); 8 pc.Add("ITEMKEY", this.DbTableName); 9 return (int)this.DataAccessor.Query("exec dbo.GetIdentityValue @itemkey=?", pc);10 }11 12 /// <summary>13 /// 取单据号。14 /// </summary>15 /// <returns></returns>16 public string GetMaxBillCode()17 {18 ParameterCollection pc = new ParameterCollection();19 pc.Add("ITEMKEY", "ProductInBillCode");20 int code = (int)this.DataAccessor.Query("exec dbo.GetIdentityValue @itemkey=?", pc);21 return DateTime.Now.ToString("yyyyMMdd") + code.ToString("D6");22 } 注:本案例的Product.UI项目中增加了一个“唯一键值更新sql语句.sql”包含了本案例所需要上述的sql脚步,请自行更新到数据库。 实现商品入库 要实现产品入库,我们需要在Product.UI项目中增加两个新的窗体ProductInForm和SelectDictForm,其中ProductInForm为产品入库的业务运行界面,SelectDictForm为其附加界面,用于完成从产品字典中检索产品信息,我们分别来看一下这两个界面,ProductInForm: ProductInForm为产品入库模块的主界面,操作员通过在产品编辑输入框输入产品编码的拼音简码,比如:青霉素(QMS)然后按回车键打开SelectDictForm窗体: SelectDictForm会根据操作员输入产品拼音简码检索数据库并列出与之匹配的所有字典记录供操作员选择,操作选择一条记录按回车键或者空格键或者点击“选择”按钮跳转回ProductInForm,操作中输入产品价格及数量之后回车,系统会把刚才的输入结果暂存在界面下边的ListView控件中,一个单据可以输入多条产品入库记录,也可以选择入库列表记录通过delete键删除入库记录,最后通过“入库”按钮完成一次入库业务。 关于业务处理 对于本示例的商品入库处理,我提出了独立的业务对象处理其输入,在项目Product.BL中定义了ProductInBL业务层对象,代码请自己参考,关于业务分层请参考DotNET企业架构应用实践-实例架构设计中的业务分层-提取独立的业务层一文。 关于代码/下载 本文今天就到这儿,“商品入库”业务模块中的详细代码我就不在这贴了,太多,大家下载了完整代码之后自己看吧,在接下的文章中我将介绍缓存查询的应用。 有关本例所涉及的数据表结构请参考基于AgileEAS.NET平台基础类库进行应用开发-总体说明及数据定义一文,有关数据对象模型定义文件、文档、DDL脚本请下载:http://files.cnblogs.com/eastjade/demo.db.doc.sql.rar,本例完整代码下载:Product.Demo.rar。 最后,声明一句,不欢迎“巴克球”!我不想再说什么,别来凑热闹了。 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET官方网站 敏捷软件工程实验室 QQ群:116773358
系列回顾 WinForm篇我用了一步一步教你使用AgileEAS.NET基础类库进行应用开发-WinForm应用篇-实例一个模块(商品字典)和一步一步教你使用AgileEAS.NET基础类库进行应用开发-WinForm应用篇-实现字典的打印两篇文章实例演示了一个基于AgileEAS.NET实现一个简单的增加、删除、修改、查询与打印的典型的简单应用案例,这应该是一个典型的MIS系统的应用场景。 本文内容 本文我将在WinForm篇前面两篇文章所介绍的案例基础上介绍字典编辑场景中应用DataUIMapper组件,有关于DataUIMapper组件的介绍请参考.NET快速开发实践之应用IExtenderProvider实现对象与UI控件的绑定一文。 代码改造 在这里我也就不再介绍DataUIMapper组件的详细功能了,直接看看改造过程,我们先来看看原先的显示与写回代码: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 private void DataDisplay_Old(IProduct dict) 2 { 3 this.tbCode.Text = dict.Code; 4 this.tbName.Text = dict.Name; 5 this.tbSpec.Text = dict.Spec; 6 this.tbUnit.Text = dict.Unit; 7 this.tbDescription.Text = dict.Description; 8 this.tbPYCode.Text = dict.PYCode; 9 }10 11 private void WriteBack_Old(IProduct dict)12 {13 dict.Code = this.tbCode.Text;14 dict.Name = this.tbName.Text;15 dict.Spec = this.tbSpec.Text;16 dict.Unit = this.tbUnit.Text;17 dict.Description = this.tbDescription.Text;18 dict.PYCode = this.tbPYCode.Text;19 } 原来的代码需要手工实现UI控件与数据对象的交互比如dict.Code = this.tbCode.Text这样的写法,那么换成DataUIMapper组件应该怎么做呢。 首先在VS开发环境中把DataUIMapper组件添加到VS环境的工具箱,需要说明的是DataUIMapper组件由程序集EAS.Data.DataUIMapper.dll承载,然后向窗体ProductDictEditor拖放一个DataUIMapper组件,然后设定DataUIMapper组件的数据源属性: DataUIMapper组件可以通过BindingSource数据实现向数据对象的绑定,也就是可以属性窗口中很方便的设定数据源,当然,开发人员也可以通过其他方式设定数据源,比如可以通过修改ProductDictEditor.Designer.cs文件指定DataUIMapper组件的数据源对象: 虽然可以通过修改*.Designer.cs,但我还是建议通过GUI文件完成DataUIMapper组件的数据源设定,当完成DataUIMapper组件的数据源设定之后,我们就可以使用很方便的Data<==>UI绑定了,可以通过DataUIMapper组件的Mappings属性(集合)来配置数据对象与UI控件的交互关系: 在属性设定界面上有一个选项,“常用/全部”,选择“常用”之后控件下拉列表中会把一些不常用的UI控件过虑,但如果使用了一些特殊控件,被考虑了你需要选择“全部”,则可以完成对UI中的所有控件进行设定。 当我们完成绑定Data<==>UI绑定关系之后,我们只需要修改原先的数据显示与写回代码如下即可: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->1 private void DataDisplay(IProduct dict)2 {3 this.dataUIMapper1.UpdateUI(dict);4 }5 6 private void WriteBack(IProduct dict)7 {8 this.dataUIMapper1.UpdateObject(dict);9 } 今天的例子就到这儿,在UI编程中还会涉及到控件的焦点跳车、输入验证、输入法控件等一个辅助的扩展编程技术,在本系列中将不在详细讲述,有关于这些内容,请参考.NET快速开发实践中的IExtenderProvider扩展组件、.NET快速开发实践之应用IExtenderProvider实现输入法自动切换、.NET快速开发实践之应用IExtenderProvider实现控件焦点跳转等几篇文章。 有关本例所涉及的数据表结构请参考基于AgileEAS.NET平台基础类库进行应用开发-总体说明及数据定义一文,有关数据对象模型定义文件、文档、DDL脚本请下载:http://files.cnblogs.com/eastjade/demo.db.doc.sql.rar,本例完整代码下载:Product.Demo.rar。 最后,声明一句,不欢迎“巴克球”!我不想再说什么,别来凑热闹了。 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET官方网站 敏捷软件工程实验室 QQ群:116773358
简要介绍 在我们进行数据库设计的时候,大家都会考虑到数据表主键的设计,而可能没有人去关注记录唯一性字段设计,或者说,很多开发人员把这两种混合在一起处理,即就是表记录的唯一性与主键相结合的技术,因为从本质上讲,表主键的值是必须唯一的,他即能确保表记录的唯一性。 我在本文提出的思路是分离表记录的唯一性与主表键的设计,也可以理解为是双主键的设计思路,即唯一性设计可以与表业务无关,而表主键的设计必须与业务相关联,一个主键记录一定能具有一定的业务意义。 主键设计的争议 关于数据库主键设计的一些原则与所采用的技术,园子中有大量的文章讨论,我选择两片具体代码性的文章,听棠.NET的数据库主键设计之思考和zhenyulu的小议数据库主键选取策略(原创)两篇文章。 关于数据库主键设计的一些原则与所采用的技术,园子中有大量的文章讨论,我选择两片具体代码性的文章,数据库主键设计之思考与小议数据库主键选取策略(原创)两篇文章。 在数据库主键设计之思考一文中,作者把数据库主键设计讲的很透彻,他也提出了主键设计与具体业务无关的论点: “我强调主键不应该具有实际的意义,这可能对于一些朋友来说不太认同,比如订单表吧,会有“订单编号”字段,而这个字段呢在业务实际中本身就是应该具有唯一性,具有唯一标识记录的功能,但我是不推荐采用订单编号字段作为主键的,因为具有实际意义的字段,具有“意义更改”的可能性,比如订单编号在刚开始的时候我们一切顺利,后来客户说“订单可以作废,并重新生成订单,而且订单号要保持原订单号一致”,这样原来的主键就面临危险了。因此,具有唯一性的实际字段也代表可以作为主键。因此,我推荐是新设一个字段专门用为主键,此主键本身在业务逻辑上不体现,不具有实际意义。而这种主键在一定程序增加了复杂度,所以要视实际系统的规模大小而定,对于小项目,以后扩展不会很大的话,也查允许用实际唯一的字段作主键的。” 从个人的经历和技术角度来讲,我不同意这个主键与业务无意义的观点,我的观点是主键必须与业务相关,即一个表主键字段或者表主键字段组合必须具体一定的业务意义,并且增加一个与业务无关而有能确保记录唯一性的字段,即表的唯一性字段: 我列举一个例子,在商品进销存业务中的入库记录中记录个如下信息: Ø dbo.PIN(产品入库表) 表名 PIN 所有者 dbo 列名 数据类型 空 说明 IDN INT Y ID BillCode VARCHAR(16) Y 单根号 Code VARCHAR(16) Y 产品编码 Name VARCHAR(128) Y 产品名称 Spec VARCHAR(64) N 规格 Unit VARCHAR(32) N 单位 Price DECIMAL(18,4) Y 价格 Number INT Y 数量 Operator VARCHAR(64) Y 入库员 InTime DATETIME N 和库时间 业务要求同一入单可以包含1-N条产品库入库信息,同一入库单不得包含两条或条件以上的同一编码的商品记录,由此我们可以知道,入库单据号BillCode及产品编码Code即可以确定一笔交流,其组合是符合主键设立原则的,同时我们在主中增加了一个字段IDN,用于确保记录的唯一性。 相关的技术 表记录唯一性设计的技术我在本文不做详细的介绍,在数据库主键设计之思考与小议数据库主键选取策略(原创)两篇文章文章之中都有非常详细的论述,请大家去这两篇文章参考,他们建议这些技术使用于主键,而我更主张用于记录的唯一性确认上。 我推荐的选择 他多种唯一性确立技术之中,我比较喜欢“手动增长型字段”的设计,即在系统中增加一个表包含至少两个字段,Key和Value,如下所示: Ø eas.IDENTITYVALUES(唯一值记录) 表名 IDENTITYVALUES 所有者 eas 列名 数据类型 空 说明 GUID UNIQUEIDENTIFIER N Guid ITEMKEY NVARCHAR(128) Y 关键字 ITEMVALUE INT N 当前值 DESCRIPTION NVARCHAR(256) N 说明 同时,数据库中提供以下存储过程: CREATE procedure eas.GetIdentityValue @itemKey char(128) AS BEGIN TRANSACTION update eas.IDENTITYVALUES Set ITEMVALUE = ITEMVALUE + 1 where ITEMKEY = @itemKey select ITEMVALUE from eas.IDENTITYVALUES where ITEMKEY = @itemKey COMMIT TRANSACTION GO 值可以采用整性或者长整性进行存储,在具体应用的过程之中,在应用表中增加一个字段,插入数据时取这个过程的返回值,如: exec eas.GetIdentityValue @itemKey =“dbo.PIN” 数据分区的扩展 记录唯一性设计除了确保数据表记录的唯一性之外,还能为数据分区提供支持,不过这有一点要求,即唯一性设计必须采用整性或者并且一定连续意义的值才能处理,而如GUID这样的没有办法在将来支持扩展分区的设计。 本文先到此为止,在后面的文章中将会应用到这种技术并进行详细的讲解。 文未我加点广告,谢谢! 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET官方网站 敏捷软件工程实验室 QQ群:116773358(AgileEAS.NET平台)
系列回顾 从上一篇文章一步一步教你使用AgileEAS.NET基础类库进行应用开发-WinForm应用篇-实例一个模块(商品字典)开始我带领大家进入WinForm篇,并且使用示例的形式详细的演示了数据表对象的查询与列表的手工绑定。 本文论点 今天我将在上一篇文章的基础上介绍信息系统的另一个非常重要的功能,报表与打印,本文要实现的功能就是把商品字典的查询结果(已经显示在UI)打印出来。 本文结合商品字典的查询我介绍基于ORM实体的报表制做技术与程序中如何应用报表,具体的说就是,如果根据现有的数据对象(数据表对象)建立报表的定义,以及如何在程序中使用报表打印、预览组件,并用商品字典的查询结果(数据表对象)做为报表的填充数据源。 下面我将先介绍报表的制作: 制做报表 运行报表设计器ReportDesigner.Start.exe,选择文件菜单的新建--->对象报表,打开“新建数据对象报表”对话框: 切换到“数据对象”Tab页,点击“浏览”选择程序集Product.DAL.SQLServer.dll,然后在对象下拉列表中选择“Product.DAL.SQLServer.Product”,然后确定打开设计界面: 上图是报表设计器根据数据实体自动生成的报表,我们需要对其进行修改,修改的合理和好看一些,并预览一下: 在这里面说明一个问题,因为报表是基于数据表对象建立的,没有连接数据库,预览数据是随机生成的,最后我们把报表定义保存到文件中,比如保持为“商品字典.rdl”,这样我们完成了报表的制度。 使用报表 报表制做完成了,接下来的任务就是如何在程序中使用这个报表,首先我们在Product.UI中引用RdlEngine.dll、RdlViewer.dll、EAS.Report.DAL.Interface.dll、EAS.Report.Controls.dll四个文件,然后我们来编写工具条的打印按钮的Click事件处理代码: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 private void tsbPrint_Click(object sender, EventArgs e) 2 { 3 if (this.lvInfo.Items.Count == 0) 4 { 5 MessageBox.Show("没有需要打印的数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); 6 return; 7 } 8 9 if (this.printForm == null)10 this.printForm = new RDLViewDialog();11 12 //13 System.IO.TextReader textReader = null;14 try15 {16 string fileName = Path.Combine(Application.StartupPath, "Reports\\商品字典.rdl");17 textReader = new System.IO.StreamReader(fileName);18 this.printForm.SourceRdl = textReader.ReadToEnd();19 }20 finally21 {22 if (textReader != null)23 textReader.Close();24 }25 26 this.printForm.DataObject = this.lvInfo.Tag;27 this.printForm.PrintPreview();28 } 编译运行程序,看看效果: 有关本例子所涉及的数据表结构请参考基于AgileEAS.NET平台基础类库进行应用开发-总体说明及数据定义一文,有关数据对象模型定义文件、文档、DDL脚本请下载:http://files.cnblogs.com/eastjade/demo.db.doc.sql.rar,本文完整代码下载:Product.Demo.rar。 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET官方网站 敏捷软件工程实验室 QQ群:116773358
本文是一步一步教你使用AgileEAS.NET基础进行应用开发系统的WinForm应用篇的开篇,从本文起开始大家将看到一个距离真实应用非常接的开发案例。 商品字典管理 商品字典管理完成产品进销存业务业务中用到的基础信息,产品字典的增加、修改、删除等业务,它不是一个进销存在主体业务,只是用于为主体业务提供基础支持的一个辅助业务。 功能和界面预览 商品字典管理完成产品进销存业务业务中用到的基础信息,产品字典的增加、修改、删除等业务,它不是一个进销存在主体业务,只是用于为主体业务提供基础支持的一个辅助业务。 字典查询:根据产品编码或者产品名称的拼音简码检索数据库与之匹配的产品字典数据,并且显示的数据列表之上。 查询结果打印:将满足查询的结果打印输出,演示报表的使用。 添加新的产品字典:调用产品字典添加界面向系统中增加一个新的产品字典。 修改现有产品字典:调用产品字典修改界面修改指定的产品字典记录。 删除现有产品字典:删除系统中已经存在的某个产品字典。 代码的重新生成 现在我们可以来看看如何实现,不过,我们在看这个实现之前先插入一个小插曲,我们来看看我们的数据查询需求,“根据产品编码或者产品名称的拼音简码检索数据库与之匹配的产品字典数据”显然是不满足这个需求的,我们此前定义的数据结构之中没有定义拼音简码,我们现在来增加上,并且修正此前定义的几个bug。 然后重新生成代码,输出目录选择本解雇方案代码目录,不要选中“生成解雇方案”: 因为生成的代码采用了分部的的结构,数据层中与数据表、实体定义相关的对象定义信息都保存的项目的Generat目录下的名称带有Generat的代码文件中,而自定义的数据层业务逻辑被保存在项目目录中的不带Generat的代码文件之中,也就是说,当数据对象的定义发生变更并且重新生成代码文件后,不会覆盖我们编写的自定义处理,只覆盖与数据对象定义相关的代码文件,以保护程序员的投资。 实现我们的业务 对于字典的查询业务处理,我们需要在数据层接口IProductList编写一个数据查询方法void GetProductList(string code)并在SQLServer实现层项目中实现这个定义: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->1 public void GetProductList(string code)2 {3 Condition condition = this.CreateCondition();4 condition.AddElement("CODE", code, ElementType.MatchPrefix);5 condition.AddElement("PYCODE", code, ElementType.MatchPrefix,ElementCombineType.Or);6 condition.AddOrderElement("IDN", true);7 this.Query(condition);8 } UI代码之中增加一个查询结果显示代码: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 internal void LoadDictList() 2 { 3 IProductList dictList = DALHelper.DALManager.CreateProductList(); 4 dictList.GetProductList(this.tbSeach.Text); 5 6 try 7 { 8 this.Cursor = Cursors.WaitCursor; 9 this.lvInfo.BeginUpdate();10 this.lvInfo.Tag = dictList;11 this.lvInfo.Items.Clear();12 foreach (IProduct dict in dictList.Rows)13 {14 ListViewItem item = new ListViewItem(new string[] { string.Empty, dict.Code, dict.Name, dict.Spec, dict.Unit,dict.PYCode, dict.Description }, 0);15 item.Tag = dict;16 this.lvInfo.Items.Add(item);17 }18 }19 finally20 {21 this.lvInfo.EndUpdate();22 this.Cursor = Cursors.Default;23 }24 } 字典的添加与修改处理,我们在UI层中增加如下窗体: 并增加如下数据显示与写回代码: 代码 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 public IProduct Product 2 { 3 get 4 { 5 return this.product; 6 } 7 set 8 { 9 this.product = value;10 11 if (value != null)12 {13 this.DataDisplay();14 }15 }16 }17 18 private void DataDisplay()19 {20 this.tbCode.Text = this.Product.Code;21 this.tbName.Text = this.Product.Name;22 this.tbSpec.Text = this.Product.Spec;23 this.tbUnit.Text = this.Product.Unit;24 this.tbDescription.Text = this.Product.Description;25 this.tbPYCode.Text = this.Product.PYCode;26 }27 28 bool VerifyInput()29 {30 return true;31 }32 33 private void btnOK_Click(object sender, EventArgs e)34 {35 if (!this.Validate())36 {37 this.closed = -1;38 return;39 }40 41 try42 {43 IProduct dict = null;44 45 if(this.Product == null)46 {47 dict = DALHelper.DALManager.CreateProduct();48 dict.Idn = dict.GetMaxIdn();49 }50 else51 {52 dict = this.Product;53 }54 55 dict.Code = this.tbCode.Text;56 dict.Name = this.tbName.Text;57 dict.Spec = this.tbSpec.Text;58 dict.Unit = this.tbUnit.Text;59 dict.Description = this.tbDescription.Text;60 dict.PYCode = this.tbPYCode.Text;61 62 63 if(this.Product ==null)64 {65 dict.Insert() ;//66 this.Product = dict;67 }68 else69 dict.Update();70 71 this.closed = 0;72 }73 catch(System.Exception exc)74 {75 MessageBox.Show(this, "在保存药品字典时出错,错误:" + exc.Message, "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);76 this.closed = -1;77 }78 } 字典的删除业务,我们安排在当选择某个商品字典之后可以通过工具条或者快捷菜单中的“删除”完成操作,我们来看看其处理代码: 代码 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 internal void ProductDel() 2 { 3 if (this.lvInfo.SelectedItems.Count < 1) return; 4 5 if(MessageBox.Show(this, "是否确认删除所选择的药品字典?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No) 6 { 7 return; 8 } 9 10 try11 {12 13 foreach(ListViewItem item in this.lvInfo.SelectedItems)14 {15 IProduct dict = item.Tag as IProduct;16 dict.Delete();17 }18 19 foreach(ListViewItem item in this.lvInfo.SelectedItems)20 {21 this.lvInfo.Items.Remove(item);22 }23 }24 catch(System.Exception exc)25 {26 MessageBox.Show(this, "在删除药品字典时出错,错误:" + exc.Message, "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);27 }28 } 我们来编译并且运行这个示例: 有关本例子所涉及的数据表结构请参考基于AgileEAS.NET平台基础类库进行应用开发-总体说明及数据定义一文,有关数据对象模型定义文件、文档、DDL脚本请下载:http://files.cnblogs.com/eastjade/demo.db.doc.sql.rar,本文完整代码下载:Product.Demo.rar。 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET官方网站 敏捷软件工程实验室 QQ群:116773358
基础篇阶段总结 我在一步一步教你使用AgileEAS.NET基础类库进行应用开发-基础篇中原计划是从UDA讲到ORM,再引出DAL层,经由DAL层引申出分层结构,进行讲解业务层,并且在UI--->BL--->DAL的基础上引出目前最流行的基于“面向服务架构的”思路,进而把SOA的理念融合进这个例程,并通过AgileEAS.NET平台中的SL和分布式ORM技术实现这种理论。 原本我是按上述想法进行规划基础篇,其基础篇的目的就是希望大家看过基础篇的文章之后能很轻松的构建基于AgileEAS.NET平台的应用。 但是我在写这个系列的过程之中,很多关心AgileEAS.NET平台的朋友都希望我能尽快的基于实际应用进行讲解,也就是早点开始WebForm和WinForm应用示例的讲解。 关于WinForm篇 WinForm篇去讲解不个误会典型的产品进销存中的字典管理、产品入库业务,以及相关业务的查询与分析,如入库查询、库存查询,我在 WinForm篇中将会就UI编程技术,数据实现与UI的绑定、报表制作、打印集成等技术进行实例讲解,下面我列一下这个例程的业务及技术点: 案例解决方案 本篇的示例将在基础篇之上进行,项目结构将采用基础篇示例之中的业务层、数据层、增加新的UI层,并对原有代码进行了修改,代码的结构如下: 本解决方案一共由5个项目组成,数据层接口Product.DAL.Interface、数据层SQL实现Product.DAL.SQLServer、业务逻辑层Product.BL、用户界面层Product.UI、解决方案启动项目Product.AppStart。 接下来的事 接下来我将详细的对这个示例之中的业务功能及相关的技术要点进行展开,下文我将从最简单的业务基础数据定义-产品字典开始讲起。 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET官方网站 敏捷软件工程实验室 QQ群:116773358
说明一下,原本的思路是通过一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录相关的文章来逐步讲解基于AgileEAS.NET平台进行应用开发的文章,但是在进行案例讲解的过程,我们不得不扯到有关于AgileEAS.NET平台进行应用开发的架构设计方面的东西,我就把一些与架构有关的文章分离出来讲,了,我是基于AgileEAS.NET平台的应用开发实例来讲解架构设计,所以本文应该还有个副标题“一步一步教你使用AgileEAS.NET基础类库进行应用开发-基础篇-提取独立的业务层”,如果可能的话我会在这些独立抽取出来的文章的基础上,来个实例讲解DotNET企业架构应用实践方面的系列。 系列回顾 在前面的文章中,我从统一数据访问开始讲起,通过UDA到ORM的一步一步的深入,我们讲到了应用系统开发架构之中的数据访问层,并且详细的讲解了基于接口驱动的数据层,一步一步教你使用AgileEAS.NET基础类库进行应用开发-基础篇-基于接口驱动的数据层一文中我提到了以下的分层模型: 但是在严格意义上讲,我们之前一直在讲数据访问层的东西,演示的例子中并完成拥有独立的业务逻辑层,整体结构如下: 关于业务层 业务层是实现应用业务逻辑处理的业务逻辑层(Business Logic Layer,我们简称为BLL或者BL,从系统架构的理论角度讲,业务逻辑处理存在于任何架构的系统,我们把这些处理业务逻辑的代码独立抽取出来则形成独立业务层。 那么,业务层到底是做什么呢,在基于数据库支持的管理信息系统中,其大多采用的是UI-->BL-->DAL这样的基准分层架构或者基于这种基准架构的扩展,如UI-->BL-Agent—>BL->DAL或者UI-->BL-Agent->SL-Agent—>SL—>BL->DAL等等结构。 在于UI-->BL-->DAL这种分层结构的系统之中,业务层使用DAL层提供的数据访问服务封装业务逻辑以供UI层使用,也就是可以简单的理解为,业务层把UI要求的业务处理进行转化并使用DAL层提供的服务按业务流程进行处理。 现在的问题 现在我们回家看我们前面演示的例子,我们的例子中只分解了UI(ClassLib.OrmDemo)和DAL层(ClassLibDemo.DAL.Interface、ClassLibDemo.DAL.SQLServer),那么是不是我们没有业务逻辑呢,这倒不是,只不过,业务逻辑被分解到DAL和UI层之中了,因为在DAL层中的数据对象之中已经默认提供了数据业务处理的CRUD,也算是一种业务处理,复杂一些的业务,如产品入库处理这样的业务我们则由程序员自己编写,并且增加在生成的DAL代码之中的分部类之中。 当然对于一个很简单的应用,我们这样处理是一种选择,如果这个应用很复杂,我们采用这种结构则会显得代码结构有点混乱,我们有必要提出独立的业务逻辑层(BL)。 结构的变化 现在我们需要在原有解雇方案之中增加一个项目ClassLibDemo.BL,则项目结构变成如下: 在ClassLib.OrmDemo和ClassLibDemo.DAL.Interface之中增加一个项目ClassLibDemo.BL,其职责是完成除ORM对象CRUD之外的业务,从上图我们也可以看出ClassLib.OrmDemo也有跨过ClassLibDemo.BL对ClassLibDemo.DAL.Interface的直接调用。 关于此问题有一个争论,那就是ORM对象应该是独立的存储对象还是具有一定的业务功能,如,Insert、Update、Delete,我们估且不讨论这个,在目前的AgileEAS.NET平台中,ORM对象含有这些业务逻辑功能。 基于以上原因,在基于AgileEAS.NET平台的应用开发中,业务层的职责是处理除ORM对象CRUD之外的业务,也就是复杂的业务逻辑。 变更代码 现在我就商品入库业务演示一下业务的变更,首先我们注释或者删除ClassLibDemo.DAL.Interface项目中接口IProductInList的方法ProductIn定义,同时删除ClassLibDemo.DAL.SQLServer中相关的代码,在ClassLibDemo.BL中增加一个类ProductInBL,代码如下: Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> 1 public class ProductInBL:EAS.Business.BusinessObject 2 { 3 /// <summary> 4 /// 产品入库业务。 5 /// </summary> 6 /// <param name="pInList"></param> 7 public void ProductIn(IProductInList pInList) 8 { 9 this.DataAccessor.TransactionExecute(new TransactionHandler2(this.InternalIn), pInList);10 }11 12 void InternalIn(IDataAccessor accessor, params object[] parameters)13 {14 IProductStore pStore = DALHelper.DALManager.CreateProductStore();15 pStore.DataAccessor = accessor;16 17 IProductInList pInList = parameters[0] as IProductInList; //通过参数取值。18 19 foreach (IProductIn pIn in pInList.Rows)20 {21 pIn.DataAccessor = accessor;22 pIn.Idn = pIn.GetMaxNewIdn();23 pIn.Insert();24 25 pStore.Code = pIn.Code;26 pStore.Price = pIn.Price;27 pStore.Refresh();28 29 if (pStore.Exists)30 {31 pStore.Number += pIn.Number;32 pStore.Update();33 }34 else35 {36 pStore.Idn = pStore.GetMaxNewIdn();37 pStore.Code = pIn.Code;38 pStore.Name = pIn.Name;39 pStore.Spec = pIn.Spec;40 pStore.Unit = pIn.Unit;41 pStore.Price = pIn.Price;42 pStore.Number = pIn.Number;43 pStore.Insert();44 }45 }46 }47 } 我们修改UI项目中入库业务调用的代码ProductInDemo如下: Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> 1 class ProductInDemo 2 { 3 public void ProductIn1() 4 { 5 this.ProductIn2(); 6 } 7 8 public void ProductIn2() 9 {10 IProductInList pInList =DALHelper.DALManager.CreateProductInList();11 12 IProduct dict =DALHelper.DALManager.CreateProduct();13 dict.Code = "1AZ0002094";14 dict.Refresh();15 16 IProductIn pIn =DALHelper.DALManager.CreateProductIn();17 pIn.Code = dict.Code;18 pIn.Name = dict.Name;19 pIn.Spec = dict.Spec;20 pIn.Unit = dict.Unit;21 pIn.Price = 12.8M;22 pIn.Number = 200;23 24 pIn.InTime = DateTime.Now;25 pIn.BillCode = DateTime.Now.ToString("yyyyMMddHHmmss") + "_1";26 pIn.Operator = "james-orm";27 pInList.Rows.Add(pIn);28 29 try30 {31 new ProductInBL().ProductIn(pInList);32 System.Console.WriteLine("入库处理完成。");33 }34 catch35 {36 System.Console.WriteLine("入库未完成。");37 }38 }39 } 最后编译运行: 有关本例子所涉及的数据表结构请参考基于AgileEAS.NET平台基础类库进行应用开发-总体说明及数据定义一文,有关数据对象模型定义文件、文档、DDL脚本请下载:http://files.cnblogs.com/eastjade/demo.db.doc.sql.rar,本文代码下载:BL.Demo1.rar。 链接 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录 AgileEAS.NET平台开发指南-系列目录 AgileEAS.NET应用开发平台介绍-文章索引 AgileEAS.NET平台应用开发教程-案例计划 AgileEAS.NET官方网站 敏捷软件工程实验室 QQ群:116773358