Blog de Oxxigeno


Buenas Pr谩cticas en .NET: Uso estructurado del fichero de configuraci贸n

Escrito por Israel Vi帽uales en .NET, Desarrollo, Linux

Una pr谩ctica habitual en desarrollos asp net es utilizar el fichero de configuraci贸n (o el app config en aplicativos de escritorio) como almac茅n de valores configurables que luego se utilizar谩n en el aplicativo para uno u otro prop贸sito.

Lo que en principio se nos antoja como una buena pr谩ctica, en la mayor铆a de las ocasiones, debido a una utilizaci贸n mal estructurada del fichero de configuraci贸n, se convierte en una lista incontrolable y sin organizaci贸n alguna de entradas en el nodo appSettings.

Para evitar esto existe una soluci贸n alternativa, m谩s elegante, m谩s clara y, m谩s optima. Las clases ConfigurationSection, ConfigurationElement y ConfigurationElementCollection permiten definir secciones, elementos y colecciones de elementos en el fichero de configuraci贸n y utilizarlas como cualquier otro objeto en nuestro aplicativo.

Vamos a definir una peque帽a secci贸n en el fichero de configuraci贸n y comentamos un poquito c贸mo realizarla.


La clase EjemploData heredar谩 de ConfigurationElement y tendr谩 dos propiedades Name y PropiedadBooleana, de tipo string y bool respectivamente. Las propiedades de ambas deber谩n tener el atributo ConfigurationProperty con el nombre que tomar谩 en el fichero de configuraci贸n, su valor por defecto (si queremos especificarlo) y si es obligatoria.

publicclass聽EjemploData聽:聽ConfigurationElement
聽聽聽聽{
聽聽聽聽聽聽聽聽#region聽Public聽Properties
 
聽聽聽聽聽聽聽聽privateconststring聽NamePropertyName聽="name";
 
聽聽聽聽聽聽聽聽[ConfigurationProperty(NamePropertyName,聽IsRequired聽=true)]
聽聽聽聽聽聽聽聽publicstring聽Name
聽聽聽聽聽聽聽聽{
聽聽聽聽聽聽聽聽聽聽聽聽get聽{returnthis[NamePropertyName].ToString();}
聽聽聽聽聽聽聽聽聽聽聽聽set聽{this[NamePropertyName]=聽value;}
聽聽聽聽聽聽聽聽}
 
聽聽聽聽聽聽聽聽privateconststring聽PropiedadBooleanaPropertyName聽="propiedadBooleana";
聽聽聽聽聽聽聽聽[ConfigurationProperty(PropiedadBooleanaPropertyName,聽DefaultValue聽="true",聽IsRequired聽=false)]
聽聽聽聽聽聽聽聽publicbool聽PropiedadBooleana
聽聽聽聽聽聽聽聽{
聽聽聽聽聽聽聽聽聽聽聽聽get聽{return(bool)this[PropiedadBooleanaPropertyName];}
聽聽聽聽聽聽聽聽聽聽聽聽set聽{this[PropiedadBooleanaPropertyName]=聽value;}
聽聽聽聽聽聽聽聽}
 
聽聽聽聽聽聽聽聽#endregion
聽聽聽聽}

Crearemos una clase EjemploDataCollection que herede de ConfigurationElementCollection, tal y como se muestra, no requiere mucha explicaci贸n

publicclass聽EjemploDataCollection聽:聽ConfigurationElementCollection
{
#region聽ConfigurationElementCollection聽Members
 
protectedoverride聽ConfigurationElement聽CreateNewElement()
{
returnnew聽EjemploData();
}
 
protectedoverrideobject聽GetElementKey(ConfigurationElement聽element)
{
return((EjemploData)element).Name;
}
 
public聽EjemploData聽this[int聽index]
{
get
{
return(EjemploData)BaseGet(index);
}
set
{
if(BaseGet(index)!=null)
{
BaseRemoveAt(index);
}
BaseAdd(index,聽value);
}
}
 
#endregion
}

Finalmente, crearemos la clase que nos permita manejar este tipo de objetos. Esta clase debe heredar de ConfigurationSection, la cual nos servir谩 para marcar el 谩mbito en el cual obtendremos los valores dentro del fichero de configuraci贸n. Debe tener:

  • Una constante p煤blica que nos indique c贸mo llegar a la secci贸n adecuada del fichero de configuraci贸n.
  • Constantes privadas que nos marquen c贸mo se llamar谩n los atributos.
  • Nodos hijos que podremos definir en el fichero de configuraci贸n
  • Sus respectivas propiedades p煤blicas que nos permitir谩n utilizarlas en cualquier parte de nuestro aplicativo.

En nuestro ejemplo definiremos la seccion como 鈥oxxigeno/ejemploSettings鈥, lo que significa que en el fichero de configuraci贸n tendremos que definir un nodo oxxigeno y dentro uno ejemploSettings.

