Section de configuration personnalisée: impossible de charger le fichier ou l’assembly

J’ai beaucoup de difficulté à accéder à une section de configuration personnalisée dans mon fichier de configuration.

Le fichier de configuration est en cours de lecture à partir d’un fichier .dll chargé en tant que plug-in. J’ai créé la configuration et le code nécessaire à l’aide du complément VS de Configuration Section Designer .

L’espace de nom est ‘ImportConfiguration’. La classe ConfigurationSection est ‘ImportWorkflows’. L’assembly est ImportEPDMAddin.

Le xml:

 

Chaque fois que j’essaie de lire dans la configuration, j’obtiens l’erreur:

Une erreur s’est produite lors de la création du gestionnaire de section de configuration pour importWorkflows: Impossible de charger le fichier ou l’assembly ‘ImportEPDMAddin.dll’ ou l’une de ses dépendances. Le système ne peut pas trouver le fichier spécifié.

La dll ne résidera pas dans le même répertoire que l’exécutable car le logiciel qui charge le plugin place la dll et ses dépendances dans son propre répertoire. (Je ne peux pas contrôler ça.)

J’ai modifié le code de l’instance singleton comme suit:

 ssortingng path = System.Reflection.Assembly.GetCallingAssembly().CodeBase; path = path.Replace("file:///", ""); System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenExeConfiguration(path); return configuration.GetSection(ImportWorkflowsSectionName) as ImportConfiguration.ImportWorkflows; 

J’ai également essayé d’utiliser un simple NameValueFileSectionHandler, mais je reçois une exception disant qu’il ne peut pas charger le fichier ou l’assembly ‘System’.

J’ai lu de nombreux articles de blog et articles et il semble qu’il soit possible de lire un fichier de configuration pour une dll, mais je ne peux tout simplement pas le faire fonctionner. Des idées? Merci.

Malheureusement, l’assembly ImportEPDMAddin résider dans le même dossier que votre exécutable, dans le dossier du framework .Net associé au framework .Net que vous utilisez (par exemple, C: \ Windows \ Microsoft.NET \ Framework \ v2.0.50727), ou enregistré dans le Global Assembly Cache.

La seule autre option est que, si vous connaissez le chemin d’access à l’assembly contenant la classe de définition du gestionnaire de configuration, vous pouvez le charger sans référence avec quelque chose comme:

 //Class global private Assembly configurationDefiningAssembly; protected TConfig GetCustomConfig(ssortingng configDefiningAssemblyPath, ssortingng configFilePath, ssortingng sectionName) where TConfig : ConfigurationSection { AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ConfigResolveEventHandler); configurationDefiningAssembly = Assembly.LoadFrom(configDefiningAssemblyPath); var exeFileMap = new ExeConfigurationFileMap(); exeFileMap.ExeConfigFilename = configFilePath; var customConfig = ConfigurationManager.OpenMappedExeConfiguration(exeFileMap, ConfigurationUserLevel.None); var returnConfig = customConfig.GetSection(sectionName) as TConfig; AppDomain.CurrentDomain.AssemblyResolve -= ConfigResolveEventHandler; return returnConfig; } protected Assembly ConfigResolveEventHandler(object sender, ResolveEventArgs args) { return configurationDefiningAssembly; } 

Assurez-vous de gérer l’événement AssemblyResolve, car cela lève une exception sans lui.

Dans le fichier de configuration de vos applications principales, ajoutez ce qui suit (où plugins est le dossier à partir duquel votre assemblage doit être chargé. Vous pouvez utiliser plusieurs chemins séparés par des virgules.

      

Tiré de http://msdn.microsoft.com/en-us/library/823z9h8w%28v=vs.90%29.aspx

Pour approfondir l’excellente réponse de AJ, voici une classe personnalisée destinée à aider à la surcharge liée à l’enregistrement et à la suppression de l’événement global.

 public sealed class AddinCustomConfigResolveHelper : IDisposable { public AddinCustomConfigResolveHelper( Assembly addinAssemblyContainingConfigSectionDefinition) { Contract.Assert(addinAssemblyContainingConfigSectionDefinition != null); this.AddinAssemblyContainingConfigSectionDefinition = addinAssemblyContainingConfigSectionDefinition; AppDomain.CurrentDomain.AssemblyResolve += this.ConfigResolveEventHandler; } ~AddinCustomConfigResolveHelper() { this.Dispose(false); } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool isDisposing) { AppDomain.CurrentDomain.AssemblyResolve -= this.ConfigResolveEventHandler; } private Assembly AddinAssemblyContainingConfigSectionDefinition { get; set; } private Assembly ConfigResolveEventHandler(object sender, ResolveEventArgs args) { // often the name provided is partial...this will match full or partial naming if (this.AddinAssemblyContainingConfigSectionDefinition.FullName.Contains(args.Name)) { return this.AddinAssemblyContainingConfigSectionDefinition; } return null; } } 

Je suggérerais de créer une instance dans une instruction using, comme ceci:

 // you'll need to populate these two variables var configuration = GetConfiguration(); var assembly = GetAssemblyContainingConfig(); using(new AddinCustomConfigResolveHelper(assembly)) { return (MyConfigSection)configuration.GetSection("myConfigSection"); } 

Pourriez-vous vérifier que les chemins de vérification sont configurés correctement dans le fichier de configuration de votre application hôte? Il est possible qu’une référence nécessaire ne soit pas chargée dans votre domaine d’application actuel.

Reliure d’assemblage -> Palpage

Vous êtes-vous assuré que la DLL est chargée en premier? Peut-être avec Assembly.LoadFile("PATH") ?

Si vous ne parvenez pas à faire fonctionner correctement les classes de System.Configuration, vous pouvez toujours avoir recours à XmlDocument pour parsingr manuellement le fichier de configuration. Utilisez XPaths pour obtenir plus facilement les données. Par exemple (en supposant que votre variable de chemin ci-dessus):

 var document = new XmlDocument(); document.Load(path); var node = document.SelectSingleNode("configuration/importWorkflows/add[@name='KEY']"); // Do whatever with node 

J’ai essayé la réponse de AJ, avec le supplément de rileywhite, mais j’ai trouvé que cela ne fonctionnait pas pour moi.

Dans mon scénario, la classe ConfigurationSection personnalisée se trouvait déjà dans l’assembly en cours d’exécution et son chargement provoque un débordement de stack. Je ne voulais pas non plus le mettre dans GAC, même si cela résolvait le problème signalé par le PO.

En fin de compte, j’ai trouvé que cela fonctionnait assez bien pour mon objective. Peut-être que d’autres le trouveront utile:

 public class CustomConfigurationSection : ConfigurationSection { public CustomConfigurationSection() { var reader = XmlReader.Create(); reader.ReadToDescendant("CustomConfigurationSection"); base.DeserializeElement(reader,false); } //  } 

Doit utiliser la chaîne de caractères pleinement qualifiée de mon module module / plugin, qui se trouve dans un répertoire de vérification, de sorte qu’elle puisse être localisée. En utilisant EntityFramework comme exemple …

Incorrect:

 type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework" 

Correct

 type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"