net - how to call configurationmanager c#
Sección de configuración personalizada de.NET: Configuration.GetSection arroja la excepción ''no se puede ubicar ensamblar'' (5)
@ g-makulik
Aquí tengo una copia de trabajo de lo que se hizo en un entorno real y comprobado que funciona.
En el archivo App.config:
<configSections>
<sectionGroup name="mySectionGroupName">
<section name="mySectionName" type="MyNamespace.MySectionHandler,MyNamespace" />
</sectionGroup>
</configSections>
....
<mySectionGroupName>
<mySectionName>
<add key="MyKey" value="MyKeyValue" />
</mySectionName>
</mySectionGroupName>
En la clase donde usas config:
....
Hashtable ht = ConfigurationManager.GetSection("mySectionGroupName/mySectionName") as Hashtable;
// when you call this, your handler will do what you want in there
string keyVal = ht["MyKey"] as String;
....
La clase responsable del manejo de la configuración:
public class MySectionHandler : DictionarySectionHandler
{
public override object Create(object parent, object context, XmlNode section)
{
// here do what you want with the value of "MyKey" - "MyKeyValue"
}
}
Espero que esto ayude
Creé una sección de configuración personalizada para un archivo DLL de complemento que almacena el XML .config en un archivo separado (de la aplicación ejecutable principal).
Aquí hay una muestra de la clase de sección personalizada:
using System;
using System.Configuration;
namespace PluginFramework.MyConfiguration
{
public class MyConfigurationSettings : ConfigurationSection
{
private Configuration _Config = null;
#region ConfigurationProperties
/// <summary>
/// A custom XML section for an application''s configuration file.
/// </summary>
[ConfigurationProperty("MyProjects", IsDefaultCollection = true)]
public MyProjectConfigurationCollection MyProjects
{
get { return (MyProjectConfigurationCollection) base["MyProjects"]; }
}
// ...
#endregion
/// <summary>
/// Private Constructor used by our factory method.
/// </summary>
private MyConfigurationSettings () : base () {
// Allow this section to be stored in user.app. By default this is forbidden.
this.SectionInformation.AllowExeDefinition =
ConfigurationAllowExeDefinition.MachineToLocalUser;
}
// ...
#region Static Members
/// <summary>
/// Gets the current applications <MyConfigurationSettings> section.
/// </summary>
/// <param name="ConfigLevel">
/// The <ConfigurationUserLevel> that the config file
/// is retrieved from.
/// </param>
/// <returns>
/// The configuration file''s <MyConfigurationSettings> section.
/// </returns>
public static MyConfigurationSettings GetSection (ConfigurationUserLevel ConfigLevel)
{
string appDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string localDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
System.Configuration.ExeConfigurationFileMap exeMap = new ExeConfigurationFileMap();
exeMap.ExeConfigFilename = System.IO.Path.Combine(appDataPath, @"MyCompany/MyPluginApp/Default.config");
exeMap.RoamingUserConfigFilename = System.IO.Path.Combine(appDataPath, @"MyCompany/MyPluginApp/Roaming.config");
exeMap.LocalUserConfigFilename = System.IO.Path.Combine(localDataPath, @"MyCompany/MyPluginApp/Local.config");
System.Configuration.Configuration Config = ConfigurationManager.OpenMappedExeConfiguration(exeMap,ConfigLevel);
MyConfigurationSettings myConfigurationSettings = null;
try {
myConfigurationSettings = (MyConfigurationSettings)Config.GetSection("MyConfigurationSettings");
}
catch (System.Exception ex) {
// ConfigurationErrorsException caught here ...
}
if (myConfigurationSettings == null) {
myConfigurationSettings = new MyConfigurationSettings();
Config.Sections.Add("MyConfigurationSettings", myConfigurationSettings); }
}
if(myConfigurationSettings != null) {
myConfigurationSettings._Config = Config;
}
return myConfigurationSettings;
}
#endregion
}
} // PluginFramework.MyConfiguration
El .config XML generado al guardar la primera vez se ve así:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- The exception complains about the following line (assembly attributes are compliant): -->
<section name="MyConfigurationSettings" type="PluginFramework.MyConfiguration.MyConfigurationSettings, PluginFramework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowDefinition="Everywhere" allowExeDefinition="MachineToLocalUser" />
</configSections>
<MyConfigurationSettings>
<!-- Config properties are serialized fine according MyConfigurationSettings
properties marked with the ConfigurationProperty attribute ... -->
<MyProjects>
<MyProjectConfiguration GUID="{4307AC92-8180-4686-9322-830312ED59AB}">
<!-- ... more complex configuration elements -->
</MyProjectConfiguration>
</MyProjects>
</MyConfigurationSettings>
</configuration>
Cuando se intenta cargar este XML usando Config.GetSection()
en ejecuciones posteriores, capturo una Config.GetSection()
ConfigurationErrorsException
en la línea marcada en el ejemplo XML, indicando que no se pudo MyPlugin
el ensamblado MyPlugin
o una de sus dependencias (perdone que No estoy publicando el mensaje de excepción original, pero lo tengo solo en alemán, y dudo que este texto sea útil aquí). La excepción interna proviene de System.IO
al intentar cargar el ensamblado y obtener una reflexión para resolver el tipo de clase ''MyConfigurationSettings''.
Para precisar la situación, el código de arriba se coloca dentro de una DLL de estructura (ensamblado), que a su vez es referenciada por la DLL de complemento real cargada desde la aplicación principal.
El siguiente diagrama UML ilustra las relaciones de varios componentes:
Después de mirar un poco sobre este problema, tengo la sensación de que es necesario darle un nombre fuerte (signo) al conjunto que exporta la clase MyConfigurationSettings
(es decir, PluginFramework
) y registrarlo con el GAC. No probé esto todavía, y me gustaría evitar este paso por varias razones (antes de saber si podría incluso ayudar y es la única opción para resolver el problema).
Así que aquí están las preguntas (lo siento, estoy colocando realmente 4 preguntas aquí, pero están tan fuertemente relacionadas que no tendría sentido crear preguntas separadas para ellos).
¿Podría resolver el problema de localización de fallas nombrando fuertemente el ensamble en cuestión y registrándolo con el GAC?
Es bastante estúpido que el ensamblaje del que se queja la administración de la configuración esté garantizado para cargarse (ya que llama a
Configuration.GetSection()
).
¿Existe alguna forma de registrar explícitamente elConfguration
o losConfguration
/Confguration
tipo de configuración apropiados con elConfigurationManager
o la claseConfguration
?También estoy interesado en obtener más información sobre el comentario de Hans Passant mencionando que esto podría ser un problema causado por la forma en que se carga el ensamblaje (principal) desde la aplicación principal. No tengo control sobre este mecanismo, y si esto causa este comportamiento inherentemente, me gustaría saber si hay una solución razonable.
Otra idea (si algo de lo anterior no muestra una forma) es administrar completamente un formato XML de configuración de forma nativa (usando soporte XML de des / serialización) y desde donde cargar y fusionar los archivos de configuración. Si esta es la opción más adecuada, ¿alguien puede dar buenos consejos sobre cómo hacer esto de manera eficiente (el código menos necesario para gestionar rutas y fusionar)?
Actualizar:
Dado que nadie parece ser capaz de dar más información sobre esta (s) pregunta (s) (las 2 respuestas realmente no me llevan más allá), estoy cambiando a la opción de 4., haciendo todo de forma manual.
Agregue un controlador de eventos para AppDomain.CurrentDomain.AssemblyResolve
. Esto debería funcionar para la option 2
.
Estoy teniendo el mismo problema y hasta ahora no he encontrado una solución totalmente sati fi cante. Nuestras cargas de aplicaciones se compilan con una referencia a una clase de sección de configuración definida en un ensamblaje dedicado. La aplicación está vinculada a un ensamblado con un nombre fuerte, pero más adelante cuando el cargador de configuración intenta leer la configuración, los rastros de fusión muestran que intenta cargar un nombre débil del mismo ensamblaje. Por algún motivo, .net no ve que es el mismo ensamblado y arroja una excepción System.IO.FileNotFound. En la solución de trabajo en mi caso es hacer referencia a nombres fuertes en la configuración.
También he notado un comportamiento extraño: una vez que un ensamblado es cargado por .net "cargador de configuración" con un nombre fuerte, ¡las referencias adicionales con un nombre débil realmente tienen éxito! Por alguna razón, el marco "recuerda" que el nombre débil se refiere a la misma asamblea.
¡Cualquier noticia del problema de tu parte sería interesante!
Intenté eso también, pero nunca lo hice funcionar así. Acabo de pensar que cargar .config automáticamente no funciona para .dll solo para .exe. Luego me di por vencido y decidí que sería más fácil simplemente cargar el archivo .config manualmente. Puede ver el código completo aquí: https://github.com/GeertBellekens/Enterprise-Architect-Toolpack/blob/master/EANavigator/NavigatorSettings.cs Esta es la parte más relevante:
public NavigatorSettings() {
Configuration roamingConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming);
// the roamingConfig now get a path such as C:/Users/<user>/AppData/Roaming/Sparx_Systems_Pty_Ltd/DefaultDomain_Path_2epjiwj3etsq5yyljkyqqi2yc4elkrkf/9,_2,_0,_921/user.config
// which I don''t like. So we move up three directories and then add a directory for the EA Navigator so that we get
// C:/Users/<user>/AppData/Roaming/GeertBellekens/EANavigator/user.config
string configFileName = System.IO.Path.GetFileName(roamingConfig.FilePath);
string configDirectory = System.IO.Directory.GetParent(roamingConfig.FilePath).Parent.Parent.Parent.FullName;
string newConfigFilePath = configDirectory + @"/Geert Bellekens/EANavigator/" + configFileName;
// Map the roaming configuration file. This
// enables the application to access
// the configuration file using the
// System.Configuration.Configuration class
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = newConfigFilePath;
// Get the mapped configuration file.
currentConfig = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
// merge the default settings
this.mergeDefaultSettings();
}
Accediendo a una propiedad de configuración:
public bool trackSelectedElement
{
get {
bool result;
if(bool.TryParse(this.currentConfig.AppSettings.Settings["trackSelectedElement"].Value, out result)) {
return result;
}
else {
return true;
}
}
set {
this.currentConfig.AppSettings.Settings["trackSelectedElement"].Value = value.ToString();
}
}
Lo que intenta hacer no es compatible con .NET Framework.
Primero, tiene sentido que tu plugin.dll esté configurado por aplicación de host (.exe o web) que lo está usando (por eso es configurable)
2º - Los archivos de configuración soportan la herencia (ej: machine.config -> applicationHost.config -> web.config). Para lo que están diseñados. Su configuración fuera de ruta no funcionaría correctamente a ese respecto.
Por lo tanto, si necesita una configuración personalizada para una parte de la aplicación o un complemento, no sigue los conceptos de .config, haga un archivo XML estándar o jsonconfig y cargue las configuraciones desde allí.