Juanma Santoyo

En ocasiones me llaman friki

Clase para acceso avanzado a las AppSettings del WebConfig

| No hay comentarios

Para quien no lo sepa, el WebConfig de asp.Net es un archivo XML que contiene todos los aspectos de configuración de nuestra aplicación. Entre los distintos parámetros, hay un nodo llamado AppSettings que nos permite definir pares clave / valor para después acceder a ellas desde cualquier punto de la aplicación.

Pero, a pesar de que el api proporciona dos métodos diferentes de acceso a las AppSettings, ambos tienen algunos inconvenientes. Lo que haremos, es crear una pequeña clase que nos permitirá tratar las AppSettings de una forma más simple y con una funcionalidad mejorada.

Clase AppSettings

Los inconvenientes

Los inconvenientes a la hora de trabajar con las variables de AppSettings son varios. Se podría decir que hay dos formas de acceder. Comentemos las dos formas:

Primera forma: la clase ConfigurationManager

La clase ConfigurationManager nos proporciona un diccionario estático que contiene los valores definidos en AppSettings:

ConfigurationManager.AppSettings["clave"];

A mi modo de ver, más largo de lo necesario y poco intuitivo (escribid “Configuration” en un VisualStudio y mirad cuantas entradas muestra el intellisense). Prometo que me costó un par de intentos memorizar esta línea.

Por otra parte, lo más grave es que el dato devuelto es siempre un string, lo cual nos obliga a hacer una conversión del dato inmediatamente después si queremos otro formato.

Segunda forma: la clase AppSettingsReader

Esta segunda clase, tiene algunas ventajas respecto a la anterior, pero también es mejorable.

Por una parte, su uso requiere de una instancia de AppSettingsReader y la posterior invocación a un método:

AppSettingsReader settings = new AppSettingsReader();
string valor = (string) settings.GetValue("clave", typeof(string)); 

Por no mencionar el casting obligatorio.

Por otra parte, aunque en principio se puede especificar el tipo del dato devuelto, hay poco control sobre él. ¿Qué pasa si es una fecha? Sinceramente, ni lo he probado.

Una posible solución

Yendo al grano, lo cierto es que el acceso a las AppSettings es mejorable. Vamos a considerar y a anotar algunas cosas sobre una posible alternativa que nos solucione los inconvenientes comentados:

  • Se accede desde una clase estática, pero más simple que la vista en la primera forma de acceder. No debería ser mucho más complejo que AppSettings.GetValue(“clave”).
  • Se ofrecen varios tipos básicos (pocos, pero controlados) como posibles retornos. Nuestra clase se encarga de hacer la conversión.
  • Además, la clase será capaz de realizar un tratamiento avanzado del contenido de las AppSettings: podrá retornar listas y diccionarios de los tipos básicos.

Definimos los diferentes tipos básicos de AppSettings

Serán solamente cuatro, pero a cambio ganaremos el control absoluto sobre los valores que retornamos.

Los tipos serán:

  • string
  • int
  • bool
  • DateTime

Definimos los diferentes formatos de las claves del AppSettings

Vamos a estipular como deberán ser escritos los datos en el WebConfig. A partir de ahora, deberemos escribir los valores en AppSettings siguiendo uno de los formatos siguientes. aunque ante cualquier excepción, siempre podremos obtener los datos como un tipo básico string (que será como si no aplicásemos ninguna conversión).

Datos básicos

No consideraremos un formato para los datos básicos porque no lo necesitan (excepto las fechas, que las vemos ahora mismo). Las cadenas se escribirán como cadenas, los números como números, y los booleanos como “true” y “false”.

Fechas

Las fechas seguirán un formato típicamente español:

dia/mes/año

Donde los días van del 1 al 31, los meses del 1 al 12, y los años tienen cuatro cifras.

Listas

Separaremos los diferentes elementos con comas.

valor1, valor2, valor3, valor4

Los espacios en blanco entre los valores y las comas serán indiferentes.

Diccionarios

Separaremos los pares con comas, y los clave valor con dos puntos.

clave1: valor1, clave2: valor2, clave3: valor3

Al igual que antes, los espacios en blanco entre los separadores y los valores son indiferentes.

Programamos la clase AppSettings

Ya sabemos que formatos tenemos que considerar. Ahora vamos a programar nuestra clase.

Antes que nada, debemos tener más o menos claro cómo queremos hacerlo. Lo haremos así:

  • Tendremos un método privado, llamado Get; que se encargará simplemente de obtener el dato de WebConfig como un string.
  • Tendremos tres métodos privados que se encargarán de convertir un string al resto de formatos. Se llamarán ToInt, ToBool y ToDate.
  • Tendremos varios métodos públicos, cada uno devolverá un tipo de dato. Los métodos se llamarán GetAsString, GetAsStringList, GetAsStringDict, GetAsInt, etc.

El método Get

private static string Get(string key)
{
	AppSettingsReader settings = new AppSettingsReader();            

	return (string) settings.GetValue(key, typeof(string));
}

