¿Cómo leer y escribir parámetros de configuración en C#?
Publicado por johnbarquin en Abril 10, 2009
Toda aplicación que se respete debe incluir algún modo de persistir su configuración de una ejecución a la otra. Aún si esto no fuera necesario, es buena práctica no codificar dentro de la aplicación los valores que utilizará por defecto, o parámetros que cambian de una máquina a otra, por ejemplo, las cadenas de conexión a las bases de datos. En C# esto es super sencillo de lograr a partir de:
- Archivos de configuración estilo XML: en aplicaciones web se nombran “web.config” y en desktop “app.config”. En general, contienen un conjunto de pares parámetro-valor.
- Un grupo de funciones suministradas por el namespace System.Configuration.
Ejemplo de archivo de configuración:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings file="">
<clear />
<add key="miParametro" value="Mi valor" />
</appSettings>
</configuration>
Paso a paso:
- Añadir al proyecto una referencia a “System.Configuration” (Project -> Add Reference …).
- Añadir al código: “using System.Configuration”.
- Para leer un parámetro de configuración:
string miValor = ConfigurationManager.AppSettings["miParametro"];
- Para añadir un parámetro nuevo al archivo de configuración:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings.Add("miParametro", "Mi valor");
config.Save(ConfigurationSaveMode.Modified);
- Para modificar y persistir un parámetro de configuración:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); config.AppSettings.Settings["miParametro"].Value = "Mi valor"; config.Save(ConfigurationSaveMode.Modified);
Nota: en las operaciones de escritura (añadir y modificar) desde Visual Studio, el instinto nos lleva inmediatamente a revisar los cambios en el archivo original ”app.config” (asumiendo aplicación desktop). Este contiene los parámetros iniciales de configuración; el archivo que se modifica realmente es nombre_de_app.exe.Config que está en la carpeta bin\Debug que es el archivo real de configuración cuando se distribuye la aplicación.
Aquí he mostrado el método de trabajo más sencillo con configuraciones en .NET. Los archivos de configuración pueden llegar a ser muy sofisticados permitiendo la categorización de los parámetros en secciones, por ejemplo <connectionStrings> para las cadenas de conexión a bases de datos. Realmente, los ejemplos anteriores operan sobre los parámetros correspondientes a una sección específica <appSettings>, lo cual es suficiente para una gran mayoría de las aplicaciones prácticas.
Ingeleo escribió
Muy buena esa la usare, en mi soft actual…. pero tengo por aca una propia mia arraigandome al pasado de vb5 y 6, jajaja
//**** hice una clase
// declaro esto
IniClass Ini = new IniClass();
//para usarla uso estas funciones
//salvar
Ini.SaveSetting(“C:\test.config”, “Key”, “Value”, “Data”);
//esto genera este texto dentro del archivo
// [KEY]
// Value=data
//Ahora Leemos
string ValorEnElConfig = Ini.GetSetting(“c:\test.config”, “Key”, “value”,”Default”);
// valor = Data // si existe esa key y ese value dentro de esa key de lo contrario devuelve Default
//solo el valor de DATA es case sencitive, el de key y value no
//****************************************************************************
using System;
using System.IO;
class IniClass
{
public bool SaveSetting(string FileName, string Key, string Value, string Data) //static void Main(string[] args)
{
string IniData=”";
try
{
//primero que nada leo el archivo a ver si que datos tiene
StreamReader streamReader = new StreamReader(@FileName);
IniData = streamReader.ReadToEnd();
streamReader.Close();
}
catch
{}
if (IniData != “”)
{//tiene datos lo proceso
//busco ese key
int x = IniData.ToUpper().IndexOf(“[" + Key.ToUpper() + "]“,0);
if (x != -1)
{// encontre ese key busco ahora ese value
x += Key.Length + 4; // muevo x al final del ky 2 por [] y 2 por \r\n,justo ahi
int z = x;
x = IniData.ToUpper().IndexOf(Value.ToUpper(),z);
if (x != -1)
{// encontre ese value ahora busco si tiene ese data
// leo el data actual para luego remplazarlo
z = x + Value.Length + 1; // 1 por el =
x = IniData.IndexOf(“\r\n”,z);
if (x == -1) { return (false); } // error no encontre el dato
string dataActual = IniData.Substring(z, x – z);
if (dataActual == Data)
{
return (true); // me salgo no tengo que salvar es el mismo dato a guardar
}
else
{ // actualizo el dato
string inicio = IniData.Substring(0, z);
string final = IniData.Substring(x, IniData.Length – x);
if (final.Substring((final.Length-2), 2) == “\r\n”) { final = final.Substring(0, final.Length – 2); }
IniData = inicio + Data + final;
}
}
else
{ // no encontre ese value agrego ese value para ese key
// guardo las 2 partes principio y final inserto el texto y luego lo sumo todo
string inicio = IniData.Substring(0, z);
string final = IniData.Substring(z, IniData.Length – z);
if (final.Substring((final.Length – 2), 2) == “\r\n”) { final = final.Substring(0, final.Length – 2); }
if(final !=”") // hay mas datos al final del archivo
{
IniData = inicio + Value + “=” + Data + “\r\n” + final;
}
else
{ // no hay mas datos al final del archivo para que sumar final, elimino el dbl enter
IniData = inicio + Value + “=” + Data;
}
}
}
else
{ // no encontre ese key lo agrego al final de archivo
IniData += “\r\n[" + Key.ToUpper() + "]\r\n” + Value + “=” + Data;
}
}
else
{// no tiene datos
IniData = “[" + Key.ToUpper() + "]\r\n” + Value + “=” + Data;
}
try
{ //ahora salvo el ini nuevamente
// create a writer and open the file
TextWriter tw = new StreamWriter(@FileName);
//quito el enter al principio
if (IniData.Substring(0, 2) == “\r\n”) { IniData = IniData.Substring(2, IniData.Length – 2); }
// write a line of text to the file
tw.WriteLine(IniData);
// close the stream
tw.Close();
return (true);
}
catch
{
return (false);
}
}
public string GetSetting(string FileName, string Key, string Value, string Default)
{
string IniData = “”;
try
{
//primero que nada leo el archivo a ver si que datos tiene
StreamReader streamReader = new StreamReader(@FileName);
IniData = streamReader.ReadToEnd();
streamReader.Close();
}
catch
{
return (Default);
}
if (IniData != “”)
{//tiene datos lo proceso
//busco ese key
int x = IniData.ToUpper().IndexOf(“[" + Key.ToUpper() + "]“, 0);
if (x != -1)
{// encontre ese key busco ahora ese value
x += Key.Length + 4; // muevo x al final del ky 2 por [] y 2 por \r\n,justo ahi
int z = x;
x = IniData.ToUpper().IndexOf(Value.ToUpper(), z);
if (x != -1)
{// encontre ese value ahora busco si tiene ese data
// leo el data actual para luego remplazarlo
z = x + Value.Length + 1; // 1 por el =
x = IniData.IndexOf(“\r\n”, z);
if (x == -1) { return (Default); } // error no encontre el dato
return (IniData.Substring(z, x – z)); // devuelvo el valor que busco
}
else
{ // no encontre ese value agrego ese value para ese key
return (Default);
}
}
else
{ // no encontre ese key lo agrego al final de archivo
return (Default);
}
}
else
{// no tiene datos
return (Default);
}
}
}
//*******************************************************************************
johnbarquin escribió
Hola Ingeleo, buen ejercicio de programación
, solo una observación, usando app.config y las funciones de System.Configuration, además de ahorrar esfuerzo de codificación, implica el uso de estándares y esto siempre es aconsejable. A partir de .NET, van quedando atrás las configuraciones por archivos .INI y por el registro de Windows.
Carlos escribió
Gracias por el código, me ha ayudado mucho ya que soy principiante en C#.
Lo que te quiero preguntar es como leo las variables de tipo string que creo en la lengüeta Setting de la propiedades del proyecto.
Muchas gracias
Carlos Pizzi
johnbarquin escribió
Si creaste de esta forma un parámetro llamado “miParametro”, puedes leerlo asi:
string valor = Settings.Default.miParametro;
Settings es una “concha” que crea propiedades tipificadas para cada parámetro que se define en tiempo de diseño. Si el parámetro fuera de tipo int, por ej. “altura” se lee asi:
int altura = Settings.Default.altura;
Con ConfigurationManager se leeria asi:
int altura = Convert.ToInt32(ConfigurationManager.AppSettings["altura"]);
Observa el XML generado en App.config con Settings para que veas las diferencias de sintaxis entre ambos métodos.
Saludos, John
Carlos escribió
Gracias John, tu ayuda me ha sido de mucha utilidad.
ariel escribió
hola estimado estoy tratando de usar tu clase pero me marca mo error esta linea cuando quiere hacer una resta.
return (IniData.Substring(z, (x – z))); // devuelvo el valor que busco
pint ade rojo el – . tenes idea que es?
graciassss
camila escribió
hola, hice la programacion como pusistes para escribir en el app.config, pero cuando reviso el archivo en el debug, persiste el valor inicial.
porfis!!! ayudame
johnbarquin escribió
Si Camila, es que hay tres versiones del archivo de configuración. Supongamos que tu aplicación se llama MiApp.exe entonces tendrás:
1- App.config (el original del código fuente). Este nunca se modifica por programa, solo si lo editas manualmente, y en este caso, se copia automaticamente a (2) y (3) a continuación.
y cuando compilas, en bin\Debug Visual Studio te coloca dos más:
2- App.exe.Config : este se usa cuando lo ejecutas como aplicación independiente, ej. desde Inicio -> Ejecutar
Siempre se mantienen los cambios al salir de la aplicación, solo cambia si se edita el App.config original.
3- App.vshost.exe.Config : se usa cuando lo ejecutas desde Visual Studio. Este se modifica según lo programes pero al terminar la ejecución VS lo restablece al original App.config. Quizás por eso no te des cuenta del cambio; puedes como comprobación colocar un Console.ReadKey() (suponiendo es una app de consola) antes que termine el programa y comprobar el cambio antes de salir.
Espero esto te aclare lo que está sucediendo internamente, saludos