订阅主要应用事件而不将插件加载到主应用领域

时间:2013-10-20 15:38:20

标签: c# plugins dll appdomain

我有一个主应用程序,它将插件加载到一个单独的应用程序域中。在该插件中,我订阅了从主应用程序传递的对象上的事件。在单独的应用程序域中创建插件会将插件dll加载到该域中,但订阅主应用程序对象上的事件也会导致插件dll也被加载到主应用程序域中。

我希望能够卸载插件域(有效)但我还需要能够替换我目前无法执行的插件dll,因为该dll是在主应用域中加载的(因为该订阅)

以下示例代码类似于我的实际代码(为简洁起见):

我有一个名为IContract的接口,用于实例化插件:

namespace PluginShared
{
    public interface IContract
    {
        void Init(IHostObject hostObject);
        void Shutdown();
    }
}

它驻留在一个单独的PluginShared.dll中。该接口定义了2个方法,Init用于传递在主应用程序中创建的对象,Shutdown用于在插件的app域被卸载之前在插件中进行必要的清理。

IHostObject位于相同的PluginShared.dll中,如下所示:

namespace PluginShared
{
    public interface IHostObject
    {
        event Action ValueChanged;
    }
}

此接口由主应用程序中的HostObject实现:

public class HostObject : MarshalByRefObject, IHostObject
{
    public event Action ValueChanged;

    public void Foo()
    {
        if (ValueChanged != null)
            ValueChanged();
    }
}

主应用程序代码加载插件,调用Init并将HostObject实例传递给插件。然后调用插件上的Shutdown并卸载插件域。

private void LoadUnloadPlugin()
{
    IHostObject hostObject = new HostObject();

    AppDomain pluginAppDomain = AppDomain.CreateDomain("PluginAppDomain");

    IContract plugin = (IContract)pluginAppDomain.CreateInstanceFromAndUnwrap(@".\Plugin1.dll", "Plugin1.Plugin1");

    plugin.Init(hostObject);
    plugin.Shutdown();

    AppDomain.Unload(pluginAppDomain);
}

该插件是它自己的Plugin1.dll:

namespace Plugin1
{
    public class Plugin1 : MarshalByRefObject, IContract
    {
        IHostObject myHostObject;

        public void Init(IHostObject hostObject)
        {
            myHostObject = hostObject;
            myHostObject.ValueChanged += OnValueChanged;
        }

        public void Shutdown()
        {
            myHostObject.ValueChanged -= OnValueChanged;
            myHostObject = null;
        }

        private void OnValueChanged()
        {
            // Do Stuff
        }
    }
}

所以,问题是当myHostObject.ValueChanged + = OnValueChanged;执行时,它会将Plugin1.dll加载到主app域中,这将锁定dll,从而阻止我删除它。

顺便说一下。我有许多类似IHostObject的接口,它们定义不同的ValueChanged,就像不同对象触发的事件一样。通常,我的插件不会订阅所有对象的事件。我之所以提到这一点,是因为上面示例代码中的ValueChanged事件可以很容易地用IContract中的一个方法替换,该方法将为每个插件调用而不是触发事件,但我的实际实现需要更多类似事件的方法。

那么有没有一种方法/技术/模式可以用来从主应用程序中获取选定的通知/事件而无需将插件dll加载到主应用程序域?

0 个答案:

没有答案