c#構建插件式的應用程序框架_第1頁
c#構建插件式的應用程序框架_第2頁
c#構建插件式的應用程序框架_第3頁
c#構建插件式的應用程序框架_第4頁
c#構建插件式的應用程序框架_第5頁
已閱讀5頁,還剩14頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、我們來看一些常見的提供插件模式的應用程序說起插件 ( plug in ) 式的應用程序大家應該不陌生吧 , 記得很早以前有一款很流行的 MP3 播放軟件winmap, 它是我記憶里最早認識的一款使用插件模式的應用程序, 你可以使用他的插件管理器插入很多的音樂效果器, 皮膚, 甚至是歌詞顯示的面板。接下來看到了 Photoshop 使用插件模式管理慮鏡。最后發現只要是大一點的應用程序基本都使用了插件式的程序框架,就拿我們最常用的工具來說吧, Visual Studio , Office , Delphi , Eclipse 等等。 Eclipse 將插件模式發揮到了及至,因為他是開源的的,所以眾

2、多的愛好者,開發出了讓人應接不暇的插件。為什么使用插件式的應用程序框架呢?我的答案就是他為應用程序的功能擴展提供的無限的想象空間。 一個應用程序, 無論你前期做了多少的市場調查,需求分析做的多么完美,你也只是迎合一部分人的期望,更甚,你只迎合了一部分人的一部分期望,或者一部分人在某一時間的一部分期望。所以當程序發布以后,你依然有機會提供新的功能而不必重新發布程序,人們也可以根據自己的需要來開發新的功能來滿足自己的需求,據我所知有很多的軟件公司就是專門開發插件來賺錢,真是一舉多得,何樂而不為呢?是如何實現插件功能的。據我的使用經驗來看, Visual Studio 和 Office 其實都是自動

3、化程序,通過COM 的方式提供了一組接口。開發人員可以利用這些接口來開發基于 COM 的插件,當插件開發完成后,注冊 COM 組件。 在 Visual Studio 中你可以使用 Add in 管理器來選擇是否啟用插件, 而 Office 似乎省去了這一步, 一旦你注冊了 Office 插件, Office 應用程序在啟動的時候會自動加載插件。 COM 方式似乎最受微軟的寵愛,因為 COM 是一種二進制重用標準,用戶可以使用大部分流行的語言來開發插件。當然你也可以使用別的方式,比如普通DLL ,只是這樣對于開發人員來說適用面就窄了, 因為各個廠商DLL 的內部結構是不盡相同的,比 VC 開發出

4、的 DLL 和 Borland C builder 開發出的 DLL 結構就不同, 需要專門的工具進行轉換。現在,還有另外一種方式,使用dotNet 的 Assembly , 使用 dotNet 的好處是開發簡單,使用也同樣簡單(不需要注冊),而且你也可用通過 COM 互操作讓開發人員可以使用各種語言進行插件開發,當然用 dotNet 開發還是最簡單的,省去不少中間過程。其實上面介紹的三種方式開發的插件最終還是寄宿在 DLL 中, 從中我們就可以看出一些端倪。 為什么使用 DLL 呢? DLL 雖然也是 PE 格式, 但是他是不能獨立運行的,一般情況下,都是在運行時加載到應用程序的內存空間。

5、插件模式正好是利用了這一點,插件不是應用程序的一部分,他以二進制的方式獨立存在,由用戶決定是否使用他。那么插件是如何與應用程序進行交互的呢?首先必須有一個契約,應用程序要聲明我有哪些功能是可以被插件使用的,并且具備什么條件才能成為我的插件。其次,應用程序不依賴于插件,也就是說,沒有你插件,我也可以很好的運行。再次,應用程序必須有一種策略來獲取插件存在的位置, 比如 Visual studio 是通過注冊表的方式。最后,應用程序可以通過某種方式動態的加載插件。最近工作比較忙, 沒有時間寫 Blog , 控件開發總結的那個系列停在那里好久了,汗一個,有空就盡快補上吧。這個系列也先開個頭吧,不然又會

