我有一个winforms项目,允许未来的开发人员为appplication创建插件。 Winforms应用程序包含开发人员在创建插件时需要引用的所有接口和类。因此,当我创建插件时,我引用主应用程序的dll。
初始化主应用程序时,我创建一个单独的域来加载所有插件dll。我这样做的原因是我可以使用appDomain.unload调用随意删除插件,然后重新加载剩余的插件。
当我在VS2008中启动Debug我的应用程序初始化时,它会加载第一个插件,但是我得到一个警告,我需要加载我用来引用主应用程序接口的插件引用的dll。
现在我的问题是在将dll加载到子域之前我可以使用主应用程序的接口来创建它们的实例,以便插件用作参考吗?如果是,我该怎么做?任何帮助表示赞赏。
这是我的应用程序的PluginManager,它加载了app.config文件中的插件。我只保留了我需要帮助的方法和类的构造函数。
在这个类中,我正在读取app.cinfig文件并将customConfigSection的内容放入customConfig集合中。当调用loadAssemblies时,我遍历集合并将程序集添加到构造函数中创建的子域。
using System;
using MyApp.Data;
using MyApp.Interfaces;
using MyApp.Variables;
using System.Reflection;
namespace MyApp.Core
{
/// <summary>
/// This object helps the application manage its scalable and extended components
/// called plugins.
/// </summary>
public class PlugInManager
{
public PlugInManager()
{
//appDomain setup
pluginDomainSetup = new AppDomainSetup();
pluginDomainSetup.ApplicationBase = pluginDomainLocation;
pluginDomainSetup.DisallowCodeDownload = true;
string pluginApplicationName = string.Format(MAOIE.Variables.Constants.PLUGIN_APPLICATION_NAME);
//appDomain creation
pluginDomain = AppDomain.CreateDomain(pluginApplicationName, null, pluginDomainSetup);
//Loads the values located in the config file
LoadPluginConfiguration();
//Load any existing plugins in the directories
LoadAssemblies();
}
private void LoadAssemblies()
{
//I"m thinking I should add this the referenced libraries to the subdomain here.
//AppDomain.Unload(this.pluginDomain);
string reference = GetReferencePath();
reference += Variables.Constants.MAOIE_CORE_DLL;
//Iterate through the items found in the app.config file.
foreach (PluginSetting item in this.PluginConfigSettings.PluginItems)
{
string file = GetPluginPath();
file += item.PluginFileName;
switch (item.PluginType)
{
case Constants.PluginType.pluginTypeA:
pluginDomain.CreateInstanceFrom(file, item.PluginAssemblyType);
IPluginTypeA ia = (IPluginTypeA)Activator.CreateInstance(pluginDomain, item.PluginFileName, item.PluginAssemblyType);
Plugable<IPluginTypeA> pia = new Plugable<IPluginTypeA>();
pia.ConcreteClass = ia;
pia.Core = false;
//collection used throughout the application
this.aerodynamicAnalyzers.Add(pia);
return;
case Constants.PluginType.pluginTypeB:
pluginDomain.CreateInstanceFrom(file, item.PluginAssemblyType);
IPluginTypeB ib = (IPluginTypeB)Activator.CreateInstance(pluginDomain, item.PluginFileName, item.PluginAssemblyType);
Plugable<IPluginTypeB> pib = new Plugable<IPluginTypeB>();
piB.ConcreteClass = ib;
pim.Core = false;
//collection used throughout the application
this.missionAnalyzers.Add(pib);
return;
case Constants.PluginType.pluginTypeC:
pluginDomain.CreateInstanceFrom(file, item.PluginAssemblyType);
IPluginTypeC ic = (IPluginTypeC)Activator.CreateInstance(pluginDomain, item.PluginFileName, item.PluginAssemblyType);
Plugable<IPluginTypeC> pic = new Plugable<IPluginTypeC>();
pic.ConcreteClass = ic;
pic.Core = false;
//collection used throughout the application
this.pluginTypeCs.Add(pio);
return;
case Constants.PluginType.pluginTypeD:
pluginDomain.CreateInstanceFrom(file, item.PluginAssemblyType);
IPluginTypeD id = (IPluginTypeD)Activator.CreateInstance(pluginDomain, item.PluginFileName, item.PluginAssemblyType);
Plugable<IPluginTypeD> piw = new Plugable<IPluginTypeD>();
pid.ConcreteClass = id;
pid.Core = false;
//collection used throughout the application
this.pluginTypeDs.Add(pid);
return;
}
}
}
}
//end PlugInManager
}
//end namespace MyApp.Core
下一课是单独项目中的单个课程。我正在使用一个空插件来测试我的pluginManager的LoadAssemblies方法。我添加了一个对MyApp.Core.dll的引用,它由visual studio复制到这个项目的bin目录中。我需要这个来实现主应用程序中的接口。
这个类只是getter和setter加上一个空方法。
///////////////////////////////////////////////////////////
// testPluginA.cs
// used as an empty class to test the import of plugins into the main application.
///////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Text;
using MyApp.Core;
namespace testPluginA
{
public class testPluginA : MyApp.Interfaces.IPluginTypeA
{
public testPluginA()
{
}
private string name = "testPluginA";
private string desc = "Test Plugin A 1";
/// <summary>
/// The description of the plugin.
/// </summary>
public string Description { get{return this.desc;} }
/// <summary>
/// The display name of the plugin.
/// </summary>
public string FriendlyName { get{return this.name;} }
/// <summary>
///
/// </summary>
/// <param name="mp"></param>
public void Optimize(MyApp.Data.Car car)
{
//does nothing
}
答案 0 :(得分:2)
将插件加载到同一个域中,但要使它们实现一个公开Load
和Unload
方法的接口。 Unload
方法的公共合同至少是以下内容:
Dispose()
适用且null
所有对插件使用的资源的引用,以便GC可以[在将来的某个时间点]收集它们Load
是有效操作您的插件编写者有责任满足此合同。无论如何,您正在加载他们的代码以执行 - 如果他们违反了规则将出错,无论您是否将它们放在他们自己的AppDomain中。
编辑:就个人而言,我认为Managed Extensibility Framework 至少至少值得检查(并在使用它时满足您的需求),因为您在构建API时会有所不同。