動態載入與外掛系統的初步實現(二):AppDomain解除安裝與代理
阿新 • • 發佈:2019-02-16
前一篇文章簡單展示了型別發現和MEF使用,本文初步進入AppDomain相關內容。
CLR程式執行時會建立預設程式集容器即AppDomain,預設AppDomain不支援解除安裝其程式集,但CLR支援建立和解除安裝AppDomain,這意味著我們可以間接地通過額外的AppDomain實現外掛的熱插拔。
代理AppDomain建立PluginProvider例項,該例項及其發現的IPlugin的實現需要被被預設AppDomain訪問,於是發生了跨AppDomain邊界的訪問,PluginProvider及IPlugin的具體實現需要由MarshalByRefObject派生(更多相關內容仍然需要自行MSDN)。
為Plugin專案新增PluginProxy類,該類負責維護上述的額外AppDomain、將PluginProvider封送回預設AppDomain。本例僅設計了單個外掛容器的場景,故以單例模式實現:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class PluginProxy { private readonly static PluginProxy instance = new PluginProxy(); private PluginProxy() { } public static PluginProxy Instance {View Codeget { return instance; } } private AppDomain pluginDomain = null; private PluginProvider pluginProvider = null; public PluginProvider Provider { get { if (pluginDomain == null) { pluginDomain = AppDomain.CreateDomain("PluginDomain"); Type pluginProviderType = typeof(PluginProvider); pluginProvider = (PluginProvider)pluginDomain.CreateInstanceAndUnwrap(pluginProviderType.Assembly.FullName, pluginProviderType.FullName); } return pluginProvider; } } public void Unload() { if (pluginDomain != null) { AppDomain.Unload(pluginDomain); pluginDomain = null; } } }
AppDomain的建立與跨邊界訪問物件的成本很高,後文中預設AppDomain與外掛的互動將以代理PluginProxy通知PluginProvider的方式實現。Plugin中PluginProvider小幅修改:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class PluginProvider : MarshalByRefObject { [ImportMany] public IEnumerable<Lazy<IPlugin>> Plugins { get; private set; } public PluginProvider() { AggregateCatalog catalog = new AggregateCatalog(); catalog.Catalogs.Add(new DirectoryCatalog(".")); CompositionContainer container = new CompositionContainer(catalog); container.ComposeParts(this); } }View Code
MyPlugin1中Plugin1小幅修改:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[Export(typeof(IPlugin))] public class Plugin1 : MarshalByRefObject, IPlugin { public String DoStuff() { return "MyPlugin1 Plugin1.DoStuff"; } }View Code
主程式PluginProxy由靜態類屬性訪問,同時加入邏輯檢驗DLL可否在AppDomain解除安裝後刪除,WinForm與WCFRestService示例在後續給出。程式碼檔案
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Program { static void Main(string[] args) { PluginProvider pluginProvider = PluginProxy.Instance.Provider; foreach (Lazy<IPlugin> plugin in pluginProvider.Plugins) { Console.WriteLine(plugin.Value.DoStuff()); } PluginProxy.Instance.Unload(); String filename = "MyPlugin1.dll"; if (File.Exists(filename)) { File.Delete(filename); Console.WriteLine("File deleted"); } else { Console.WriteLine("File not exist"); } Console.WriteLine("Press Enter to exit"); Console.ReadLine(); } }View Code
附求職:尋求.Net相關職位,偏向後端,目前人在北京,有意請郵件jusfr.v#gmail.com,請替換#為@,溝通後奉上簡歷。