6、被自己找各種借口扼殺了。構建插件式的應用程序框架(二)訂立契約無論是用COM勺方式,還是普通DLL才卬或.NET方 式來實現插件框架,首先要面臨的問題就是如何訂立 契約。如同我上一篇文章講到的一樣,契約是應用程 序和插件之間進行交互的依據和憑證。應用程序必須 聲明我有什么樣的功能可被插件使用,并且插件必須 符合什么條件才能被我使用。反之,插件必須要知道 應用程序提供什么樣的功能,我才能將自己的功能融 入到應用程序的體系中。本系列文章主要講如何使用一 NET實現插件式的應用程序框架,所以其它的方式我 就不再提了。如何使用.NET訂立契約呢?首先想到的Interface 其次是抽象類,但是在插件模

7、式中我使用接口,因為 我們是在滿足應用程序的主要目的的基礎上來提供附 加的插件功能,就這一點來說,接口更靈活,更容易 擴展。接下來,如何訂立契約的內容呢?這就要根據 你的業務需求了,為了講解的方便,我們定義一個最 最基本的插件式應用程序的插件契約。我們做一個假 定,我們的應用程序是一個多文檔的應用程序,包含 一個主菜單欄,一個工具欄,菜單欄可以在程序的上 下左右四個方向停靠,另外還有一個狀態欄。到后邊, 如果有必要,我會擴展這個應用程序,讓他本身提供更多的可供插件使用的功能。所以就目前而言,我想 實現的功能就是讓插件為主程序添加工具條,菜單項 并實現一些簡單的功能。應用程序向插件提供服務有兩種

8、方式,一種是直接 再應用程序接口中聲明屬性或者方法,一種是將應用 程序接口聲明成一個服務容器。我打算兩種方式都用, 明確的功能就在接口中直接聲明成屬性或者方法,另 外將應用程序聲明成一個服務容器,以方便插入更多 的服務功能,提高應用程序的可擴展性。下邊是一個非常簡單的應用程序接口定義,對于我 們的假定已經足夠了。using System;using System.Collections.Generic;using System.Text;using System.ComponentModel.Design;using System.Windows.Forms;namespace PluginF

9、ramework日圖public interface IApplication:IServiceContainer韓ToolStripPanel LeftToolPanel get;ToolStripPanel RightToolPanel get;ToolStripPanel TopToolPanel get;ToolStripPanel BottomToolPanel get;MenuStrip MainMenuStrip get;StatusStrip StatusBar get;插件的接口定義:using System;using System.Collections.Generic;

10、using System.Text;namespace PluginFramework三王public interface IPlugin甑 IApplication Application get;set;甑 String Name get;set;甑 String Description get;set;void Load();void UnLoad();event EventHandler<EventArgs> Loading;構建插件式的應用程序框架(三)-動態加載不管你采用什么方式實現插件式的應用程序框 架,核心還是動態加載,換句話說,沒有動態加載技 術也就無所謂插件式的

11、應用程序框架了。使用Com實現的話,你可以利用 Com的API通過ProgID來 動態創建COM對象,如果使用普通DLL,你需要使 用 Windows 的API函數LoadLibrary 來動態加載 DLL ,并用GetProcAddress 函數來獲取函數的地卅。 而使用.NET技術的話,彳需要使用 Assembly類的 幾個靜態的 Load (Load , LoadFile , LoadFrom ) 方法來動態加載匯集。一個Assembly里可以包含多個類型,由此可 知,一個Assembly 里也可以包含多個插件,就像前 一篇文章所講,只要它從IPlugin接口派生出來的類 型,我們就承認

12、它是一個插件類型。那么 Assembly 被動態加載了以后,我們如何獲取Assembly里包含 的插件實例呢?這就要用到反射(Reflection )機制 了。我們需要使用Assembly 的GetTypes靜態方法 來得到Assembly里所包含的所有的類型,然后遍歷 所有的類型并判斷每一個類型是不是從IPlugin接口 派生出來的,如果是,我們就使用 Activator的靜態 方法CreateInstance方法來獲得這個插件的實例。上NET的動態加載就是這幾個步驟。下來,我做一個簡單的例子來演練一下動態加載。首先聲明一點,這個 例子非常簡單,純粹是為了演練動態加載,我們的真 正的插件式的

