1. 程式人生 > >動態載入與外掛系統的初步實現(二):AppDomain解除安裝與代理

動態載入與外掛系統的初步實現(二):AppDomain解除安裝與代理

前一篇文章簡單展示了型別發現和MEF使用,本文初步進入AppDomain相關內容。

CLR程式執行時會建立預設程式集容器即AppDomain,預設AppDomain不支援解除安裝其程式集,但CLR支援建立和解除安裝AppDomain,這意味著我們可以間接地通過額外的AppDomain實現外掛的熱插拔。

代理AppDomain建立PluginProvider例項,該例項及其發現的IPlugin的實現需要被被預設AppDomain訪問,於是發生了跨AppDomain邊界的訪問,PluginProvider及IPlugin的具體實現需要由MarshalByRefObject派生(更多相關內容仍然需要自行MSDN)。

為Plugin專案新增PluginProxy類,該類負責維護上述的額外AppDomain、將PluginProvider封送回預設AppDomain。本例僅設計了單個外掛容器的場景,故以單例模式實現:

public class PluginProxy
{
    private readonly static PluginProxy instance = new PluginProxy();

    private PluginProxy()
    {
    }

    public static PluginProxy Instance
    {
        
get { 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; } } }
View Code

AppDomain的建立與跨邊界訪問物件的成本很高,後文中預設AppDomain與外掛的互動將以代理PluginProxy通知PluginProvider的方式實現。Plugin中PluginProvider小幅修改:

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小幅修改:

[Export(typeof(IPlugin))]
public class Plugin1 : MarshalByRefObject, IPlugin
{
    public String DoStuff()
    {
        return "MyPlugin1 Plugin1.DoStuff";
    }
}
View Code

主程式PluginProxy由靜態類屬性訪問,同時加入邏輯檢驗DLL可否在AppDomain解除安裝後刪除,WinForm與WCFRestService示例在後續給出。程式碼檔案

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,請替換#為@,溝通後奉上簡歷。