viernes, 1 de septiembre de 2006

Recursos incrustados y propiedades extendidas

Los recursos incrustados (embedded resources in inglish) son un mecanismo que nos permite incluir ficheros dentro de un ensamblado. Constituyen una forma limpia y eficaz de distribuir ficheros con una aplicación, cuando no queremos que dichos ficheros pululen por el directorio de la aplicación y puedan por tanto ser chafardeados por los juanquercillos de turno (deberán ser juanquers de cierta categoría si quieren ver algo).

Incluir recursos incrustados desde Visual Studio 2005 es muy sencillo: basta agregar (o crear) los ficheros deseados en el proyecto, abrir la ventana de propiedades de los mismos, y en Acción de generación seleccionar Recurso incrustado. Para recuperar estos ficheros una vez generado el ensamblado, viene al rescate la clase Assembly, en concreto sus métodos GetManifestResourceNames y GetManifestResourceStream.

Veamos un ejemplo. Tomemos un proyecto chorra tal que este:


Supongamos que queremos que todo lo que hay bajo el directorio DatabaseChangeScripts se almacene en el ensamblado como recursos incrustados. No tenemos más que seleccionar todos los ficheros (ya sabes, Shift o Ctrl y clics a discteción), botón derecho, propiedades y:


El siguiente código muestra cómo obtener la lista de todos los recursos incrustados del ensamblado:

Si copias este código en el método Main de Program.cs, al ejecutar el proyecto desde el propio Visual Studio verás lo siguiente en la ventana de resultados:


Fíjate en el interesante detalle de que la jerarquía de carpetas se mantiene en el nombre del recurso. Esto da pie a numerosas e interesantes piruladas, como la que os voy a mostrar ahora. Pero antes, veamos cómo recuperar el contenido de un recurso incrustado una vez conocido su nombre:

En este caso, suponemos que el recurso en cuestión es un fichero de texto, por tanto ponemos su contenido en una cadena.

Pues bien, una estructura como la del ejemplo es la que yo uso para mantener un control de versiones en la base de datos que usan las aplicaciones en las que trabajo. Cada vez que necesito hacer un cambio con respecto a la estructura que tiene la base de datos ya instalada al cliente, creo una nueva carpeta de versión y pongo dentro todas las secuencias de comandos SQL necesarias para la actualización. Al inicio de la aplicación compruebo la versión de la base de datos, y si no es la última, leo las secuencias de comandos incrustadas y las ejecuto, tras lo cual actualizo el número de versión de la base de datos (por supuesto, todo con las pertinentes transacciones de por medio, de forma que nunca queden actualizaciones a medias).

Para guardar el número de versión en la base de datos uso una propiedad extendida. Las propiedades extendidas de SQL Server son atributos globales a nivel de base de datos, no dependen de ninguna tabla ni procedimiento almacenado y constan de un nombre y un valor (en realidad ambién es posible establecer propiedades extendidas para otros objetos, no sólo para las propias bases de datos).

Para crear una propiedad extendida hay que usar el siguiente procedimiento almacenado del sistema (el nombre y el valor son ejemplos):

Para borrar una propiedad extendida existente:

Para modificar el valor de una propiedad extendida:

Finalmente, para consultar el valor de una propiedad extendida:

Si tienes el SQL Server Management Studio, también puedes controlar las propiedades extendidas visualmente, mediante la ventana de propiedades de la base de datos:


Pues hala, dada la tremenda utilidad de los recursos incrustados, incrustaos bien esta parrafada en el cerebro (¿lo pillais? ¿Lo pillais? Bueno, al menos no me pegueis muy fuerte...)

lunes, 28 de agosto de 2006

La ley de Demetrio

He aquí un claro ejemplo de lo gracioso que puede llegar a ser traducir frases en inglés. En este caso, todo un señor paradigma de la programación orientada a objetos (The Law of Demeter) nos queda reducido a algo que parece el título de una película setentera de Pajares y Esteso.

La susodicha ley especifica un método para construir clases lo más desacopladas e independientes posible, de forma que la reutilización de componentes y el mantenimiento de aplicaciones resulten tareas algo más sencillas. Concretamente, la ley dice que un método de una clase sólo debería invocar métodos pertenecientes a:
  1. El propio objeto.
  2. Los objetos creados por el método.
  3. Los objetos pasados al método como parámetros.
  4. Los campos y propiedades del propio objeto.
Si seguimos esta ley a rajatabla, esto implica, por ejemplo, que no podemos invocar métodos de objetos que nos son devueltos al invocar otros métodos. Esto puede llegar a ser complejo de cumplir.

Otra consecuencia más "razonable" es la ausencia de variables globales. La información de contexto apropiada debería estar contenida en el propio objeto como una propiedad. Aunque esto también parece complejo de cumplir, ahora veremos un ejemplo de cómo hacerlo de forma sencilla.

Tomemos por ejemplo el recurso global por excelencia de cualquier aplicación (por lo menos del tipo de aplicación que yo desarrollo): la conexión a la base de datos. Supongamos que necesitamos un objeto SqlConnection omnipresente, accesible desde cualquier lugar de la aplicación. Lo típico en estos casos es crear una clase estática de estado y almacenar la conexión como una propiedad de la misma. Entonces, las clases que necesitan acceso a la base de datos no tienen más que leer la susodicha propiedad de la susodicha clase.

Pues bien, según Demetrio, esto está MAL.

En primer lugar, la conexión no debería ser accesible a cualquier clase de la aplicación, sino sólo a aquellas de la capa de acceso a datos. Pero eso es otro tema, y tampoco quiero ponerme excesivamente repelente.

