2010-04-17 12 views
12

Implementamos un marco de plugin para nuestra aplicación y cargamos ensambles de plugins usando Assembly.Loadfrom. Luego usamos GetTypes() y examinamos los tipos con cada archivo de complemento para las interfaces compatibles.Assembly.GetTypes() - ReflectionTypeLoadException

El usuario proporciona una ruta de acceso a los complementos y recorremos cada uno de los archivos de la carpeta para ver si (el complemento) es compatible con nuestra interfaz de complementos. Si lo hace, creamos una instancia, si no, pasamos al siguiente archivo.

Construimos dos versiones de software a partir de una base de código (appA_1 y appA_2).

La carga de los complementos funciona bien cuando los complementos son cargados por la aplicación que se creó al mismo tiempo que el archivo de complemento. Sin embargo, si construimos appA_2 y apuntemos a la carpeta del complemento de la aplicación A_1, obtenemos una excepción cuando se llama a GetTypes().

Una versión básica de nuestro código es;

var pluginAssembly = Assembly.LoadFrom(FileName);  
foreach (var pluginType in pluginAssembly.GetTypes()) 
{ 

Recibimos la excepción "ReflectionTypeLoadException".

Esto es preocupante porque queremos que nuestra aplicación sea capaz de cargar los tipos de cualquier complemento, creado por cualquier persona. ¿Hay algo que nos falta?

EDIT: Después de iterar a través de LoaderExceptions, hemos descubierto que hay un solo archivo libPublic.dll que genera una excepción System.IO.FileNotFoundException. Lo extraño es que este archivo reside en el directorio de la aplicación y el complemento está referenciado al archivo del proyecto.

EDIT 2: En el registro de excepciones se encuentran los siguientes "Comparando el nombre de ensamblado como resultado la falta de coincidencia: Número de revisión"

+0

¿Cuál es el mensaje de excepción? ¿La excepción tiene una excepción interna? ¿Cuál es el mensaje de eso? – dtb

+0

¿Alguna razón por la que no está utilizando un marco existente como MEF? – dtb

+0

Aún puede crear problemas como este cuando usa MEF, aunque MEF es definitivamente útil para encargarse del trabajo. –

Respuesta

14

Un par de cosas:

  • Asegúrese de que usted don' t tienen ensamblajes duplicados en el directorio del complemento (es decir, ensamblajes que ya está cargando en la aplicación principal desde el directorio de la aplicación). De lo contrario, cuando carga el complemento, puede cargar una copia adicional del mismo ensamblaje. Esto puede conducir a excepciones divertidas como:

    El objeto (del tipo 'MyObject') no es del tipo 'MyObject'.

  • Si usted está recibiendo la excepción cuando una instancia de un tipo, es posible que necesite para manejar 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; 
    } 
    

Soy consciente de que es un poco extraño tener que decirle al CLR que, para resolver un ensamblaje, busque el ensamblado con el nombre que estamos usando para resolverlo, pero he visto cosas raras sin él. Por ejemplo, podría crear instancias de un ensamblado de complemento, pero si traté de usar TypeDescriptor.GetConverter, no encontraría el TypeConverter para la clase, aunque podría ver el atributo Converter en la clase.


En cuanto a las modificaciones, esto probablemente no es lo que está causando la excepción actual, aunque es posible que encuentre estos temas más adelante a medida que trabaja con sus complementos.

+1

¡Eres increíble! Tuve el problema de montaje duplicado, ¡así que esta respuesta me salvó! – JoeCool

+0

Esto resolvió mi problema también. Estaba cargando mi complemento que exponía un UITypeEditor y TypeConverters personalizados y mientras mis tipos se cargaban, los editores/convertidores no creaban instancias. Además, mis complementos estaban ubicados en un subdirectorio relativo a la aplicación, y curiosamente, si pongo el plugin en el mismo directorio que la aplicación de host funcionó bien. Esta solución ayudó a que los complementos funcionasen independientemente de su ubicación. – Mike

+0

Tiene toda la razón. Yo también estaba cargando un ensamblado en la aplicación secundaria que ya existe en la aplicación principal. Cuando cargué con AppDomain.CurrentDomain.GetAssemblies() obtuve el ensamblado y resolví el problema del cargador en GetTypes(). Muchas gracias :) @Dan Dryant –

0

Estás obteniendo una versión de ensamblaje no coincidente. Dado que sus complementos se refieren a este libPublic.dll, debe versionarlo con cuidado y, en particular, no superar su revisión/compilación/etc. números en cada compilación.

2

Gracias a esta publicación pude resolver el ReflectionTypeLoadException que obtenía en un UITypeEditor. Es un ensamblado de diseñador (una etiqueta inteligente winforms utilizada en tiempo de diseño) de una biblioteca de clases personalizada, que escanea para algunos tipos.

/// <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

¿De dónde viene IServiceProvider? ¿Cómo se puede obtener? – Pangamma

Cuestiones relacionadas