13、應用程序框架里會有專門的PluginService來負責插件的加載,卸載。我們的插件位于一個DLL里,所以我們首先創 建一個 Class library 工程。創建一個 FirstPlugin 類讓它派生于IPlugin接口,并實現接口的方法和屬 性,由于本文的目的是演示動態加載,所以 IPlugin 接口的Loading事件我們就不提供默認的實現了,雖 然編譯的時候會給出一個警告,我們不必理會它。這 個插件的功能就是在應用程序里創建一個停靠在主窗 體底部的ToolStrip,這個ToolStrip上有一個按鈕, 點擊這個按鈕,會彈出一個 MessageBox 顯示“The first plu

14、gin ;下面是代碼:using System;using System.Collections.Generic;using System.Text;using PluginFramework;using System.Windows.Forms;namespace FirstPlugin日2public class FirstPlugin:IPlugin百電privateApplication application =nullprivate String name=""private String description =""中“IPlugin M

15、embers卜 接下來我們創建一個Windows Application 工 程讓主窗體派生于 Application 接口并實現IApplic ation接口的方法和屬性,下來我們聲明1個MenuStrip和1個StatusStrip ,讓他們分別停靠在窗口 的頂部和底端,接下來我們聲明4個ToolStripPane l,分別人他們停靠在上下左右四個邊,最后我們創建 一個ToolStrip,在上邊添加一個按鈕,當點擊這個按 鈕的時候,我們動態的加載插件。為了方便演示,我們把生成的Assembly放置到 固定的位置,以方便主程序加載,在本例里,我們在 應用程序所在的文件夾里創建一個子文件夾Pl

16、ugins(E:PractisePluginSamplePluginSamplebinDebugPlugins ),將插件工程產生的 Assembly (FirstPlugin.dll )放置在這個子文件夾。下面是動 態加載的代碼:private void toolStripButton1_Click( object sender, EventArgs e) I/動態加載插件,為了方便起見,我直接給出插件所在的位置String pluginFilePath = Path.GetDirectoryName(Application.ExecutablePath) + "pluginsWF

17、irstPlugin.dll"Assembly assembly = Assembly.LoadFile(pluginFilePath);1/得到Assembly 中的所有類型Type types = assembly.GetTypes();I/遍歷所有的類型,找到插件類型,并創建插件實例并加載foreach (Type type in types)的 if (type.GetInterface("IPlugin") !=null )/ 判斷類型是否派生自IPlugin 接口前1IPlugin plugin = (IPlugin)Activator.CreateI

18、nstance(type);/ 創建插件實例plugin.Application =this ;plugin.Load();卜卜干我把完整源代碼也附上,方便大家使用:源代碼下載構建插件式的應用程序框架(四)服務容器在構建插件式的應用程序框架(二)訂立契約一文中,可以看到我們的 Application 接口是派 生于IServiceContainer 接口的。為什么要派生于I ServiceContainer 呢?我們來看看 IServiceConta iner的定義,它有幾個AddService 方法和Remov eService方法以及從IserviceProvider 繼承過來的 GetS

19、ervice 方法。Service 本身杲.NET設計時架構 的基礎,Service提供設計時對象訪問某項功能的方 法實現,說起來還真拗口。就我看來, ServiceCont ainer機制的本質就是解耦合,就是將類型的設計時 功能從類型本身剝離出來。如果你把類型的設計時功 能也封裝到類型里,這樣的類型包含了很多只有開發 人員才會用到而最終用戶根本不需要的功能,使得類 型既臃腫有不便于擴展。而將設計時功能剝離出來, 這樣類型就可以不依賴于特定的設計環境,之所以現 在有這么多非官方的.NET設計環境可能就是這個原 因吧。我們的插件式的應用程序框架正好也需要這樣 一個松散的架構,我就移花接木把它應

