jueves, 20 de octubre de 2011

Trabajar con archivos de configuración

Como todos sabemos, para añadir parámetros o elementos de configuración a un proyecto .NET, utilizamos los archivos de configuración (indistintamente con el archivo app.config o con el archivo web.config)
Para añadir opciones a estos archivos, disponemos básicamente de dos opciones:
  1. Entrada Manual:
    Con entrada manual me refiero a aquellas entradas que ubicamos en la sección de un archivo de configuración.

    image
    Para acceder a estos valores en tiempo de ejecución, tenemos que utilizar la clase “ConfigurationManager”, siempre que hallamos añadido la referencia correspondiente al ensamblado “System.Configuration.dll”

    image
  2. Entrada Semiautomática:
    Estas entradas son las que se establecen desde la ventana de propiedades de un proyecto.

    image
    Estas entradas se almacenan en el archivo de configuración de una manera un tanto “especial” como ya habréis observado.

    image
    Y para acceder a estos valores en tiempo de ejecución, típicamente haremos lo siguiente:

    image
Pero, ¿tenemos alguna opción adicional para trabajar con estos archivos de configuración? La respuesta es rápida y concisa: .
Si observamos las entradas que se generan en el archivo de configuración al utilizar el panel de propiedades del proyecto, vemos que añade dos elementos, por un lado un “sectionGroup” y por otro lado un “setting” en un nodo con el formato “Namespace.Properties.Settings” que coincide con el atributo “name” del elemento “sectionGroup”
La parte que más interesa ahora mismo es la del “sectionGroup” ya que si la observamos con detenimiento, podemos ver que tiene especificado un “type”, que típicamente será del estilo:
type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=key"

Además la propia entrada “section” tiene también un atributo “type”, que típicamente será del estilo:
type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=key"

Con lo anterior lo único que quiero indicar es que si los distintos elementos del archivo de configuración son de tipos concretos del Framework de .NET, ¿por qué no vamos a poder utilizar ahí tipos personalizados creados por nosotros?

En este punto, alguien puede preguntarse por qué nos interesa tener entradas personalizadas, y la respuesta, tal y como yo lo veo, hay que buscarla en el deseo de tener los archivos de configuración organizados y limpios, ya que con esta posibilidad podríamos tener distintas secciones dependiendo de módulos activados en nuestros programas, como podría ser un sistema de trazas o incluso los parámetros necesarios para utilizar componentes genéricos de acceso a datos.

Al turrón


Una vez que hemos visto un poco por encima cómo se utilizan los archivos de configuración, vamos a generar nuestros propios tipos de entradas, para poder organizar los parámetros necesarios para nuestros componentes genéricos.

Lo primero que tenemos que hacer es crear una clase personalizada “ConfigurationSection” que nos sirva para trabajar con los valores del archivo de configuración. Esta clase heredará de la clase “ConfigurationSection”, que nos permitirá trabajar con los datos en tiempo de ejecución.

El siguiente fragmento de código muestra la clase, está disponible en la sección de adjuntos:
     /// 
     /// This class allow us to access the config file data via the Configuration Manager.
     ///
     public class CustomTraceSection : ConfigurationSection
     {
         ///
         /// Create an "active" attribute.
         ///
         [ConfigurationProperty("active", DefaultValue = "false", IsRequired = false)]
         public Boolean Active
         {
             get
             {
                 return (Boolean)this["active"];
             }
             set
             {
                 this["active"] = value;
             }
         }
         ///
         /// Create a "traceLevel" element.
         ///
         [ConfigurationProperty("traceLevel")]
         public TraceLevelElement TraceLevel
         {
             get
             {
                 return (TraceLevelElement)this["traceLevel"];
             }
             set
             {
                 this["traceLevel"] = value;
             }
         }

Con este código lo que estamos generando es el soporte para nuestra sección de configuración personalizada, que quedará así:
image

Además estamos definiendo también los componentes que tendrá nuestra sección de configuración, en este caso un atributo “active” y un elemento “traceLevel”. El elemento “traceLevel” se genera mediante una clase personalizada que hereda de “ConfigurationElement”, cuyo detalle se ve a continuación, a pesar de que es muy similar a la clase anterior:

    public class TraceLevelElement : ConfigurationElement
     {
         ///
         /// Create a "value" attribute.
         ///
         [ConfigurationProperty("value", DefaultValue = "Nothing", IsRequired = true)]
         public TraceLevel Value
         {
             get
             {
                 return (TraceLevel)this["value"];
             }
             set
             {
                 this["value"] = value;
             }
         }
A destacar: En esta última clase hemos utilizado un tipo enumerado para indicar los valores disponibles para la propiedad, a título informativo de las posibilidades que nos brinda el sistema.

Con este código, ya podemos completar nuestra sección de configuración, que quedará así:
image

Ya sólo nos queda utilizar esta sección en nuestro código y lo tendremos todo ligado y bastante organizado:

            //Instanciamos la sección de configuración
            CustomTraceSection config =
                (CustomTraceSection) ConfigurationManager.GetSection("customTraceGroup/customTrace");

            //Acceso a valor concreto
            Boolean active = config.Active;

            //Acceso a valor embebido en un elemento
            TraceLevel traceLevel = config.TraceLevel.Value;


A partir de aquí, ¡a jugar!

Adjuntos

Descargar

Mejoras

  • Podríamos almacenar la ruta de la sección de configuración en una constante.
  • Podemos (tal vez en otro artículo) generar esas entradas en el archivo de configuración de forma ‘programática’, con lo que no sólo dejamos el archivos de configuración organizado, sino que además evitamos tener que poner esas entradas a mano.
  • Cualquier propuesta de mejora adicional, será bienvenida.

No hay comentarios: