20 de mayo de 2010

Trace de NHibernate con syntax highlighting

NHTrace es una aplicación open source que muestra las sentencias sql generadas por NHibernate, tal como se podrían ver por consola, pero en este caso con syntax highlight para poder ver de forma mas amigable el código sql generado.



Para resolver el tema de syntax highlighting, a falta de buenas librerías open source en C#, decidí optar por usar librerías javascript y mostrar los mensajes en un componente WebBrowser.

Acá apareció el primer problema, el componente WebBrowser que viene con el framework funciona de forma tal, que cuando se asigna el código html a mostrar, por cuestiones de seguridad no se soporta la ejecución de código javascript. Para resolver esto fue necesario crear una clase que herede del WebBrowser e implementar algunas interfaces para que la seguridad la podamos manejar nosotros y así habilitar la ejecución de javascript.

Por suerte alguien ya había hecho algo así antes, porque seguir la documentación de la MSDN para hacer esto es, con riesgo a quedarme corto, muy confuso.

Para resolver el problema de "escuchar" los eventos de log4net, se presentaban distintas opciones con respecto a qué appender de log4net utilizar. A continuación menciono los appenders que fui probando y el motivo por el cual los descarté:

RemotingAppender: De forma aleatoria, los eventos llegaban desordenados

UdpAppender: De forma aleatoria, algunos eventos se "perdían"

FileAppender: Esta era una opción bastante aceptable, pero no llegué a resolver un problema que se presenta cuando se configura el appender con "appendToFile" en false (probablemente en el futuro le dedique mas tiempo para ver si se puede resolver)

Teniendo en cuenta que ninguno de estos appenders me servían de mucho, gracias a google (cuándo no) encontré que en el repositorio de svn de log4net hay un MsmqAppender que no está incluido en la distribución de log4net, pero realmente funciona perfecto, no pierde eventos y los eventos llegan en el orden correcto. La única desventaja de este appender es que hay que configurar el Message Queuing de Windows, ya que ese es el mecanismo que utiliza para la transmisión de los eventos, pero de todas maneras es algo muy sencillo de hacer.

Para más detalles sobre cómo configurar qué librería utilizar para el syntax highlight, cómo configurar MSMQ y log4net, está todo explicado en el sitio del proyecto, claro que desde ahí también se puede descargar la aplicación.

Espero que sea de utilidad, cualquier comentario ó sugerencia de mejora será bienvenido.

19 de abril de 2010

Document Session Manager - Addin de Visual Studio para administrar documentos

Document Session Manager es un addin para Visual Studio 2008 que permite guardar y recuperar la lista de archivos abiertos dentro de la IDE (ej: archivos xml, archivos de código fuente, formularios winforms, etc.)

Las características de Document Session Manager (DSM de ahora en más) están inspiradas en un addon de firefox llamado Session Manager

DSM permite guardar la lista de archivos abiertos dentro de lo que es llamado una "sesión". Luego, esta sesión puede ser cargada causando que todos los documentos que pertenecen a la misma sean abiertos en la IDE. El objetivo principal de ello es ayudar al programador a focalizarse en sólo un conjunto de documentos, deshaciéndose de otros que se pudieran haber abierto durante un debugging o mientras se estaba navegando mediante el comando Go To Definition (F12) de Visual Studio (en mi experiencia, muchos archivos que quizás sólo necesitábamos para echarles un vistazo rápido, pueden llenar la IDE de Visual Studio en muy poco tiempo ;)

Una característica extra de DSM es la habilidad de mantener la lista de documentos que estaban abiertos antes de iniciar un debugging; una vez que el debugging termina, esa lista de documentos puede ser restaurada, cerrando cualquier otro documento que se hubiese abierto durante la sesión de debug. (NOTA: si se desea, esta característica puede ser desactivada en la página de opciones del addin)

El proyecto está hosteado en codeplex. Más información y capturas de pantalla se pueden encontrar en la página principal del proyecto y en el sector de documentación.

Algunas capturas...





Espero que sea útil, cualquier comentario será bienvenido!

9 de abril de 2010

Plugin de CodeRush para cerrar el archivo activo cuando se recolecta un marcador

CR_MarkerCloseOnCollect es un plugin que he desarrollado y que puede resultar útil para aquellos que, como yo, usan CodeRush como herramienta de refactor en Visual Studio.

Es un plugin muy sencillo (de hecho, está hecho con solo 5 líneas de código), cuyo propósito es cerrar el archivo activo cuando se recolecta un marcador (Marker) de CodeRush.

