2012-08-14 15 views
7

Sto provando a caricare i plugin in fase di runtime e ad accedere ai loro file di configurazione. Le sezioni di configurazione nei loro file di configurazione sono associate a classi derivate da ConfigurationElementCollection, ConfigurationElement e ConfigurationSection. I plugin e i relativi file di configurazione sono ubicati in una sottocartella denominata "Plugin".Plugin MEF con i propri file di configurazione?

Il problema è che non riesco a caricare i dati di configurazione del plug-in e deserializzare correttamente le rispettive classi.

Ecco un esempio di configurazione plug-in per il 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> 

ho caricare questo utilizzando questo codice:

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

Ciò genera l'errore:

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. 

Ho aggiunto questo in cima al file di configurazione:

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

Quindi la DLL viene trovato, ma non non è idonea alla classe corretta quando provo a recuperarlo:

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

Si restituisce sempre null. Lo so che sta guardando il file di localizzazione e configurazione corretta perché posso recuperare il XML utilizzando questo codice:

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

Tuttavia, quando provo a deserializzare con questo codice:

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

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

... ottengo un'eccezione:

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

Questo è il contenuto della InnerException:

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

Penso che sia riferendosi alla EmailConfigElementCollection classe, ma poi il messaggio non ha senso, perché questa classe non ha una funzione di accesso di default:

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

Ho usato questo codice con successo in altri progetti (anche con DLL/configs separati), ma questa è la prima volta che cerco di usarlo con MEF. Qualcuno sa qual è il problema o una soluzione adeguata?

sto usando .NET 4.5

+0

ho letto da qualche parte che si può semplicemente utilizzare l'ExecutingAssebly.Posizione nella configurazione di OpenExeConfiguration – Luke

+0

possibile delle [sezioni di configurazione personalizzate negli assembly di esportazione MEF] (http://stackoverflow.com/questions/4845801/custom-configuration-sections-in-mef-exporting-assemblies) –

+0

Questo non tanto un duplicato, ma una copia diretta di http://social.msdn.microsoft.com/Forums/en-US/16df81ea-270b-47e2-bd30-877e0e32c88c/mef-plugins-with-the-own-configuration-files –

risposta

5

ho fissato questo con la seguente modifica:

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

ho ricevuto questo da questa domanda: Custom configuration sections in MEF exporting assemblies. In realtà avevo provato prima senza successo.

Il trucco era che ho dovuto spostare il tag runtime per la parte inferiore della configurazione 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

Non hai nemmeno bisogno di una sezione runtime nel file di configurazione. –

Problemi correlati