2012-08-14 13 views
7

Estoy intentando cargar complementos en tiempo de ejecución y acceder a sus archivos de configuración. Las secciones de configuración en sus archivos de configuración se asignan a las clases derivadas de ConfigurationElementCollection, ConfigurationElement y ConfigurationSection. Los complementos y sus archivos de configuración están ubicados en una subcarpeta llamada "Complementos".Complementos MEF con sus propios archivos de configuración?

El problema es que parece que no puedo cargar los datos de configuración del complemento y deserializarlos en sus clases respectivas correctamente.

Aquí es un ejemplo de una configuración de plugin para el plugin EmailPlugin.dll:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <configSections> 
    <section name="EmailConfigurationSection" type="Foo.Plugins.EmailConfigurationSection, EmailPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowDefinition="Everywhere" allowExeDefinition="MachineToApplication" restartOnExternalChanges="true"/> 
    </configSections> 
    <EmailConfigurationSection server="192.168.0.10"> 
    <EmailSettings> 
     <add keyword="ERROR" 
        sender="[email protected]" 
        recipients="[email protected], [email protected]" 
        subject = "Error occurred" 
        body = "An error was detected" 
      /> 
    </EmailSettings> 
    </EmailConfigurationSection> 
</configuration> 

me carga esta utilizando este código:

private static System.Configuration.Configuration config = null; 
    public static System.Configuration.Configuration CurrentConfiguration 
    { 
     get 
     { 
      if (config == null) 
      { 
       Assembly assembly = Assembly.GetAssembly(typeof(EmailPlugin)); 
       string directory = Path.GetDirectoryName(assembly.CodeBase); 
       string filename = Path.GetFileName(assembly.CodeBase); 
       string assemblyPath = Path.Combine(directory, filename); 
       config = ConfigurationManager.OpenExeConfiguration(new Uri(assemblyPath).LocalPath); 
      } 

      return config; 
     } 
    } 

Esto da como resultado el error:

An error occurred creating the configuration section handler for EmailConfigurationSection: Could not load file or assembly 'EmailPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. 

Agregué esto al principio del archivo de configuración:

<runtime> 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
    <probing privatePath="Plugins"/> 
    </assemblyBinding> 
</runtime> 

Así que la DLL se encuentra, pero no no significa echados a la clase apropiada cuando intento de recuperarlo:

EmailConfigurationSection defaults = CurrentConfiguration.Sections["EmailConfigurationSection"] as EmailConfigurationSection; 

siempre vuelve nula. Sé que está mirando la ubicación y la configuración de archivo correcto porque puedo recuperar el XML utilizando este código:

var section = CurrentConfiguration.Sections["EmailConfigurationSection"]; 
string configXml = section.SectionInformation.GetRawXml(); 

Sin embargo, cuando intento deserializar con este código:

var serializer = new XmlSerializer(typeof(EmailConfigurationSection)); 
object result; 

EmailConfigurationSection defaults; 
using (TextReader reader = new StringReader(configXml)) 
{ 
    defaults = (EmailConfigurationSection)serializer.Deserialize(reader); 
} 

... consigo una excepción:

There was an error reflecting type 'Foo.Plugins.EmailConfigurationSection'. 

Este es el contenido de la InnerException:

You must implement a default accessor on System.Configuration.ConfigurationLockCollection because it inherits from ICollection. 

supongo que se está refiriendo a la EmailConfigElementCollection clase, pero entonces el mensaje no tiene sentido, porque esta clase tiene un descriptor de acceso por defecto:

public EmailConfigElement this[int index] 
    { 
     get 
     { 
      return (EmailConfigElement)BaseGet(index); 
     } 
     set 
     { 
      if (BaseGet(index) != null) 
      { 
       BaseRemoveAt(index); 
      } 
      BaseAdd(index, value); 
     } 
    } 

He utilizado este código con éxito en otros proyectos (incluso con DLL/configuraciones separadas), pero esta es la primera vez que intento usarlo con MEF. ¿Alguien sabe cuál es el problema o una solución adecuada?

estoy usando .NET 4.5

+0

he leído en alguna parte que sólo tiene que utilizar el ExecutingAssebly.Ubicación en su OpenExeConfiguration – Luke

+0

posible duplicado de [Secciones de configuración personalizadas en ensambles de exportación MEF] (http://stackoverflow.com/questions/4845801/custom-configuration-sections-in-mef-exporting-assemblies) –

+0

Esto no tanto un duplicado, pero una copia directa de http://social.msdn.microsoft.com/Forums/en-US/16df81ea-270b-47e2-bd30-877e0e32c88c/mef-plugins-with-theown-configuration-files –

Respuesta

5

i fijo esto con la siguiente modificación:

public static System.Configuration.Configuration CurrentConfiguration 
{ 
    get 
    { 
     if (config == null) 
     { 
      // Added the next bit 
      AppDomain.CurrentDomain.AssemblyResolve += (o, args) => 
      { 
       var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); 
       return loadedAssemblies.Where(asm => asm.FullName == args.Name) 
              .FirstOrDefault(); 
      }; 

      Assembly assembly = Assembly.GetAssembly(typeof(EmailPlugin)); 
      string directory = Path.GetDirectoryName(assembly.CodeBase); 
      string filename = Path.GetFileName(assembly.CodeBase); 
      string assemblyPath = Path.Combine(directory, filename); 
      config = ConfigurationManager.OpenExeConfiguration(new Uri(assemblyPath).LocalPath); 
     } 

     return config; 
    } 
} 

Tengo este de esta pregunta: ¿ Custom configuration sections in MEF exporting assemblies. De hecho, lo había intentado antes sin éxito.

El truco fue que tuve que mover la etiqueta de tiempo de ejecución para la parte inferior de la configuración XML:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <configSections> 
    <section name="EmailConfigurationSection" type="Foo.Plugins.EmailConfigurationSection, EmailPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowDefinition="Everywhere" allowExeDefinition="MachineToApplication" restartOnExternalChanges="true"/> 
    </configSections> 
    <EmailConfigurationSection server="255.255.255.1"> 
    <EmailSettings> 
     <clear /> 
     <add keyword="FOO" 
        sender="[email protected]" 
        recipients="[email protected]" 
        subject = "Foo occurred" 
        body = "Hello" 
      /> 
    </EmailSettings> 
    </EmailConfigurationSection> 
    <runtime> 
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
     <probing privatePath="Plugins"/> 
     </assemblyBinding> 
    </runtime> 
</configuration> 
+0

Ni siquiera necesita la sección de tiempo de ejecución en el archivo de configuración. –

Cuestiones relacionadas