Hay una excepción a esta regla, ya que cuando el marcador que se recolecta pertenece al mismo archivo que actualmente está activo en la IDE de Visual Studio, el archivo no se cerrará.

Mas allá de la sencillez del plugin, creo que puede ser de bastante utilidad, ya que es muy común utilizar F12 para ir al archivo donde se encuentra la declaración de algún elemento (como puede ser una clase, interfaz, método, etc...) y luego querer volver al lugar donde se insertó el marcador, sin que nos interese mantener abierto este archivo.

El enlace para descargar el plugin y algunas capturas de pantalla se pueden encontrar en esta ubicación, dentro del proyecto DXCore Community Plugins.

Espero que sea útil, cualquier comentario será bienvenido !

25 de marzo de 2010

CodeRush plugin to extract NHibernate's hql queries as Named Queries in a separate xml file

I have created a DevExpress CodeRush plugin to extract hql queries as Named Queries to an xml mapping file.

The idea is to write the hql query in code, like this:


var query = session.CreateQuery("from Order o where o.Amount > :amount");
query.SetParameter("amount", 100);
return query.List<Order>();


Then, position the cursor over the hql query, in this case "from Order o where o.Amount > :amount", and select the refactor option "Extract Hql Named Query".



The plugin then tries to locate the mapping file, and adds the query as a Named query.



After the query is added in the xml file, you can give a name to the named query, which will be synchronized in both files (like que CodeRush's rename F2)



Please note that after the query has been extracted, you should manually change the CreateQuery method with GetNamedQuery

Currently the plugin supports only a fixed name for the xml mapping file, and two strategies to locate that file:

* In current project only (default)
* First in current project, then in solution

This can be configured in the plugin options page.



Also, the refactor command can be configured with a key shortcut



Information about the plugin and download link is placed in the CR_ExtractHqlNamedQuery wiki page on the DXCore Community Plugins project.

Special thanks to Rory Becker for all the information he has shared about DXCore plugin development

21 de marzo de 2010

Detectando errores de bindeo de assemblies

A veces, cuando la aplicación que estamos desarrollando esta dividida en muchos assemblies, detectar un problema de referencias (ya sea un problema de versionado o directamente la falta de un determinado assembly) puede resultar bastante difícil.

El error que el runtime muestra es algo parecido a lo siguiente:

System.IO.FileLoadException: Could not load file or assembly 'B, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1735b5aafe024a29' or one of its dependencies.
The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'B, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1735b5aafe024a29'
at A.Class1..ctor()
at ConsoleApplication1.Program.Main(String[] args) in C:\VSProjects\AssemblyBindingTest\ConsoleApplication1\Program.cs:line 17

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

En este ejemplo, una aplicación de consola referencia a un assembly A.dll, y este assembly a su vez referencia a otro assembly B.dll
La versión correcta de B.dll debería ser la 1.1.0.0, pero en la carpeta donde se ejecuta la aplicación, deliberadamente hice deploy de la versión 2.1.0.0
Lo único que este mensaje de error me dice, es que no se pudo levantar el assembly 'B, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1735b5aafe024a29', o alguna de sus dependencias.

Lo cual no me dice mucho para resolver mi problema, en especial si esto ocurre en un ambiente con decenas de assemblies e inclusive algunos quizás no desarrollados por mi, sino por terceros.

Lo importante del mensaje es lo siguiente:
WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.

Aquí me dice que asignando el valor 1 a la entrada del registro HKLM\Software\Microsoft\Fusion!EnableLog se puede habilitar el "Assembly binding logging", vamos a hacerlo y veamos como cambia el mensaje de error que nos muestra el runtime:

System.IO.FileLoadException: Could not load file or assembly 'B, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1735b5aafe024a29' or one of its dependencies.
The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'B, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1735b5aafe024a29'
at A.Class1..ctor()
at ConsoleApplication1.Program.Main(String[] args) in C:\VSProjects\AssemblyBindingTest\ConsoleApplication1\Program.cs:line 17

=== Pre-bind state information ===
LOG: User = WinXP\Jorge
LOG: DisplayName = B, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1735b5aafe024a29
(Fully-specified)
LOG: Appbase = file:///C:/VSProjects/AssemblyBindingTest/ConsoleApplication1/bin/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : A, Version=1.1.0.0, Culture=neutral, PublicKeyToken=10f50b7c12e8c3d1.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: Post-policy reference: B, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1735b5aafe024a29
LOG: Attempting download of new URL file:///C:/VSProjects/AssemblyBindingTest/ConsoleApplication1/bin/Debug/B.DLL.
WRN: Comparing the assembly name resulted in the mismatch: Major Version
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

La primer parte del mensaje es igual a lo que obteníamos antes, pero ahora nos indica además el assembly "llamador":
Calling assembly : A, Version=1.1.0.0, Culture=neutral, PublicKeyToken=10f50b7c12e8c3d1.

Y lo mas importante, el motivo por el cual no se pudo realizar el bindeo.
LOG: Attempting download of new URL file:///C:/VSProjects/AssemblyBindingTest/ConsoleApplication1/bin/Debug/B.DLL.
WRN: Comparing the assembly name resulted in the mismatch: Major Version

Con esto sabemos que el assembly que no se pudo bindear es B.dll (y no alguna de sus dependencias, como sugería el mensaje original) y específicamente sabemos que el problema es de versionado (la dll que el runtime encontró es de una versión mayor a la requerida por la aplicación)

Por último, no olvidemos lo que nos decia el mensaje a modo de advertencia sobre habilitar Assembly Binding Logging:
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

Así que para evitar problemas de performance, luego de haber descubierto y solucionado nuestro problema, deshabilitamos el assembly binding logging asignando un 0 a HKLM\Software\Microsoft\Fusion!EnableLog

Espero que sea útil, cualquier comentario será bienvenido !

18 de marzo de 2010

Asociar un schema (xsd) a los archivos de configuracion de NHibernate y Spring.net en Visual Studio

Este es el primer post de muchos otros que estarán por venir... o al menos eso espero ;)