20、用到我們的框 架中。ServiceContainer是.NET 提供的 IserviceContainer的實現,如果沒有特殊的需要我們不必擴展它,而是直接的利用它。在上一篇文章中我們在實現IApplication 接口的時候就直接使用的 ServiceContainer 。我們在使用 Service 架構的時候,總是傾向于有一個根容器,各個Service 容器構成了一個Service 容器樹, 每一個節點的服務都可以一直向上傳遞,直到根部,而每一個節點請求Service 的時候,我們總是可以從根節點獲得。我把這個根節點比喻成一個服務中心,它匯總了所有可提供的服務,當某個對象要請求服務( Ge

21、tService ) 只需要向根結點發送要獲得的服務,根結點就可以把服務的對象傳遞給它。從另外一個角度看, ServiceContainer 為我們的插件是應用程序提供了有力的支持,利用 Service Container ,你不但可以獲得應用程序所提供的所有的功能,而且你還可以通過插件向應用程序添加 Ser vice ,而你添加的 Service 又可以服務另外的 Servi ce ,這樣我們的應用程序框架就更加的靈活了。但是任何東西都是有兩面性的,帶來靈活的同時也為開發人員的工作增加了復雜度,所以使用 ServcieContianer 開發的應用程序必須提供足夠詳細的文檔,否則開發人員可能

22、根本不知道你到底有多少Service 可以用,因為很多的 Service 是通過插件提供的,可能應用程序的作者都不會知道程序發布以后會出現多少 Serviceo寫了這么多,可能接觸過ServiceContainer 的朋友已經覺得羅唆了,沒接觸過的還是覺得說得莫 明其妙。有空接著寫,我會創建幾個簡單的服務演練 演練,增強一下感性認識,呵呵。構建插件式的應用程序框架(五)管理插件我們現在已經搭建了插件式的應用程序框架,接 下來的工作就是要充實框架的內容,提供基本的服務, 也就是Service。我想首要的任務就是提供插件的管 理服務,我在前面的文章也提到了,要實現動態加載 必須要知道插件寄宿在哪里

23、,哪些要加載,哪些不加 載,這些就是這篇文章要討論的問題。首先解決的就是插件放在什么地方,我采取的 傳統的方法,將插件放到應用程序所在目錄下的制定 目錄,我會在應用程序所在的目錄下創建一個文件夾, 命名為Plugins。接下來的工作就是要通知哪些插件 是要加載的,哪些是不需要加載的,我會將這些信息 放到應用程序的配置文件中的制定配置塊中,當應用 程序運行的時候,就會讀取配置文件,并根據獲得的 信息加載插件。另外我們的應用程序框架是建立在Service基礎之上,所以我需要創建一個管理插件的s我們現在定義一個插件管理的Service接口。using System;using System.Coll

24、ections.Generic;using System.Text;namespace PluginFrameworkring pluginDescription);Ivoid RemovePlugin(String pluginName);IString口 GetAllPluginNames();IBoolean Contains(String pluginName);IBoolean LoadPlugin(String pluginName);IBoolean UnLoadPlugin(String pluginName);IIPlugin GetPluginInstance(String

25、 pluginName);Ivoid LoadAllPlugin();t-PluginService要實現的目標首先是在配置文件中添加/刪除要加載的插件以及相關的信息,接下來就是動態的加載插件。我們要定義幾個類型:Plugin配 置區塊類型,Plugin元素類型,plugin元素集合類 型,以便我們能夠讀取插件的信息。最后我們實現PluginService :using System;using System.Collections.Generic;using System.Text;using System.Xml;using System.Configuration;using Syste

26、m.Reflection;using System.Windows.Forms;using System。;using System.Collections;namespace PluginFramework日叫public class PluginService : IPluginService鈍private lApplication application =null ;private PluginConfigurationSection config =null ;private Dictionary<String, IPlugin> plugins =new Dictionary< string , IPlug

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論