基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET平台开发指南 - 实现插件...
插件契約介紹
???????? 我們知道,要基于平臺(容器)加插件的這種模式進行開發,我們必須定義一組契約,用于約束模塊插件開發,也就是說,模塊插件需要遵守一定的標準進行開發,才能正常被容器調用,這就是IModule所定義的內容。
IModule/// <summary> /// 插件接口定義。 /// </summary> public interface IModule:IPrivilegObject {/// <summary>/// 獲取模塊的名稱。/// </summary>/// <remarks>該值由開發者自己生成。</remarks>new string Name { get;}/// <summary>/// 獲取模塊的版本信息。/// </summary>/// <remarks>該值為對象的版本信息,從程序集中讀取,也可由開發者自己生成。</remarks>string Version { get;}/// <summary>/// 獲取模塊的開發者信息。/// </summary>/// <remarks>該值為對象的開發組織或個人說明信息,從程序集中讀取。</remarks>string Developer { get;}/// <summary>/// 獲取模塊的分組信息。/// </summary>/// <remarks>該值為模塊的分組,由開發人員定義,也可以在安裝后定義。</remarks>string Group { get; }/// <summary>/// 獲取模塊的介紹。/// </summary>/// <remarks>模塊的介紹與說明信息,由開發人員定義,也可以在安裝后定義。</remarks>string Description { get;}/// <summary>/// 獲取對象的圖標。/// </summary>/// <remarks>對象的圖標主要用于加載模塊時用。</remarks>Image Icon { get;}/// <summary>/// 當功能模塊成功啟動后觸發。/// </summary>event System.EventHandler Started;/// <summary>/// 在關閉模塊之前觸發該事件。/// </summary>event System.EventHandler Exited;/// <summary>/// 關閉當前模塊。/// </summary>void Close();/// <summary>/// 運行當前模塊。/// </summary>/// <param name="parameters">模塊運行的初始參數列表。</param>void Start(params object[] parameters); }???????? IModule定義了模塊名稱及模塊被調用的方法Run(),以及被平臺加載和關閉的事件,從定義可我們看到IModule繼續自IPrivilegObject。
IPrivilegObject/// <summary> /// 系統權限對象的基本規范。 /// </summary> public interface IPrivilegObject {/// <summary>/// 獲取權限對象的全局唯一標識符(GUID)。/// </summary>/// <remarks>該值由實現類得到,默認值實現類的GUID值。</remarks>System.Guid Guid { get; }/// <summary>/// 獲取對象權限對象所有者名稱。/// </summary>/// <remarks>該值用于說明權限所有者的名稱。</remarks>string Name { get;} }???????? IPrivilegObject為權限對象接品,平臺(運行容器)可以使用其鑒權系統對其實現權限檢查,關于系統的權限設計我會在后面專門進行說明。
???????? 在模塊插件的接口中,我們看到了很多關于模塊自描述的信息,比如名稱、說明、類型、程序集、版本號以及開發者等等,定義這些信息的目的在于對模塊的自描述,資源管理平臺在安裝模塊的過程中讀取這些元數據并存儲在數據庫,以方便對系統中插件的管理。
???????? 模塊元數據中定義的程序集、類型信息用于容器反射調用插件,這也是平臺+插件所依賴的關鍵技術。
直接實現IMobile接口
???????? 開發人員可以選擇直接實現IModule接口極其相關成員以實現一個業務插件,下面來一個簡單的實現:
Calculatorclass Calculator:IModule {#region IModule 成員public void Close(){}public string Developer{get{return "james/agilelab.cn";}}public event EventHandler Exited;public string Group{get{throw new Exception("The method or operation is not implemented.");}}public System.Drawing.Image Icon{get{return null;}}public string ModuleName{get{return this.Name;}}public void Run(params object[] parameters){try{System.Diagnostics.Process.Start("calc.exe");}catch{}}public event EventHandler Started;public string Version{get{return System.Reflection.Assembly.GetAssembly(this.GetType()).GetName().Version.ToString(); }}#endregion#region IObject 成員public string Assembly{get{return System.Reflection.Assembly.GetAssembly(this.GetType()).GetName().Name;}}public string Description{get{return "外部工具,計算器";}}public string Type{get{return this.GetType().ToString();}}#endregion#region IPrivilegObject 成員public Guid Guid{get{return new Guid("4B538C7C-99BD-46aa-9244-C594239D354A");}}public string Name{get{return "計算器";}}#endregion#region IAddIn 成員public void Start(params object[] parameters){this.Run(parameters);}#endregion }?????????? 原則說上,這種方法是可以的,但是在具體開發過程中,非必要情況下,不必要直接實現IModule接口,AgileEAS.NET平臺提供了一組默認的基礎實現。
復用AgileEAS.NET平臺基礎實現
???????? 開發人員直接實現IModule接口的問題在于會寫大量與業務無關的代碼,鑒于此問題,AgileEAS.NET平臺針對WebForm和WinForm應用提供了一系統的基礎實現,開發人員選擇在合適的基類上繼承并重寫與業務相關的信息,下面是一個簡單例子:
UserControl2public partial class UserControl2 : EAS.Windows.UI.Controls.ExplorerControl {public UserControl2(){InitializeComponent();}public override Guid Guid{get{return new Guid("2B6F6C7F-2382-433f-87D7-D601CE378081");}}public override string ModuleName{get{return "模塊插件例子";}}public override string Description{get{return "例子,還是例子";}}public override void Run(params object[] parameters){this.Message = "正在初始化插件...";}private void button1_Click(object sender, EventArgs e){MessageBox.Show("來來來,大家一起玩");} }???????? 可以看到,代碼相比直接實現IModule接口要簡介的多,AgileEAS.NET提供了如下的默認實現:
EAS.Windows.UI.Forms.ModuleForm
???????? WinForm模塊插件的基類實現(獨立的運行窗體),開發人員重寫ModuleName、Description、Guid屬性及入口方法Run即可。
EAS.Windows.UI.Controls.ModuleControl
???????? WinForm模塊插件的基類實現(內嵌入運行容器的業務控件),開發人員重寫ModuleName、Description、Guid屬性及入口方Run法即可。
EAS.Windows.UI.Controls.ExplorerControl
???????? WinForm模塊插件的基類實現(內嵌入運行容器的業務控件),相比較EAS.Windows.UI.Controls.ModuleControl提供了Close方法等、消息通知等增強功能,在開發過程中一般直接取代EAS.Windows.UI.Controls.ModuleControl。
EAS.Web.UI.ModulePage
???????? WebForm模塊插件的基類實現(獨立的運行面),開發人員重寫ModuleName、Description、Guid屬性即可,WebForm插件因為其特殊性無需處理入口方法。
EAS.Windows.UI.Controls.ModuleControl
???????? WebForm模塊插件的基類實現(內嵌入運行容器的業務控件),開發人員重寫ModuleName、Description、Guid屬性即可。
???????? 別外,針對項目中大量的數據綁帶應用業務,AgileEAS.NET平臺配合數據綁定接口IDataBind也提供了如下基礎實現:
???????? EAS.Windows.UI.Data.Form、EAS.Windows.UI.Data.ModuleForm、EAS.Windows.UI.Data.Control、EAS.Windows.UI.Data.ExplorerControl。
???????? EAS.Web.UI.Data.Page、EAS.Windows.Web.Data.ModulePage、EAS.Web.UI.Data.Control、EAS.Windows.Web.Data.ModuleControl。
???????? AgileEAS.NET除了提供這一系列的基礎實現之外,還提供了基于WinForm和WebForm開發常用的一組基礎實現指導組件,稱為GUI模板(EAS.Windows.Template.Dll和EAS.Web.Template.Dll)在開發中利于GUI能極大的加速應用開發,GUI模板以源代碼的形式向開發人員提供。
屬性標記Module
???????? 前面的1,2,3節都是基于實現IModule接口的方式來開發插件,下面將提供實現插件的另一種方式,利用.NET的聲明編程的方式采用屬性標記插件。
???????? 我們定義了ModuleAttribute屬性:
ModuleAttribute /// <summary>/// EAS.NET模塊插件屬性。/// </summary>/// <remarks>/// 提供IModule的標記實現,提供基于屬性標記的插件實現。/// </remarks>[AttributeUsage(AttributeTargets.Class)]public class ModuleAttribute : Attribute{private Guid guid = System.Guid.Empty;private string name = string.Empty;private string description = string.Empty;/// <summary>/// 初始化ModuleAttribute對象。/// </summary>/// <param name="guid">模塊Guid。</param>/// <param name="name">模塊名稱。</param>public ModuleAttribute(string guid, string name){this.guid = new Guid(guid);this.name = name;}/// <summary>/// 初始化ModuleAttribute對象。/// </summary>/// <param name="guid">模塊Guid。</param>/// <param name="name">模塊名稱。</param>/// <param name="description">模塊說明。</param>public ModuleAttribute(string guid, string name,string description){this.guid = new Guid(guid);this.name = name;this.description = description;}/// <summary>/// 模塊Guid。/// </summary>public string Guid{get{return this.guid.ToString();}set{this.guid = new Guid(value);}}/// <summary>/// 模塊名稱。/// </summary>public string Name{get{return this.name;}set{this.name = value;}}/// <summary>/// 模塊說明。/// </summary>public string Description{get{return this.description;}set{this.description = value;}}}???????? 及ModuleRunAttribute/ModuleStartAttribute屬性
ModuleStartAttribute /// <summary>/// 模塊入口方法屬性。/// </summary>/// <remarks>/// 配合ModuleAttribute實現基于標記的IMoule模塊。/// </remarks>[AttributeUsage(AttributeTargets.Method)]public class ModuleStartAttribute : Attribute{/// <summary>/// 初始化ModuleStartAttribute對象。/// </summary>public ModuleStartAttribute(){}}???????? 我們只需要在我們要公共的模塊插件的類打上ModuleAttributes標記、在模塊的入口調用方法上打上ModuleRunAttribute就可以了,以下為示例:
Hello /// <summary>/// 基于標記實現的插件。/// </summary>[Module("CB58C5BB-5D15-4a17-802E-341F9F65F35C", "Hello例子", "基于標記的模塊實現例子")]public class Hello{/// <summary>/// 入口方法。/// </summary>[ModuleRun]public void Start(){MessageBox.Show("Hello...");}public void Start2(){MessageBox.Show("Hello2...");}}
?????? 在以上例子中,我們標記了一個模塊插件,他的GUID屬性為“CB58C5BB-5D15-4a17-802E-341F9F65F35C”,模塊名稱為Hello例子,入口方法為Start方法,特別聲明一下,Start必須為一公共為參該當,Web模塊不需要入口方法。
關于IModule.Run的參數
?????? 通常情況運行容器是通過調用IModule接口的Run(params object [] parameters)方法實現功能模塊的加載和運行,運行容器通過Run方法向功能模塊以下參數。
?????? 第一個參數:模塊插件的父容器,如果是模塊為IModule接口,則這個參數為資源管理平臺的主界面(Shell); 如果是模塊為IExplorerControl接口,則這個參數為IExplorerControl模塊的容器控IExplorerControlContainer實例。
?????? 第二個參數:為當前登錄到資源管理平臺的當前賬號(EAS.Explorer.Users.IAccount Account)信息,提供系統當前使用者的信息。
?????? 第三個參數:為當前應用程序的會話信息,提供應用程序會話上下文環境,系統會話中包含著數據連接等相關的會話資源,模塊程序也可以使用這些。第二個參數與第三個參數是相互的,第二個參數的Session屬性就是第三個參數,第三個參數的Client屬性就是第二個參數,意思就是說,會話建立在當前賬號登錄到系統上的這個操作形成的,而會話的客戶端正是登前操作者。
?????? 功能模塊在處理Run(params object [] parameters)方法時,可參考以下代碼:
?????? IExplorerControl:
public override void Run(params object[] parameters)
{
?????? ISession session = (EAS.Sessions.ISession)parameters[2];
?????? …
}
??????? IModule:
public override void Run(params object[] parameters)
{
?????? Form shell = (System.Windows.Forms.Form)parameters[1];
?????? ISession session = (EAS.Sessions.ISession)parameters[2];
?????? …
}
平臺與模塊的交互
?????? 我們知道,插件開發完成之后要安裝、部署在平臺中,運行在AgileEAS.NET平臺的容器中,插件在運行過程中,如果取得平臺的上下文參數,如當前系統的登錄賬戶、數據庫連接等一系列的插件運行資源。
?????? 在AgileEAS.NET平臺的3.5版本之前,插件只有通過實現IModule接口來完成,所以平臺與插件的交互也就通過Run方法來完成,Run方法提供了平臺的三個參數,詳細內容見2.5節。但是在3.5之后,AgileEAS.NET平臺增加了更為方便的屬性標記實現,對于模塊的入口使用ModuleRun標記并且要求開發人員所標記的入口方法為無參方法,這樣就無法通過插件入口的調用完成平臺的參數傳遞。
?????? 為解決此問題,我們引入了一個上下文的概念,AgileEAS.NET平臺上下文環境,在4.0版本后,我們建議即使通過IModule接口實現的模塊,也不要使用Run入口方法的參數,轉而使用AgileEAS.NET運行容器上下文環境:
EAS.Modularization.Platform.IContainer,提供了會話,上下文環境的定義,他的定義:
IContainer /// <summary>/// 定義插件的運行容器接口。/// </summary>public interface IContainer{/// <summary>/// 獲取應用程序名稱。/// </summary>string Name { get;}/// <summary>/// 獲取容器上下文環境。/// </summary>IContext Context{get;}/// <summary>/// 獲取容器的當前會話。/// </summary>ISession Session{get;}/// <summary>/// 運行模塊。/// </summary>/// <param name="module">模塊實例。</param>void StartModule(object module);/// <summary>/// 運行模塊。/// </summary>/// <param name="module">模塊類型。</param>void StartModule(Type module);/// <summary>/// 運行模塊。/// </summary>/// <param name="module">模塊Guid。</param>void StartModule(Guid module);/// <summary>/// 運行模塊。/// </summary>/// <param name="module">模塊實例。</param>void StartModule(IModule module);/// <summary>/// 關閉模塊。/// </summary>/// <param name="module">模塊實例。</param>void CloseModule(object module);/// <summary>/// 關閉當前模塊。/// </summary>void CloseModule();/// <summary>/// 關閉模塊。/// </summary>/// <param name="module">模塊實例。</param>void CloseModule(IModule module);}?????????? 通過接口定義我們可以知道,他提供了當前系統的賬戶、會話、應用程序上下文環境(IOC容器)、會話上下文環境等等。
???????? 在當前會話中定義了當前系統的各種會話資源如數據庫連接、ORM訪問器等等開發基礎資料,程序員可以通過
?????????? IConnection dncn = Session.Resouces.FindResources(typeof(IConnection))[0] as IConnection;
?????????? 的方式進行取得各種資源進行業務處理。
插件的調試
?????????? 在最初的AgileEAS.NET平臺版本中,是沒有調試環境的,大概在2.0版本中加入了調試環境,WinForm的開發有獨立的調試環境,WebForm的開發使用WebForm的運行容器直接調試:
?????????? WinForm應用開發中,提供了一個EAS.Develop.Debuger.dll的程序集,由它給我們的插件提供一個模擬的WinForm運行容器,怎么使用這個調試環境呢,首先在應用開發的VS解決方案中,增加一個新的應用程序項目AppStart,引用及其甩依賴的程序集,添加一個Start類并增加如下代碼:
/// <summary>/// 調試器啟動類。/// </summary>class AppStart{ /// <summary>/// AgileEAS.NET調試器入口。/// </summary>[STAThread]static void Main() {EAS.Develop.Debuger.Application.Start();} }?????????? 并修改配置文件中的Assembly配置項的值為需要調試的程序集名稱:
?????????? <ConfigurationItem name="Assembly" value="EAS.Windows.FullExam"/>:
?????????? 插件調試環境使用與真實運行環境的配置文件,同樣的會話、同樣的上下文環境,同樣的系統會話資源,這一切都由系統配置文件進行配置。
?
鏈接
???? AgileEAS.NET平臺開發指南-系列目錄
???? AgileEAS.NET應用開發平臺介紹-文章索引
???? AgileEAS.NET官方網站
???? 敏捷軟件工程實驗室
?
QQ群:116773358
轉載于:https://www.cnblogs.com/eastjade/archive/2010/09/13/1824708.html
總結
以上是生活随笔為你收集整理的基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET平台开发指南 - 实现插件...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 平面电子地图如何表现同一位置的POI
- 下一篇: 手把手教你自己写一个js表单验证框架