En segundo lugar, toda clase que necesite acceso la base de datos debe tener una propiedad que albergue la conexión, de esta guisa:

De esta forma, si en el futuro queremos reutilizar la clase en otro proyecto, podremos hacerlo sin problemas, puesto que no habrá ninguna dependencia de datos globales.

Y tu dirás, "¡Pero yo creo instancias de esa clase en mil sitios en mi código! ¿Tengo que establecer la conexión cada vez? ¡Qué pesadilla!" Y razón no te falta. Pero existe una solución muy sencilla: crear una propiedad estática que contendrá el valor predeterminado para la propiedad, es decir, el valor que tendrán las instancias nuevas si no se especifica lo contrario. Verbigracia:

Ahora sólo tienes que establecer el valor de la propiedad estática una vez, en el método Main que da inicio a la aplicación:

...y si para una instancia en particular quieres establecer otra conexión, puedes hacerlo tranquilamente mediante su propiedad Connection.

Y como hoy estás un poco gruñón, volverás a quejarte: "Vale, pero cada vez que creo una clase nueva con acceso a datos, tengo que acordarme de inicializarle la conexión predeterminada en el Main. Y yo tengo muchas clases y bla bla..." Tranquiiilo, que esto también tiene una solución facilona. Es hora de que la reflexión venga al rescate.

No, no se trata de que nos volvamos filósofos de repente. La reflexión es el mecanismo de .NET que nos permite obtener información sobre los componentes de cualquier ensamblado: podemos listar las clases existentes, los miembros de una clase, invocar métodos especificando su nombre, etc.

Usando reflexión, podemos decirle a nuestra aplicación lo siguiente: "Búscame todas las clases del ensamblado actual que tengan una propiedad llamada DefaultConnection, y les estableces la propiedad con este valor". Dicho y hecho:

Una solución más limpia sería crear un interfaz (por ejemplo IConnectable) que tuviera como propiedad la conexión y su alter-ego estático, y hacer que las clases con derecho a acceso a la base de datos implementaran ese interfaz. Pero eso te lo dejo como ejercicio (que además ya estoy cansado de escribir).

Conclusión: haz caso a Demetrio, que es más viejo que tú y sabe mucho.

Más información aquí.

jueves, 24 de agosto de 2006

Fragmentos de código

Visual Studio 2005 proporciona un mecanismo útil para insertar rápidamente esos pequeños trozos de código que usamos una y otra vez. El mecanismo se llama, precisamente, fragmentos de código (en inglés Code Snippets).

Un fragmento de código se almacena como un fichero XML y consiste en una porción de código fijo con algunos campos variables. Cada fragmento tiene un nombre corto que sirve para invocarlo desde el editor de Visual Studio: basta escribir el nombre del fragmento y pulsar TAB. Todo el código del fragmento aparecerá ante nuestros ojos como por arte de birlibirloque, y podremos movernos entre los campos editables con la tecla TAB. Cuando lo hayamos editado todo a nuestra conveniencia, bastará pulsar ENTER y seguir programando como si nada hubiera pasado.

Haz la prueba. Desde el editor de código de C#, escribe prop y pulsa TAB. Aparecerá tal que esto:


prop es uno de los fragmentos que Visual Studio incorpora de fábrica, y permite añadir propiedades con un campo privado de respaldo (lo cual debe hacerse siempre en vez de usar campos públicos, como todo programador educado sabe). Por supuesto, la gracia del asunto consiste en que puedes definir tus propios fragmentos y añadirlos al arsenal (menú Herramientas - Administrador de fragmentos de código).

Por ejemplo, para mi quehacer diario he creado un fragmento llamado propt basándome en el prop existente. Los cambios son dos: establece como nombre del campo de respaldo el mismo que el de la propiedad, con un carácter de subrayado delante; y añade un boceto de comentario XML. La invocación de propt genera lo siguiente:


Y por si os interesa, teneis el código del fragmento aquí mismo: podeis descargarlo e importarlo desde Visual Studio.

Más información sobre el tema en la web del tito Puertas.

MessageBox.Show("¡Hola!");

Saludos, buena gente. Como bien pone más arriba, en este blog publicaré todo aquello que descubra/se me ocurra/aprenda durante el desempeño de mi empleo como programador en .NET (C# con Visual Studio 2005 en estos momentos) y SQL Server (de nuevo, versión 2005). Más que nada lo hago para tener una especie de copia de seguridad de mi cerebro, para cuando se me vayan olvidando cosas (que la edad no perdona, y la de uno ya tiene seis bits); pero si alguno de estos relatos mitológicos te resulta de utilidad, pues tanto mejor. Huelga decir que vuestros comentarios, si los hubiere, son bienvenidos.

Y tú dirás, "¡Pero bueno! ¡Si tú eres comunista! ¿Cómo es posible que trabajes para el demonio capitalista?" Pues hijo, la vida da muchas vueltas, las cosas vienen tal como vienen, el fútbol es así y uno de cada dos por tres son seis. Todos cometemos locuras en nuestra juventud, y la mía consistió en adentrarme en el mundo de la programación PCera con el infame limitado Visual Basic 6. Para expiar mi culpa, os contaré que en mi empresa actual se programaba en VB.NET cuando yo entré, pero mediante un hábil proceso de lavado cerebral y publicidad subliminal conseguí que nos pasáramos al C#.

Pues eso, que os divirtais, y no olvideis visitar mi otra bitácora.