一、前言

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.agileeas.net

官方博客:http://eastjade.cnblogs.com

github:https://github.com/agilelab/eas

QQ:47920381

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。

使用Lua脚本语言开发出高扩展性的系统,AgileEAS.NET SOA中间件Lua脚本引擎介绍的更多相关文章

  1. 犀利的报表系统,发票据与报表开发的快速利器,AgileEAS.NET SOA中间件GReport使用指南

    一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...

  2. AgileEAS.NET SOA中间件平台/敏捷软件开发平台

    AgileEAS.NET SOA中间件平台/敏捷软件开发平台 最新下载 一.前言 AgileEAS.NET SOA中间件平台,简称EAS.NET,是基于敏捷并行开发思想和Microsoft .Net构 ...

  3. ESP8266 LUA脚本语言开发: 准备工作-LUA开发是怎么来的

    前言 当前8266有各种开发 1.在官方已经封装好的C库上开发(SDK开发) 2.官方在SDK的基础上封装的AT指令程序(AT指令开发) 3.在SDK的基础上嵌入脚本语言(Lua,Python等开发方 ...

  4. Atitit.软件架构高扩展性and兼容性原理与概论实践attilax总结

    Atitit.软件架构高扩展性and兼容性原理与概论实践attilax总结 1. 什么是可扩展的应用程序?1 2. 松耦合(ioc)2 3. 接口的思考 2 4. 单一用途&模块化,小粒度化2 ...

  5. 优秀开源项目之三:高性能、高并发、高扩展性和可读性的网络服务器架构State Threads

    译文在后面. State Threads for Internet Applications Introduction State Threads is an application library ...

  6. jetbrick,新一代 Java 模板引擎,具有高性能和高扩展性

    新一代 Java 模板引擎,具有高性能和高扩展性. <!-- Jetbrick Template Engineer --> <dependency> <groupId&g ...

  7. (转)mysql数据库高可用高扩展性架构方案实施

    http://shanhu.blog.51cto.com/1293405/1212605-----mysql数据库高可用高扩展性架构方案实施

  8. AgileEAS.NET SOA中间件平台/敏捷软件开发平台 and SQL详解

    AgileEAS.NET SOA中间件平台/敏捷软件开发平台 http://www.smarteas.net/ SQL详解: http://www.w3school.com.cn/sql/func_d ...

  9. ESP8266 LUA脚本语言开发: 准备工作-动手编译LUA固件

    前言 这节咱自己编译LUA固件 准备一台linux的机子 我把固件放到了git上,方便电脑用http下载 我先用这个连接linux 大家随意哈,只要是一台linux的机子就可以,不管是图形页面还是命令 ...

随机推荐

  1. shell知识点小结

    目录 引言 shell中的数组 数组的定义 数组的使用 实际的例子 shell中大小的比较 shell中的括号 shell中函数的定义 杂项知识点 字符串转数组 常用判断标志 linux后台运行相关 ...

  2. 11月6日上午PHP练习《租房子》解析

    一.题目要求 二.题目做法 1.建立数据库 2.封装类文件 <?php class DBDA { public $fuwuqi="localhost"; //服务器地址 pu ...

  3. "Emgu.CV.CvInvoke”的类型初始值设定项引发异常 解决办法

    系统win7 32位,只在这一台电脑上出现这种问题,已知VS编译是X86,在数台电脑上测试都正常. 后来把opencv的dll路径例如 E:\...\x86  加入到系统环境变量中就正常了. emgu ...

  4. Migrating an Existing Website from SQL Membership to ASP.NET Identity

    Migrating an Existing Website from SQL Membership to ASP.NET Identity public class User : IdentityUs ...

  5. 文件夹锁定(Source)

    文件夹锁定(Source)private void Lock(string folderPath){    try    {        string adminUserName = Environ ...

  6. Python 读写文件中数据

    1 需求 在文件 h264.txt 中的数据如图1,读入该文件中的数据,然后将第1列的地址删除,然后将数据输出到h264_out.txt中: 图1 h264.txt 数据截图             ...

  7. scp命令详解

    \ svn 删除所有的 .svn文件 find . -name .svn -type d -exec rm -fr {} \; linux之cp/scp命令+scp命令详解   名称:cp 使用权限: ...

  8. iphone如何导出微信聊天记录到电脑?

    有个小美眉买了个iphone,但发现自己就是一小白,很多功能都不会用,微信倒是用得挺上手的,可以晚上聊到三四点,流量直接飙升500MB.最近她说手机太卡了,问ytkah帮她整一下.拿起她的IPhone ...

  9. log4net 运行时改变日志级别

    ((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root.Level = Level.Debug; ((log ...

  10. 【krpano】浏览点赞插件1.1(源码+介绍+预览)

    插件使用说明详见:http://www.cnblogs.com/reachteam/p/5479068.html 插件更新 1.新增测试模式 用户可以使用uid="test"进行本 ...