我们使用Assembly.Loadfrom为我们的应用程序实现一个插件框架并加载插件程序集。然后我们使用GetTypes()并进一步检查每个插件文件的类型以获得支持的接口。
用户提供了插件的路径,我们循环浏览文件夹中的每个文件,看看它(插件)是否支持我们的插件界面。如果是,我们创建一个实例,如果不是,我们将移动到下一个文件。
我们从一个代码库(appA_1和appA_2)构建了两个版本的软件。
当插件由与插件文件同时构建的应用程序加载时,加载插件很有效。但是,如果我们构建appA_2并指向appA_1的插件文件夹,则在调用GetTypes()时会出现异常。
我们代码的基本版本是;
var pluginAssembly = Assembly.LoadFrom(FileName);
foreach (var pluginType in pluginAssembly.GetTypes())
{
我们收到“ReflectionTypeLoadException”异常。
这很令人担忧,因为我们希望我们的应用程序能够加载由任何人构建的任何插件的类型。有没有我们遗失的东西?
编辑: 在遍历LoaderExceptions之后,我们发现有一个文件libPublic.dll会生成System.IO.FileNotFoundException异常。奇怪的是,这个文件驻留在应用程序目录中,插件被引用到项目文件中。
编辑2: 在异常日志中,我们发现以下内容 “比较程序集名称导致不匹配:修订号”
答案 0 :(得分:15)
一些事情:
确保插件目录中没有重复的程序集(即您已经从app目录中加载到主应用程序中的程序集。)否则,当您加载插件时,它可能会加载同一程序集的附加副本。这可能导致有趣的例外,例如:
对象('MyObject'类型)不是'MyObject'类型。
如果您在实例化类型时遇到异常,则可能需要处理AppDomain.AssemblyResolve
:
private void App_Startup(object sender, StartupEventArgs e)
{
// Since we'll be dynamically loading assemblies at runtime,
// we need to add an appropriate resolution path
// Otherwise weird things like failing to instantiate TypeConverters will happen
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var domain = (AppDomain) sender;
foreach (var assembly in domain.GetAssemblies())
{
if (assembly.FullName == args.Name)
{
return assembly;
}
}
return null;
}
我意识到告诉CLR有点奇怪,为了解决一个程序集,找到我们用来解决的名称的程序集,但我看到没有它的奇怪事情发生了。例如,我可以从插件程序集中实例化类型,但如果我尝试使用TypeDescriptor.GetConverter
,它就找不到该类的TypeConverter
,即使它可以看到Converter
该课程属性。
查看您的编辑内容,这可能不是导致您当前异常的原因,但您在使用插件时可能会遇到这些问题。
答案 1 :(得分:2)
感谢这篇文章,我可以解决ReflectionTypeLoadException
中的UITypeEditor
问题。它是自定义类库的设计器程序集(在设计时使用的winforms智能标记),可扫描某些类型。
/// <summary>
/// Get the types defined in the RootComponent.
/// </summary>
private List<Type> getAssemblyTypes(IServiceProvider provider)
{
var types = new List<Type>();
try
{
IDesignerHost host = (IDesignerHost)provider.GetService(typeof(IDesignerHost));
ITypeResolutionService resolution = (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService));
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
foreach (var assembly in ((AppDomain)sender).GetAssemblies())
{
if (assembly.FullName == args.Name)
{
return assembly;
}
}
return null;
};
Type rootComponentType = resolution.GetType(host.RootComponentClassName, false);
types = rootComponentType.Assembly.GetTypes().ToList();
}
catch
{
}
return types;
}
答案 2 :(得分:0)
您收到的程序集版本不匹配。由于您的插件引用了此libPublic.dll
,因此您必须仔细对其进行版本控制,特别是不要修改其版本/构建/等。每次编译时的数字。