首页 C#创建插件业务平台

C#创建插件业务平台

举报
开通vip

C#创建插件业务平台 2009. 92009. 9 编程语言 PROGRAM LANGUAGE 1 引言 在信息系统开发, 用户业务功能变化预先不可知, 故要提 高系统后期的业务扩展。 一般情况下用户需求发生变化, 要重 新编写代码, 编译, 生产部署包, 然后再更新用户程序, 这样 的过程比较繁琐。 本文讨论生成后的应用系统与外部编译的业务库实现动态 绑定, 应用程序在运行过程中动态绑定要实现的外部业务。 当 业务发生变化, 也只是替换这些外部的动态库, 不用重新对应 用程序进行修改和编译, 实现了耦合绑定。 同...

C#创建插件业务平台
2009. 92009. 9 编程语言 PROGRAM LANGUAGE 1 引言 在信息系统开发, 用户业务功能变化预先不可知, 故要提 高系统后期的业务扩展。 一般情况下用户需求发生变化, 要重 新编写代码, 编译, 生产部署包, 然后再更新用户程序, 这样 的过程比较繁琐。 本文讨论生成后的应用系统与外部编译的业务库实现动态 绑定, 应用程序在运行过程中动态绑定要实现的外部业务。 当 业务发生变化, 也只是替换这些外部的动态库, 不用重新对应 用程序进行修改和编译, 实现了耦合绑定。 同时, 业务实例对 象可以在程序运行时实现实例化, 达到了封装效果, 并且降低 了调用代码和具体实现类代码的耦合, 增强灵活性和可复用 性, 增加了软件的可维护性。 C# 提供的反射机制, 再结合自适应数据参数的传递, 通 过这个技术, 可以将应用框架中的扩展点以插件式程序集的方 式来动态加载、 构建, 从而实现可动态扩展的应用程序。 2 反射机制 反射是.NET 中重要机制, 通过反射, 可以在运行时获得 . NET 中每一个类型 (包括类、 结构、 委托、 接口和枚举等) 的 成员, 包括方法、 属性、 事件, 以及构造函数等; 还可以获得 每个成员的名称、 限定符和参数等。 .NET 的应用程序结构分 为应用程序域、 程序集、 模块、 类型和成员几个层次, 公共语 言运行库加载器管理应用程序域, 这种管理包括将每个程序集 加载到相应的应用程序域以及控制每个程序集中类型层次结构 的内存布局。 程序集包含模块, 而模块包含类型, 类型又包含 成员, 反射则提供了封装程序集、 模块和类型的对象。 可以使 用反射动态地创建类型的实例, 将类型绑定到现有对象或从现 有对象中获取类型, 然后调用类型的方法或访问其字段和属 性。 反射通常具有以下用途: (1) 使用 Assembly 定义和加载 程序集, 加载在程序集清单中列出的模块, 以及从此程序集中 查找类型并创建该类型的实例; (2) 使用 Module 了解如下的 类似信息 , 如模块的程序集以及模块中的类等 ; (3) 使用 CoustructorInfo 了解如下的类似信息, 如构造函数的名称、 参 数、 访问修饰符 (如 public 或 private) 和实现详细信息 (如 ab- stract 或 virtua1) 等; (4) 使用 MethodInfo 来了解如下的类似 信息, 如方法的名称、 返回类型、 参数、 访问修饰符 (如 pub- lic 或 private) 和实现详细信息 (如 abstract 或 virtua1) 等; (5) 使用 FieldInfo 来了解如下的类似信息, 如字段的名称、 访问修 饰符 (如 public 或 private) 和实现详细信息 (如 static) 等, 并 获取或设置字段值; (6) 使用 EventInfo 来了解如下的类似信 息, 如事件的名称、 事件处理程序数据类型、 自定义属性、 声 明类型和反射类型等, 并添加或移除事件处理程序: (7) 使 用 PropertyInfo 来了解如下的类似信息, 如属性的名称、 数据 类型、 声明类型、 反射类型和只读或可写状态等, 并获取或设 置属性值; (8) 使用 ParameterInfo 来了解如下的类似信息 , 如参数的名称、 数据类型、 参数是输入参数还是输出参数, 以 及参数在方法签名中的位置等。 3 设计思路 插件是一种遵循一定规范的应用程序接口编写出来的程序 模块。 当应用程序已经部署, 业务却发生了变化, 这样可以通 过读取插件配置信息, 载入新的应用构件, 实现变化的业务。 对于应用系统的框架而言, 扩展点是框架中预先定义的一 些 “点”。 在框架复用中应用构件的组装需要基于扩展点进 行。 构造性和演化性是软件的两个本质特征, 作为一类重要的 可复用软件制品。 而基于扩展点可以组装不同的应用构件以适 应领域的变化性, 则体现了框架对于软件演化特征的支持。 本文涉及到几个概念, 插件配置定义、 接口定义、 方法定 义、 调用参数定义和返回参数定义。 在本插件平台中, 配置文 件描述插件配置定义, 接口定义, 方法定义。 对于调用参数定 义和返回参数定义则采用通用对象和动态对象组来实现传入和 返回参数。 插件平台的实现过程如图 1 所示。 当平台运行初始化时, 通过读取 XML 配置信息, 装载 DLL, 通过 C# 的反射机制 分析 定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析 DLL 里的全部实现类和方法。 外部构件可以在平台容器中被实 例化, 并执行插件点的方法。 实现的算法不再是编码硬绑定。 C#创建插件业务平台 任 钢 摘 要: 在 C# 中采用反射机制, 通过动态参数输入和动态数据结果输出, 实现业务的外部 维护。 以此为基础创建了一个插件平台, 说明插件平台实现的技术基础、 实现思路和实现的 步骤, 并给出了插件平台的 C#程序源代码。 关键词: C#; 放射机制; 动态参数; 插件平台 19 2009. 9 这样, 应用程序在运行过程中动态绑定要实现的外部业 务, 当业务发生变化, 也只是替换这些外部的动态库, 不用重 新对应用程序进行修改和编译, 实现了耦合绑定。 4 具体实现 PlugPlatform 平台包括四个部分: (1) 配置文件的获取和 解析; (2) 通用参数和动态参数组处理; (3) 插件平台装载 DLL 并执行外部方法; (4) 异常处理。 4.1 配置文件的获取和解析 配置文件以 XML Schema 为基础, 分为两种类型, 一种是 类配置文件, 主要描述关于外部 DLL 中的类以及方法的内容; 第二种配置文件是接口配置文件, 主要描述关于外部 DLL 中 的接口以及方法的内容。 类配置文件的 XSD 如图 2 所示。 按照此 XSD 形成的配置 XML 如图 3 所示。 同理可以接口配置文件的 XSD 内容 (如图 4) 和 XML 树 (如图 5)。 在实现将 XML 树状结构的数据转换为二维 MethodObject 哈希 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf , MethodObject 哈希表是一个 key/value 的键值对, 其中 key 通常可用来快速查找 , value 用于存储对应于 key 的值 。 MethodObject 类数据结构如下: public class MethodObject { private ClassObject classobject = null; private InterfaceObject interfaceobject = null; private DllFileObject dllfileobject = null; private string name = string.Empty; private string simplename = string.Empty; private string implementname = string.Empty; public string MethodName {get { return this.name; } set { this.name = value; } } public string SimpleName { get { return this.simplename; } set { this.simplename = value; } } public string ImplementName {get { return this.implement- name; }set { this.implementname = value; }} public ClassObject ClassObject {get { return this.classob- ject; }set { this.classobject = value; }} public InterfaceObject InterfaceObject {get {return this.in- terfaceobject; }set {this.interfaceobject = value; }} public DllFileObject DLLFileObject { get { return this.dll- fileobject; } set { this.dllfileobject = value; }} } MethodObject 哈希表中 key 为保证内容的唯一性而采用方 法的全名。 可以, 这样形成的主键可以进行快速查找。 value 用来存储 MethodObject 对象。 同时 MethodObject 对象与 Class Object对象, InterfaceObject 对象和 DLLFile 对象都是多对一的 关系。 所以, 一旦获得了 MethodObject 对象, 就可以反推出 ClassObject 对象, InterfaceObject 对象和 DLLFile 对象。 根据 XML Schema 可以构建 XML 文档树, 对 XML 文档树 的节点进行分层遍历, 然后采用递归算法, 依次把 XML 文档 树上最边上的叶子转化为方法对象哈希表, 实现方式如图 6 所 示。 4.2 通用参数和动态参数组处理 对于外部的方法, 要传入参数, 同时也获得结果。 这些都 要用一些通用的数据结构来描述。 参数必须可以支持任何类 型, 是一个通用性的参数。 通过创建一个数据的通用类, 可以 保证支持任何数据类型。 由于传入和传出的参数有多有少, 这就要求参数组能实现 随意的自动增长和减少。 通过设计一个动态自增长的参数数组 就可以实现。 设计模型如图 7 表示。 图 1 PlugPlatform 整个过程图 图 2 类配置文件的 schema 图 图 3 类配置文件的 XML 树 图 4 接口配置文件的 schema 图 图 5 接口配置文件的 XML 树 图 6 配置 XML 转 MethodObject 哈希表 20 2009. 92009. 9 编程语言 PROGRAM LANGUAGE 动态参数组的增加数组对象方法如下: public DynamicArrayObject addObject(DataValueObject obj) { if (Objects == null) { Objects = new DataValueObject[1]; Objects[0] = obj; return this; } else { DataValueObject [] objectList = new DataValueOb- ject[Length + 1]; for (int i = 0; i < Length; i++) { objectList[i] = Objects[i]; } objectList[Length] = obj; Objects = objectList; return this;} } 动态参数组的删除数组对象方法如下: public DynamicArrayObject deleteObject(int idx) { if (Objects == null) return this; else { if (idx >= 0 && idx < Length && Length > 1) { DataValueObject [] objectList = new DataValueObject [Length - 1]; for (int i = 0; i < idx; i++) {objectList[i] = Objects[i];} for (int i = idx + 1; i < Length; i++) {objectList[i - 1] = Objects[i]; } Objects = objectList; return this; } else { if (idx == 0 && Length <= 1) { Objects = null; return this; } else return this; } } } 4.3 插件平台动态装载 DLL 并执行 PlugFramework 是整个 PlugPlatform 平台的核心内容。 主要 实现检查和装载 DLL 文件, 动态创建实例化对象, 验证并执 行外部方法。 PlugPlatform 依据配置文件可以了解装载的外部 DLL 文件 和要求执行的类或接口方法。 整个装载和调用过程如图 8 所 示。 PlugFramework 包含有类和接口, 这些类和接口之间有继 承、 实现、 关联关系, 如图 9 所示。 PlugFramework 各个类的具体描述如表 1。 动态调用外部方法的核心代码如下所示: public object InvokeClassMethod (String className, object[] objectArgs, String methodName, object[] methodArgs) { Object[] newArgs = new Object[methodArgs.Length]; Object thisObject = new Object(); Type type = CreateType(className); MethodInfo[] methods = type.GetMethods(); Object instance = CreateObject(type, objectArgs); foreach (MethodInfo m in methods) { if (m.Name == methodName) { newArgs = ConvertArgsType(m, methodArgs); 图 7 DataValueObject 类和 DynamicArrayObject 类的 设计模型 图 8 PlugPlatform 动态装载的全过程 图 9 PlugPlatform 类图 表 1 21 2009. 9 try { if (! m.IsStatic) thisObject = m.Invoke (instance, newArgs); //非静态方法,使用类实例调用 else thisObject = m.Invoke(null, newArgs); return thisObject;} catch (Exception e) {throw new PlusException("不能 动态调用方法,原因:" + e.Message, e); }} } return thisObject; } 图 10 表示 PlugPlatform 实现全过程。 下面分别对每个步骤 做一个详细描述。 (1) 外部应用请求动态调用。 (2) PlusConfig 类根据配置文件创建 PlugFactory 对象。 (3) PlugFactory 对象创建一个 Action 对象。 (4) Action 对象获得 MethodObject 对象组, 逆向产生 Dll- FileObject 对象。 (5) 根据 DllFileObject 对象中的 DLL 文件信息, Action 对 象通过 AssemblyManager 类获得 Assembly 对象。 (6) Action 对象使用 Assembly 对象创建 TypeManager 对 象。 (7) Action 对象传递 MethodObject 对象给 TypeManager 对 象。 (8) TypeManager 对象可依据 MethodObject 对象获得 Clas- sObject 对象。 并使用 ClassObject 对象信息动态创建一个外部 ClassObject 对象的实例 instance。 (9) TypeManager 对象使用 instance 和 MethodObject 对象 信息调用 instance 的动态方法。 instance 把执行结果返回给 Ac- tion 对象。 (10) Action 对象把执行结果返回给外部应用。 其中 Plus 工厂模式采用了 Factory 模式。 对于 Assembly 的 生成采用了 Singleton 模式。 4.4 异常处理 由于应用程序中有很多不可预料的问题, 本平台在很多地 方都有可能出现人为错误, 如找不到配置文件; 配置文件的格 式不对, 不能解析配置文件; 类或接口名称写错了, 不能实例 化类; 方法名称写错了, 不能执行方法等等。 5 应用实例 本例程序主要有三个方面组成 : XML 配置文件 、 外部 DLL 文件和 PlusPlatform 调用代码。 5.1 XML 配置文件 采用的 XML 配置文件有两个, 一个是针对类对象的 XML 配置文件, 一个是针对接口对象的配置文件。 其中类对象的 XML 配置文件如下: testAction01 testAction02 testAction03 testAction01 接口对象的配置文件与类对象配置文件基本相同, 只不过 配置信息中由类换成了接口: testAction01 5.2 DLL 文件内容 其编译的 DLL 文件为 UserLibrary.dll, 该 dll 文件包括两个 类和一个接口, 其内部代码为: public class UserTest1 { public DynamicArrayObject testAction01 (DynamicAr- rayObject outObject) { DynamicArrayObject thisObject=new DynamicArrayObject(); //分解 DynamicArrayObject DataValueObject do1 = null; string ls = null; for (int i = 0; i < outObject.Length; i++) { do1 = outObject.getObject(i); ls += (String)do1.getDataValue(); } DataValueObject do2 = new DataValueObject(); do2.setDataType(do1.getDataType()).setDataValue(ls); //组装 DynamicArrayObject,返回 DynamicArrayObject thisObject.addObject(do2); 图 10 PlugPlatform 实现的顺序图 22 2009. 92009. 9 编程语言 PROGRAM LANGUAGE return thisObject; } public DynamicArrayObject testAction02 (DynamicAr- rayObject outObject) { return outObject; } } public class UserTest2 : InterfaceTest1 { public DynamicArrayObject testAction01 (DynamicAr- rayObject outObject) { DynamicArrayObject thisObject=new DynamicArrayObject (); //分解 DynamicArrayObject DataValueObject do1 = null; string ls = null; for (int i = 0; i < outObject.Length; i++) { do1 = outObject.getObject(i); ls += (String)do1.getDataValue(); } DataValueObject do2 = new DataValueObject(); do2.setDataType(do1.getDataType()).setDataValue(ls); //组装 DynamicArrayObject,返回 DynamicArrayObject thisObject.addObject(do2); return thisObject; } public DynamicArrayObject testAction02 (DynamicAr- rayObject outObject){ return outObject;} } public interface InterfaceTest1 { DynamicArrayObject testAction01(DynamicArrayObject outObject); } 5.3 调用代码 调用代码也分为两类, 一类是针对类对象处理的, 代码如 下: DynamicArrayObject thisObject = new DynamicArrayOb- ject(); DataValueObject do1 = new DataValueObject(); DataValueObject do2 = new DataValueObject(); do1.setDataType("string").setDataValue("类测试 :第一个对 象值."); do2.setDataType("string").setDataValue("第二个对象值."); thisObject.addObject(do1).addObject(do2); string dllFile=Application.StartupPath + "\\DllClassFile.xml"; PlugFactory factory = PlusConfig.BuildFactory(dllFile); IAction action = factory.CreatAction(); DynamicArrayObject outputObject = action.Execute ("UserLibrary.UserTest1.testAction01", thisObject); 另一类是针对接口对象处理, 代码如下: DynamicArrayObject thisObject=new DynamicArrayObject(); DataValueObject do1 = new DataValueObject(); DataValueObject do2 = new DataValueObject(); do1.setDataType("string").setDataValue("接口测试:第一个对 象值."); do2.setDataType("string").setDataValue("第二个对象值."); thisObject.addObject(do1).addObject(do2); string dllFile = Application.StartupPath + "\\DllInterface- File.xml"; PlugFactory factory = PlusConfig.BuildFactory(dllFile); IAction action = factory.CreatAction(); DynamicArrayObject outputObject = action.Execute ("In- terfaceTest1.testAction01", thisObject); 可以对返回的 DynamicArrayObject 做分解查看, 满足设计 要求。 6 结语 反射机制结合动态数组很好地解决了应用软件的后期维护 和升级。 对于应用软件的变化, 可不改动任何现有的程序, 只 要修改 XML 配置文件的相应对象名称和加载新的对象即可, 程序不需要任何的重编、 重启和硬性改动, 并保证了原应用系 统的可复用性从而实现降低耦合度, 实现复用的目标。 本模型在层与层之间借助类调用和接口实现, 利用反射机 制把调用者与实现者在编译期分离。 运行期通过读配置文件动 态加载实现类, 并通过接口将实现者强制转型, 使其为调用者 所用, 完成调用者和实现者的解耦。 但是, 这个功能并不是完 全完善, 对于插件平台也有很多的改进性, 如果能对类和接口 配置文件更加丰富, 把插件平台升级为一个框架容器, 该容器 能把对象之间的依赖关系先行剥离, 然后在适当时候由容器负 责产生具体的实例再注射到调用者中, 即控制权由应用代码中 转到了外部容器, 控制权发生了转移。 即所谓的控制反转模 式, 这种模式在 Java 中已经有比较成熟的框架, 如 Spring 等。 相信凭借 Microsoft.NET 庞大的技术框架平台, 在 C# 上也会有 这样的控制反转框架出现。 参考文献 [1] (美) Karli Watson Christian Nagel 等, 康博译 . C# 入门经 典. 北京: 清华大学出版社, 2006. [2] MSDN Library .NET Framework 开发员指南: 在运行时了解 类型信息. 2003. [3] 刘瑜, 张世琨, 王立福, 杨芙清. 基于构件的软件框架与 角色扩展形态研究. 软件学报, 2004; 14(8): 1364-1370. [4] 段春笋, 杜立新. C# 动态数组设计原理. 电脑编程技巧与 维护, 2005; (7) :24-25. [5] 何文海, 谢建刚 . 基于 .NET 平台的插件式应用框架开发 . 电脑知识与技术 (学术交流), 2007; (8): 755-756. [6] 冷山述, 陆倜, 武装. 用 C# 构造可复用软件体系结构. 航 空计算技术, 2003; (4): 88-93. [7] 殷凯, 谢文威. 在工厂方法模式中.NET 反射技术应用的研 究. 常州工学院学报, 2006; (4): 28-34. [8] 姚明, 李家兰. 基于.NET 的通用软件开发平台的研究与实 现. 电脑知识与技术 (学术交流), 2007; (8): 797-798. (收稿日期: 2009 年 1 月 6 日) 23
本文档为【C#创建插件业务平台】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_221943
暂无简介~
格式:pdf
大小:411KB
软件:PDF阅读器
页数:5
分类:互联网
上传时间:2011-04-10
浏览量:23