En este método tenemos la única instancia de AppSettingsReader que vamos a usar. El resto de métodos de la clase se apoyarán en este para obtener la información del WebConfig.

Los métodos conversores

Serán tres. Uno convertirá un string a int, otro a bool y el último a DateTime.

private static int ToInt(string value)
{
	int v = 0;

	if (int.TryParse(value, out v))
	{
		return v;
	}

	return 0;
}

private static bool ToBool(string value)
{
	bool v = false;

	if (bool.TryParse(value, out v))
	{
		return v;
	}

	return false;
}

private static DateTime ToDateTime(string value)
{
	DateTime v = DateTime.Today;

	if (DateTime.TryParseExact(value, "dd/MM/yyyy", new CultureInfo("es-ES"), DateTimeStyles.None, out v))
	{
		return v;
	}
	
	else return new DateTime();
}

Los métodos que retornarán los datos

Estos métodos se apoyarán en los anteriores para obtener los valores, darles un formato de salida y devolverlos. Hay uno por tipo de dato y tipo de salida (normal, lista o diccionario).

Además, a los métodos que requieran de un separador (los que devuelven listas y diccionarios) les haremos una sobrecarga que permita indicar un separador distinto. De esta forma podremos reaccionar ante posibles conflictos entre nuestros separadores por defecto y los valores que contengan las AppSettings.

public static string GetAsString(string key)
{
	string value = Get(key);
	
	return value;
}

public static int GetAsInt(string key)
{
	string value = Get(key);
	
	return ToInt(value);
}

public static bool GetAsBool(string key)
{
	string value = Get(key);
	
	return ToBool(value);
}

public static DateTime GetAsDateTime(string key)
{
	string value = Get(key);

	return ToDateTime(value);
}

public static List<string> GetAsStringList(string key, char sep)
{
	string value = Get(key);
	List<string> list = new List<string>();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(s.Trim());
	}

	return list;
}

public static List<string> GetAsStringList(string key)
{
	return GetAsStringList(key, '|');
}

public static List<int> GetAsIntList(string key, char sep)
{
	string value = Get(key);
	List<int> list = new List<int>();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(ToInt(s.Trim()));
	}

	return list;
}

public static List<int> GetAsIntList(string key)
{
	return GetAsIntList(key, '|');
}

public static List<bool> GetAsBoolList(string key, char sep)
{
	string value = Get(key);
	List<bool> list = new List<bool>();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(ToBool(s.Trim()));
	}

	return list;
}

public static List<bool> GetAsBoolList(string key)
{
	return GetAsBoolList(key, '|');
}

public static List<DateTime> GetAsDateTimeList(string key, char sep)
{
	string value = Get(key);
	List<DateTime> list = new List<DateTime>();

	foreach (string s in value.Split(new char[] { sep }))
	{
		list.Add(ToDateTime(s.Trim()));
	}

	return list;
}

public static List<DateTime> GetAsDateTimeList(string key)
{
	return GetAsDateTimeList(key, '|');
}

public static Dictionary<string, string> GetAsStringDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary<string, string> dict = new Dictionary<string, string>();

	foreach(string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], value[1]);
		}
	}

	return dict;
}

public static Dictionary<string, string> GetAsStringDict(string key)
{ 
	return GetAsStringDict(key, ';', '|');
}

public static Dictionary<string, int> GetAsIntDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary<string, int> dict = new Dictionary<string, int>();

	foreach (string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], ToInt(value[1]));
		}
	}

	return dict;
}

public static Dictionary<string, int> GetAsIntDict(string key)
{
	return GetAsIntDict(key, ';', '|');
}

public static Dictionary<string, bool> GetAsBoolDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary<string, bool> dict = new Dictionary<string, bool>();

	foreach (string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], ToBool(value[1]));
		}
	}

	return dict;
}

public static Dictionary<string, bool> GetAsBoolDict(string key)
{
	return GetAsBoolDict(key, ';', '|');
}

public static Dictionary<string, DateTime> GetAsDateTimeDict(string key, char itemSep, char valueSep)
{
	string raw = Get(key);
	Dictionary<string, DateTime> dict = new Dictionary<string, DateTime>();

	foreach (string i in raw.Split(itemSep))
	{
		string item = i.Trim();

		string[] value = item.Split(valueSep);
		value[0] = value[0].Trim();
		value[1] = value[1].Trim();

		if (!dict.ContainsKey(value[0]))
		{
			dict.Add(value[0], ToDateTime(value[1]));
		}
	}

	return dict;
}

public static Dictionary<string, DateTime> GetAsDateTimeDict(string key)
{
	return GetAsDateTimeDict(key, ';', '|');
}

¡Hemos terminado!

Ahora ya tenemos una clase que, además de ser fácilmente utilizable desde cualquier parte del programa, nos proporciona los valores de AppSettings en el formato que necesitemos. Además hemos extendido la funcionalidad respecto al api de asp.Net por que también es capaz de obtener los datos en forma de listas y diccionarios.

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

Deja un comentario

Los campos obligatorios están marcados con *.