domingo, 13 de julio de 2008

Como agregar una lista de elementos en cualquier archivo de configuración de .NET (App.Config)

Muchas veces es interesante poder editar la forma en la que guardamos la configuración de nuestras aplicaciones de .net; el framework nos trae dos secciones por defecto para que guardemos nuestras configuraciones: una es AppSettings (que es un conjunto de claves/valor para uso general), la otra es la sección ConnectionStrings.

Además tenemos la alternativa de crear un archivo de settings donde un amistoso generador de código nos escribe todo por nosotros y así salir rápido del paso.

Esto puede servir en la mayoría de los casos comunes y silvestres. ¿Pero, qué sucede si necesitamos una sección de configuración que contenga una colección de N valores?

En este caso es cuando tenemos que crear nuestra propia sección de configuración, a través de todo el conjunto de clases que el framework nos provee.

Si buscamos un poco vemos que agregar un solo ítem nuevo no es muy complejo, pero cuando ya queremos jugar con colecciones de ítems se complica. Investigando un poco encontré un blog donde explica cómo hacerlo (http://www.ecyware.com/blog/PermaLink.aspx?guid=fe10f79c-739e-46f2-a774-db276de26636 ), como en ese blog algunas cosas no están muy claras y no se puede copiar y pegar, decidí compartir con ustedes mi propia versión en español inspirada del mismo.

Bueno a modo de receta intentare explicar un poco como viene la mano.

Pasos necesarios para crear tu propia sección personalizada de ítems configuración dentro de una colección:

  1. Primero necesitamos editar nuestro archivo App.Config, dándole el esqueleto de la futura sección de configuración.

    Para eso necesitamos primero, indicarle al framework que hay una sección nueva y cuál va a ser la clase que lo va a "controlar". Entonces agregamos esta entrada en la sección configSections:

<configuration>

<configSections>

<section
name="listElementSection"
type="ConsoleApplication2.ListElementSection, ConsoleApplication2"/>

</configSections>


Como vemos en esta parte definimos cual es el nombre del nodo inicial XML de la seccion a crear, y luego el nombre de la clase que la controlará, seguido por el nombre del assembly. Es importante que esta clase herede de ConfigurationSection para que podamos usar nuestra sección.

También vamos a agregar en nuestro App.Settings la lista de ítems con la estructura XML que hayamos decidido:

<?xml
version="1.0"
encoding="utf-8" ?>

<configuration>

<configSections>

<section
name="listElementSection"
type="ConsoleApplication2.ListElementSection, ConsoleApplication2"/>

</configSections>


<listElementSection>

<listItems>

<add
name="Nombre1" />

<add
name="Nombre2" />

</listItems>

</listElementSection>

</configuration>


  1. Ahora vamos a comenzar a codificar las clases que controlaran nuestra sección personalizada de configuración.

    Primero necesitamos una clase que maneje los ítems de nuestra colección, es decir que en cada elemento <add />. Para ello necesitamos una clase que herede de ConfigurationElement, y tenga tantas propiedades etiquetadas como campos querramos utilizar. El siguiente ejemplo de codigo les va a dejar las cosas mas claras:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


namespace ConsoleApplication2

{


class
ListItemElement : System.Configuration.ConfigurationElement

{

[System.Configuration.ConfigurationProperty("name", IsKey = true, IsRequired = true)]


public
string Name

{


get

{


return (string)base["name"];

}


set

{


base["name"] = value;

}

}

}

}

Acá notamos como hay que marcar cada propiedad que va a contener el campo del XML con el atributo ConfigurationProperty, y como tenemos que implementar el almacenamiento de la misma a través de la clase base.

  1. Una vez que tenemos el ítem listo, vamos a crear el elemento que va a representar la colección de ítems. Para eso heredamos de ConfigurationElementCollection y marcamos con un attributo especial denominado ConfigurationCollectionAttribute el cual indicara el tipo de los ítems que contendrá:


namespace ConsoleApplication2

{

[System.Configuration.ConfigurationCollectionAttribute(typeof(ListItemElement))]


class
ListItemCollection : System.Configuration.ConfigurationElementCollection

{


protected
override System.Configuration.ConfigurationElement CreateNewElement()

{


return
new
ListItemElement();

}



protected
override
object GetElementKey(System.Configuration.ConfigurationElement element)

{


return ((ListItemElement)element).Name;

}

}

}


En este punto tenemos que sobrescribir dos métodos, uno denominado CreateNewElement, que deberá retornar un objeto de la clase que creamos al principio que representa el tipo de elemento que está en la sección <add>, es decir en nuestro ejemplo ListItemElement().

Y el otro método a sobrescribir será GetElementKey, este recibe un ConfigurationElement, parámetro que podremos castear a nuestro tipo especializado ListItemElement (en este caso), y deberá retornar algún valor a utilizar como clave de la colección.

También pueden agregarle mas funcionalidad a esta colección, pero yo no he necesitado más que esto; además la clase base de la misma tiene ya varios métodos para agregar/quitar ítems ya están implementados, pero una buena idea es agregarle métodos que gestionen ítems del tipo que creamos anteriormente.

  1. Ahora ya tenemos el elemento inicial <add>, tenemos el elemento que representa a la colección de ítems, es decir a <listItems> por lo tanto nos está faltando representar a la sección madre de nuestra configuración, es decir en este caso a <listElementSection>. Para hacer esto, de nuevo vamos a crear una clase, pero en este caso va a heredar de ConfigurationSection:


namespace ConsoleApplication2

{


class
ListElementSection : System.Configuration.ConfigurationSection

{

[System.Configuration.ConfigurationProperty("listItems")]


public
ListItemCollection ListItems

{


get { return (base["listItems"] as
ListItemCollection); }

}

}

}


Acá tenemos que crear una propiedad, que contendrá la colección de elementos e indicarle que la misma matchea contra la sección <listItems> del xml mediante el uso del atributo ConfigurationProperty. Y por último y no menos importante, una pequeña implementación de la misma que retorne el tipo que habíamos creado para gestionar la colección de ítems es decir ListItemCollection.


Uff, con eso ya estaría andando, fíjense bien antes de compliarlo que el configSection se encuentre correcto, es decir que el atributo name tenga el nombre del nodo padre de nuestra configuración, y que el atributo type apunte al tipo que hereda de ConfigurationSection que creamos para tal fin.

Para terminar les dejo un pequeño programita de cómo utilizaríamos los valores, es decir como traeríamos la configuración:



class
Program

{


static
void Main(string[] args)

{


ListElementSection nav = ConfigurationManager.GetSection("listElementSection") as
ListElementSection;



foreach (ListItemElement it in nav.ListItems)

{


Console.WriteLine(it.Name);

}


Console.ReadLine();

}

}

Bajar código de fuente