13 diciembre 2006

Acabando con las configuraciones (Settings)

Además de lo que comenté el otro día, he encontrado muchos más problemas con los Settings de .net, y mucho más graves que los comentados.
El primero: las clases de configuración se persisten usando un SettingsProvider, y si no se define ninguno se aplica LocalFileSettingsProvider, que almacena los parámetros de aplicación en un archivo .config y los de usuario en otro .config distinto. Hasta ahí medio bien (después veremos), pero hay un gran problema: esto sólo se cumple para las aplicaciones (proyectos exe), no para las librerías. En este caso, no se da persistencia a los parámetros (así, como suena). Y .net no ofrece más SettingsProvider que este, cuyo funcionamiento es tan indeseable. Para evitarlo, reutilizamos la instancia del provider que sí funciona en la aplicación para los Settings de las librerías, con una clase propia SettingsPersistenciaUnificada.
Por otro lado, pensando en una aplicación distribuida en una red (quizá local) que accede a una base de datos centralizada, los parámetros de aplicación también deben estar centralizados, por lo que la idea de guardarlos en la máquina en un archivo .config, válido para aplicaciones web, no tiene ningún sentido en aplicaciones winforms. Necesitamos un DbSettingsProvider que desarrollamos nosotros, y que almacena los parámetros de usuario localmente (hereda de LocalFileSettingsProvider para reusar su idea de los archivos .config), y los de aplicación en una base de datos a la que accede mediante un parámetro local llamado ConnectionString que está guardado localmente.
La ventaja de trabajar con un SettingsProvider es que en principio podríamos seguir usando los archivos .settings de Visual Studio, pero como se dijo en la entrada de anteayer, necesitamos que los parámetros de las librerías sean públicos para que los acceda, consulte y modifique la propia aplicación, por lo que optamos por crear los archivos Settings.cs manualmente (tanto los de las librerías como los de la aplicación, que necesitan indicar un SettingsProvider en un atributo, así como establecer la ConnectionString como parámetro de usuario, no de aplicación, para que se almacene en la máquina y no en la base de datos).
Por fin hemos echado a andar los Settings, tras algunos obstáculos no esperados.

Etiquetas:

4 Comments:

Blogger Pablo said...

Hemos encontrado un fallo de DbSettingsProvider, y además tiene muy difícil solución (incluso creo que imposible), así que vamos a documentarlo porque no es grave y sólo fuerza a inicializar los Settings en un sentido concreto. El error en cuestión se produce cuando el Provider intenta obtener la ruta de la base de datos en la que persistirá los parámetros. Si nunca se ha establecido el valor del parámetro local ConnectionString, se supone que debe tomarse su valor por defecto, y ahí es donde marra: nunca se recupera ese valor. Y argumento por qué creo que es imposible recuperarlo: al acceder a un parámetro, se pasan al provider sus metadatos desde la clase donde está definido; pero en este caso quiero acceder al parámetro desde el propio provider, por lo que no conozco sus metadatos, entre los cuales se podría encontrar el valor por defecto. Conclusión: corrijo el error producido para hacer notar este comportamiento, y es responsabilidad de la aplicación (la que contiene el Settings con el parámetro ConnectionString) inicializarlo antes de que sus librerías lo accedan.

16 enero, 2007 09:19  
Blogger Pablo said...

De todo lo anterior, nada de nada. Fue mi primera idea, pero tras estudiarlo mejor había un problema más profundo: el ConnectionString que guardábamos desde la aplicación no podía leerse desde la librería, ya que sus contextos eran distintos, por lo que la librería buscaba el parámetro en otra sección distinta. La solución es más radical: utilizar el propio Settings desde el DbSettingsProvider para acceder a ConnectionString. Para ello creamos una interfaz ISettingsPrincipal que se utiliza automáticamente si está disponible al unificar persistencia.

16 enero, 2007 13:17  
Blogger Pablo said...

Finalmente ha sido imposible almacenar los parámetros de usuario y de aplicación en un mismo Settings, ya que en el mismo proceso en que se recuperaba la cadena de conexión (parámetro de usuario) se recuperaban también los parámetros de aplicación, que fallaban por no tener aún una cadena de conexión válida, y después no se volvían a cargar. La solución ha sido separar en dos clases los parámetros de aplicación y los de usuario: AppSettings y UserSettings; y manualmente establecer una ConnectionString en el proveedor de App accediendo al parámetro existente en UserSettings. Así no hay que unificar la persistencia de los AppSettings ya que parten de la ConnectionString del UserSettings que sí tienen que haber sido unificados (entre los proyectos dentro de una misma solución).
Por cierto, para UserSettings sí estamos usando LocalFileSettingsProvider, estableciendo todos los parámetros como UserSettings, incluida la cadena de conexión, que no puede marcarse con el atributo SpecialSetting para indicar que se trata de una ConnectionString puesto que en ese caso ya no se almacena correctamente (se interpreta como un parámetro de aplicación inmutable).

10 abril, 2007 09:29  
Blogger Pablo said...

Hay un nuevo modelo de configuraciones que extiende al básico de .net (no se si realmente extiende o parte de cero), y se también viene de Microsoft en forma de EntLib (Enterprise Library): los Configuration Application Blocks, véase http://msdn2.microsoft.com/en-us/library/ms954818.aspx
No sé si permite solucionar los problemas que hemos encontrado hasta ahora (todos o alguno), habrá que mirarlo con tiempo.

27 junio, 2007 08:43  

Publicar un comentario

<< Home