2010-04-17 67 views
12

我们使用Assembly.Loadfrom为我们的应用程序和加载插件程序集实现插件框架。然后我们使用GetTypes()并进一步检查支持接口的每个插件文件的类型。Assembly.GetTypes() - ReflectionTypeLoadException

插件的路径由用户提供,我们遍历文件夹中的每个文件以查看它(插件)是否支持我们的插件接口。如果是这样,我们创建一个实例,如果我们不移动到下一个文件。

我们从一个代码库(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

什么是异常信息?异常是否有内部异常?那是什么信息? – dtb 2010-04-17 12:19:07

+0

任何你没有使用MEF等现有框架的理由? – dtb 2010-04-17 12:19:37

+0

使用MEF时,您仍然可以创建类似这样的问题,尽管MEF对于处理繁琐的工作非常方便。 – 2010-04-17 12:27:43

回答

14

有几件事情:

  • 确保你不” t在插件目录中有重复的程序集(也就是说,你已经从应用程序目录中加载到主应用程序中的程序集)。否则,当您加载插件时,它可能会加载相同程序集的其他副本。这可能导致有趣的例外,如:

    对象(类型'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

你太棒了!我有重复组装问题,所以这个答案救了我! – JoeCool 2012-11-30 16:19:41

+0

这也解决了我的问题。我加载了我的插件,它暴露了一个自定义的UITypeEditor和TypeConverters,当我的类型加载时,编辑器/转换器不会实例化。 此外,我的插件位于相对于应用程序的子目录中,奇怪的是,如果我将插件放在与主机应用程序相同的目录中,它工作得很好。 此解决方案有助于使插件无论位于何处都能正常工作。 – Mike 2013-05-09 05:33:43

+0

你是绝对正确的。我也是在父应用程序中已经存在的子应用程序中加载程序集。当我加载AppDomain.CurrentDomain.GetAssemblies()时,我得到了程序集并解决了GetTypes()中的Loader问题。非常感谢:) @Dan Dryant – 2014-11-18 07:24:41

0

您正在装配版本不匹配。由于你的插件引用了这个libPublic.dll,所以你必须仔细地对它进行版本化,特别是不要修改它的修订版本/ build/etc。每个编译的数字。

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; 
} 
+0

IServiceProvider从哪里来?如何获得? – Pangamma 2017-11-27 22:39:35

相关问题