Queremos que exista una atributo en el nodo ejemploSettings, para lo cual crearemos una constante privada que nos diga como debe llamarse, 鈥nuevaPropiedad鈥, y una propiedad p煤blica que nos permita recuperarlo del fichero de configuraci贸n y utilizarlo en el aplicativo. Para ello crearemos una propiedad normal que nos devolver谩 un objeto de tipo string y le establecemos un atributo a la propiedad de tipo ConfigurationProperty, que indique c贸mo se va a llamar ese atributo en el fichero de configuraci贸n y si es obligatorio o no que exista.

Adem谩s nos interesa que bajo el nodo ejemploSettings exista una colecci贸n de nodos del mismo tipo (en nuestro caso EjemploData). Para ello procederemos igual que para la propiedad actual, pero definiremos su salida como EjemploDataCollection, y le agregaremos el atributo ConfigurationCollection pas谩ndole como par谩metro el tipo de objetos que se coleccionar谩n.

publicsealedclass聽EjemploSettings聽:聽ConfigurationSection
{
 
publicconststring聽SectionName聽="oxxigeno/ejemploSettings";
 
#region聽Public聽Properties
 
privateconststring聽NuevaPropiedadPropertyName聽="nuevaPropiedad";
 
[ConfigurationProperty(NuevaPropiedadPropertyName,聽IsRequired聽=true)]
publicstring聽NuevaPropiedad
{
get聽{returnthis[NuevaPropiedadPropertyName].ToString();}
set聽{this[NuevaPropiedadPropertyName]=聽value;}
}
 
privateconststring聽ColeccionDeEjemploPropertyName聽="coleccionDeEjemplo";
 
[ConfigurationProperty(ColeccionDeEjemploPropertyName,聽IsRequired聽=true,聽IsDefaultCollection聽=true)]
[ConfigurationCollection(typeof(EjemploData))]
public聽EjemploDataCollection聽ColeccionDeEjemplo
{
get聽{return(EjemploDataCollection)this[ColeccionDeEjemploPropertyName];}
}
 
#endregion
}

As铆 pues, para cargar datos en el fichero de configuraci贸n, debemos cargar la clase controladora (EjemploSettings) y montar el 谩rbol de nodos que hemos definido en las clases.

Dentro del nodo configurationSections debemos crear un nodo SectionGroup como se muestra, y dentro un nodo section. Pueden existir m煤ltiples nodos sectionGroup pero no con el mismo nombre. Cada nodo sectionGroup puede tener en su interior multiples nodos section.

   <sectionGroup name="oxxigeno">
      <section name="ejemploSettings" type="Oxxigeno.Ejemplo.Configuration.EjemploSettings, Oxxigeno.Ejemplo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=96df930e30970c00">
   </sectionGroup>

Y聽despues聽creamos聽el聽谩rbol聽de聽nodos聽tal聽como聽lo聽hemos聽definido,聽quedar铆a聽algo聽as铆:

   <oxxigeno> 
      <ejemploSettings nuevaPropiedad="valorDeLaPropiedad"&gt; 
         <coleccionDeEjemplo&gt; <clear/&gt;
            <add name="nombreDeLaEntrada1" propiedadBooleana="false" /&gt; 
            <add name="nombreDeLaEntrada2" propiedadBooleana="true" /&gt; 
         </coleccionDeEjemplo>
      </ejemploSettings>
   </oxxigeno&gt;

La forma de recuperar estos valores ser铆a la siguiente:

EjemploSettings聽ejemploSettings聽=聽ConfigurationManager.GetSection(EjemploSettings.SectionName)as聽EjemploSettings;
string聽nuevaPropiedad聽=聽ejemploSettings.NuevaPropiedad;
foreach(EjemploData聽obj聽in聽ejemploSettings.ColeccionDeEjemplo)
{
string聽nombre聽=聽obj.Name;
bool聽propiedadBooleana聽=聽obj.PropiedadBooleana;
}

Considero que este m茅todo de utilizaci贸n del fichero de configuraci贸n es:

  • M谩s 煤til: Los valores se encuentran parseados al tipo necesario, no se obtienen unicamente valores de tipo string como pasa si utilizamos AppSettings, lo cual facilita el trabajo del desarrollador.
  • M谩s estructurado: Los valores dentro del fichero de configuraci贸n son facilmente localizables y, por lo tanto, modificables.

Deja un comentario


Nuestras oficinas:

Oxxigeno Espa帽a
C/Luchana, 23. 28010 - Madrid
Tel.: 91 144 12 00
Fax: 91 144 12 01
E-mail:

Oxxigeno France
77, rue La Bo毛tie. 75008 - Paris
Tel.: +33 (0)1 45 61 68 99
Fax: +33 (0)1 45 61 51 05
E-mail: