Usar ConfigurationManager para cargar la configuración desde una ubicación arbitraria

124

Estoy desarrollando un componente de acceso a datos que se usará en un sitio web que contiene una combinación de páginas ASP y ASP.NET clásicas, y necesito una buena forma de administrar sus configuraciones.

Me gustaría usar un personalizado ConfigurationSection, y para las páginas ASP.NET esto funciona muy bien. Pero cuando se llama al componente a través de la interoperabilidad COM desde una página ASP clásica, el componente no se ejecuta en el contexto de una solicitud ASP.NET y, por lo tanto, no tiene conocimiento de web.config.

¿Hay alguna manera de decirle ConfigurationManageral solo cargar la configuración desde una ruta arbitraria (por ejemplo, ..\web.configsi mi ensamblaje está en la /bincarpeta)? Si es así, creo que mi componente puede recurrir a eso si el valor predeterminado ConfigurationManager.GetSectionvuelve nulla mi sección personalizada.

¡Cualquier otro enfoque para esto sería bienvenido!

Mike Powell
fuente
2
Ver stackoverflow.com/questions/3912727/…
Ohad Schneider el

Respuestas:

124

Prueba esto:

System.Configuration.ConfigurationFileMap fileMap = new ConfigurationFileMap(strConfigPath); //Path to your config file
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
Ismaeel
fuente
¿Cómo puedo obtener programáticamente el valor strConfigPath para mi aplicación ASP.NET WebForms alojada en sub.domain.com/virtualDir2 y la ruta C: \ Portals \ App1 \ v2 y el archivo de configuración en C: \ Portals \ App1 \ v2 \ web.config ?
Kiquenet
1
@Kiquenet: El punto de la pregunta es que strConfigPath es una ubicación arbitraria . En otras palabras, usted decide cuál es la ruta, en lugar de confiar en el marco para intentar cargar un archivo de configuración desde su ubicación convencional. Supongo que Server.MapPath le daría la ubicación absoluta para cualquier archivo dentro de su solución.
Ismael el
1
Quizásvar config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~/web.config");
Kiquenet
@Kiquenet definitivamente.
Ucho
66

Otra solución es anular la ruta predeterminada del archivo de configuración del entorno.

Me parece la mejor solución para la carga de archivos de configuración de ruta no trivial, específicamente la mejor manera de adjuntar archivos de configuración a dll.

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", <Full_Path_To_The_Configuration_File>);

Ejemplo:

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", @"C:\Shared\app.config");

Más detalles se pueden encontrar en este blog .

Además, esta otra respuesta tiene una solución excelente, completa con código para actualizar la configuración de la aplicación y un IDisposableobjeto para restablecerla a su estado original. Con esta solución, puede mantener el ámbito de configuración de la aplicación temporal:

using(AppConfig.Change(tempFileName))
{
    // tempFileName is used for the app config during this context
}
Tecnologías de Saturno
fuente
1
Esto también funciona para cargar archivos web.config. Lo uso para cargar un web.config en lugar de app.config para una aplicación de consola relacionada con la tarea. ;)
James Wilkins
1
Esto (y las otras respuestas aquí) no me funcionan. Había agregado el código en la función program.cs: Main (). Mi configuración contiene una redirección de versión de ensamblaje (consulte stackoverflow.com/questions/30165393/… ) pero la redirección no afecta cuando la configuración se cambia manualmente.
Vortex852456
1
¿Utilizaste "APP_CONFIG_FILE"?
Saturn Technologies
40

La respuesta de Ishmaeel generalmente funciona, sin embargo, encontré un problema, que es que el uso OpenMappedMachineConfigurationparece perder los grupos de secciones heredados de machine.config. Esto significa que puede acceder a sus propias secciones personalizadas (que es todo lo que el OP quería), pero no a las secciones normales del sistema. Por ejemplo, este código no funcionará:

ConfigurationFileMap fileMap = new ConfigurationFileMap(strConfigPath);
Configuration configuration = ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
MailSettingsSectionGroup thisMail = configuration.GetSectionGroup("system.net/mailSettings") as MailSettingsSectionGroup;  // returns null

Básicamente, si pone un reloj en el configuration.SectionGroups, verá que system.net no está registrado como SectionGroup, por lo que es prácticamente inaccesible a través de los canales normales.

Hay dos formas que encontré para evitar esto. El primero, que no me gusta, es volver a implementar los grupos de secciones del sistema copiándolos de machine.config en su propio web.config, por ejemplo

<sectionGroup name="system.net" type="System.Net.Configuration.NetSectionGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
  <sectionGroup name="mailSettings" type="System.Net.Configuration.MailSettingsSectionGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <section name="smtp" type="System.Net.Configuration.SmtpSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  </sectionGroup>
</sectionGroup>

No estoy seguro de que la aplicación web se ejecute correctamente después de eso, pero puede acceder a la sección Grupos correctamente.

La segunda solución es abrir su web.config como una configuración EXE, que probablemente esté más cerca de su función prevista de todos modos:

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = strConfigPath };
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
MailSettingsSectionGroup thisMail = configuration.GetSectionGroup("system.net/mailSettings") as MailSettingsSectionGroup;  // returns valid object!

Me atrevo a decir que ninguna de las respuestas proporcionadas aquí, ni la mía ni la de Ishmaeel, están utilizando estas funciones como pretendían los diseñadores de .NET. Pero, esto parece funcionar para mí.

Gavin
fuente
1
También puede usar la sobrecarga ConfigurationManager.OpenExeConfiguration (String) para el mismo propósito. Ver: codeproject.com/KB/dotnet/mysteriesofconfiguration3.aspx#t2_1
Ohad Schneider el
10

Además de la respuesta de Ishmaeel, el método OpenMappedMachineConfiguration()siempre devolverá un Configurationobjeto. Por lo tanto, para verificar si se cargó, debe verificar la HasFilepropiedad donde verdadero significa que proviene de un archivo.

Joseph Daigle
fuente
9

¡La respuesta aceptada es incorrecta!

Lanza la siguiente excepción al acceder a la propiedad AppSettings:

No se puede convertir el objeto del tipo 'System.Configuration.DefaultSection' para escribir 'System.Configuration.AppSettingsSection'.

Aquí está la solución correcta:

System.Configuration.ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = "YourFilePath";
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
Jacob
fuente
1
Sí, esta es definitivamente la respuesta correcta. Gracias por publicar tu respuesta.
Fabio Milheiro
Creo que System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration es aún más correcto, pero no está disponible para .NET Core, por lo que en este caso esta respuesta parece funcionar.
Risord
4

Proporcioné los valores de configuración a Word alojado .nET Compoent de la siguiente manera.

Un componente de biblioteca de clases .NET que se llama / aloja en MS Word. Para proporcionar valores de configuración a mi componente, creé winword.exe.config en la carpeta C: \ Archivos de programa \ Microsoft Office \ OFFICE11. Debería poder leer los valores de configuración como lo hace en .NET tradicional.

string sMsg = System.Configuration.ConfigurationManager.AppSettings["WSURL"];
Iftikhar Ali
fuente
1

Para ASP.NET, use WebConfigurationManager:

var config = WebConfigurationManager.OpenWebConfiguration("~/Sites/" + requestDomain + "/");
(..)
config.AppSettings.Settings["xxxx"].Value;
Javier Cañon
fuente
0

Usar procesamiento XML:

var appPath = AppDomain.CurrentDomain.BaseDirectory;
var configPath = Path.Combine(appPath, baseFileName);;
var root = XElement.Load(configPath);

// can call root.Elements(...)
JoelFan
fuente