我正在尝试创建一个插件框架并通过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 assembly = pluginDomain.Load(AssemblyName.GetAssemblyName(file.FullName));
如果我不创建单独的appdomain并且只是将程序集加载到主appdomain中,那么创建实例就可以了。在我的情况下,Service的appdomain创建子appdomain。我想将插件的程序集加载到代理中。代理派生自MarshalByRefObject,因此我可以创建一个实例并从Windows服务端解包。
然后,服务将插件的加载和生命周期管理委托给代理。代理将通过方法参数获取子appdomain的上下文到LoadDependencies。
为什么不创建IPlugin实例的任何想法?
答案 0 :(得分:0)
我能够通过在代理级别推断域来解决此问题。在我的Windows服务中,我按照以下方式创建了插件代理实例:
IPluginProxy pluginProxy = IPluginProxy)
(pluginDomain
.CreateInstanceFromAndUnwrap(directory.FullName + "\\Utility.Common.dll",
typeof(PluginProxy).FullName));
在我对LoadAssemblies的调用中,我将子appdomain作为参数传递:
LoadDependencies(string pluginDirectoryPath,AppDomain pluginDomain
);
这是不必要的,因为代理位于子域的上下文中。这解决了这个问题。