C#程序集在子域中创建实例



我正在尝试创建一个插件框架,并通过C#中的反射加载依赖项。我目前的实现如下:

public interface IPlugin : IDisposable
{
    void Run();
}
public interface IPluginProxy : IDisposable
{
    void RunProxy();
    void LoadDependencies(string pluginDirectoryPath, AppDomain pluginDomain);
}
public class PluginProxy : MarshalByRefObject, IPluginProxy, IDisposable
    {
        private List<IPlugin> pluginTypes = null;

        public void ProcessProxy()
        {
            //loop thorough plugin types and call Run on all plugins
            foreach(var pluginType in pluginTypes)
            {
                pluginType.Run();
            }
        }
        public void LoadDependencies(string pluginDirectoryPath, AppDomain pluginDomain)
        {
            pluginTypes = Utility.LoadAssembliesAndGetPluginTypes(pluginDirectoryPath, pluginDomain);            
        }
        //TODO:
        public void Dispose(){}
    }
public Class Utility
{
    public static List<IPlugin> LoadAssembliesAndGetPluginTypes(string pluginDirectoryPath, AppDomain pluginDomain)
    {
        try
        {
            var pluginTypes = new List<IPlugin>();
            var pluginsDirectory = new DirectoryInfo(pluginDirectoryPath);
            var files = pluginsDirectory.GetFiles("*.dll", SearchOption.TopDirectoryOnly);
            foreach (FileInfo file in files)
            {
                // Load the assembly into the child application domain.
                Assembly assembly = pluginDomain.Load(AssemblyName.GetAssemblyName(file.FullName));
                var iPluginTypes = zGetTypes(assembly);
                pluginTypes.AddRange(iPluginTypes.ToList());
            }
            return pluginTypes;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
    private static IEnumerable<IPlugin> zGetTypes(Assembly assembly)
    {
        var myPlugins = from y in assembly.GetTypes()
                             where y.IsClass && y.GetInterface("IPlugin") != null &&
                                   y.GetConstructor(Type.EmptyTypes) != null
                             select Activator.CreateInstance(y) as IPlugin;
        return myPlugins;
    }
}

我有一个windows服务,它创建了一个新的应用程序域。然后它获取PluginProxy并调用LoadDependencies和ProcessProxy。注意,我正在尝试将依赖项加载到子域中。

问题出在zGetTypes方法上。该方法能够找到IPlugin类型(intellisense显示了这一点)。但是,即使调用Activator.CreateInstance.,类型也不会初始化(null)

请注意,如果我在子域中,zGetTypes无法创建类型为IPlugin的实例。

程序集Assembly=pluginDomain.Load(AssemblyName.GetAssemblyName(file.FullName));

如果我不创建单独的appdomain,只将程序集加载到主appdomain中,那么创建实例就可以了。在我的案例中,Service的appdomain创建子appdomain。我想把加载插件程序集的责任推给代理。Proxy派生自MarshalByRefObject,因此我可以创建一个实例并从windows服务端打开它。

然后,该服务将插件的加载和生命周期管理委托给代理。代理将通过LoadDependencies的方法参数获取子appdomain的上下文。

有什么想法为什么不创建IPlugin的实例吗?

我能够通过在代理级别推断域来解决这个问题。在我的windows服务中,我以以下方式创建插件代理的实例:

IPluginProxy pluginProxy = IPluginProxy)
(pluginDomain
.CreateInstanceFromAndUnwrap(directory.FullName + "\Utility.Common.dll", 
typeof(PluginProxy).FullName));

在对LoadAssemblies的调用中,我将子appdomain作为参数传递:LoadDependencies(字符串pluginDirectoryPath,AppDomain pluginDomain);

这是不必要的,因为代理是在子域的上下文中。这解决了问题。

最新更新