Para romper el hielo, voy a empezar con algo sencillo, pero que puede llegar a resultar bastante útil.

En Visual Studio, si uno quiere que un determinado archivo xml se valide contra un schema y además tener disponible la funcionalidad de Intellisense, es necesario asociar el xml al xsd en cuestión. Esto se puede hacer fácilmente mediante el menú Xml\Schemas, luego se selecciona el xsd de la lista o se busca un archivo xsd en disco. Hasta ahí todo bien, el problema es que es necesario realizar esta asociación en cada xml, uno por uno, y aun peor es el hecho de que esas asociaciones quedan registradas en el archivo de opciones de usuario de la solución (.suo), así que si me llevo un proyecto a otra solución estaría perdiendo todas las asociaciones entre xml y xsd que tenia dentro del proyecto.

Este problema se puede evitar siguiendo los siguientes pasos (voy a ejemplificar usando archivos xsd de NHibernate y Spring.net, pero la solución aplica para otros casos)

Buscar la carpeta Xml\Schemas, dentro de la ruta donde fue instalado el Visual Studio, y copiar los archivos xsd que queremos asociar a nuestros xmls (por ejemplo "C:\Program files\Microsoft Visual Studio 9.0\Xml\Schemas\").

En este caso, copiamos los archivos xsd para configuración de Spring.net y los archivos xsd de configuración y de mapping de NHibernate:

spring-objects-1.3.xsd
nhibernate-configuration.xsd
nhibernate-mapping.xsd

Luego buscar el archivo Catalog.xml que, siguiendo el ejemplo anterior, debería encontrarse en "C:\Program files\Microsoft Visual Studio 9.0\Xml\Schemas\Catalog.xml" y agregar estas tres lineas dentro del tag SchemaCatalog.


<SchemaCatalog xmlns="http://schemas.microsoft.com/xsd/catalog">
...
<Schema href="%InstallRoot%/xml/schemas/nhibernate-mapping.xsd"
targetNamespace="urn:nhibernate-mapping-2.2"/>
<Schema href="%InstallRoot%/xml/schemas/nhibernate-configuration.xsd"
targetNamespace="urn:nhibernate-configuration-2.2"/>
<Schema href="%InstallRoot%/xml/schemas/spring-objects-1.3.xsd"
targetNamespace="http://www.springframework.net"/>
...
</SchemaCatalog>


Una vez hecho esto, cuando abramos un archivo xml que tenga asociado alguno de los namespaces identificados en el atributo targetNamespace, automáticamente Visual Studio nos va a asociar el schema xsd que corresponda.

Pongo como ejemplo un archivo de configuración de Spring.net, donde el namespace se asigna mediante el atributo xmlns:


<objects xmlns="http://www.springframework.net">
<object name="MyMovieLister"
type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
</object>
</objects>


Espero que sea útil, cualquier comentario será bienvenido !