2009-10-14

Nuevo proyecto: zInject, o "Cómo hacer Inyección de Código para cualquier hijo de vecino"

Hace tiempo que tenía la idea de hacer un programa para poder inyectar código sobre assemblies ya compiladas dando vueltas por la cabeza. Finalmente, hoy fue el día de crear su versión 0.1

Les presento zInject!

Cual es la idea detrás de esto? Simple...
Supongamos que yo tengo un proyecto hecho y derecho, con una clase cuyos métodos son M1, M2 y M3.


public class M
{
public void M1()
{
...
}

public void M2()
{
...
}

public void M3()
{
...
}
}


Un día viene el jefe y me dice: "De ahora en mas, tenemos que verificar cuanto demora la ejecución de los siguientes métodos: M1, M2 y M3.
En ese momento uno piensa: "Bien, tendría que hacer nuevos métodos que se ejecuten antes y después de M1, M2 y M3 y que los mismos calcules cuanto tardó cada ejecución.


public class M
{
public void M1()
{
Empezo("M1");
...
Termino("M1");
}

public void M2()
{
Empezo("M2");
...
Termino("M2");
}
    public void M3()
{
Empezo("M3");
...
Termino("M3");
}
}

Esto trae una serie de problemas. Agregar esto ensucia el código de M1, M2 y M3 por las llamadas a los nuevos métodos al principio y al final. Peor aún, si tengo que agregar nuevos "comportamientos" al principio o al final del método, el código termina siendo incomprensible! Ni hablar en caso de que cada comportamiento (como seguridad o auditoria) a agregar implique mas de una sola linea de código...

Para solucionar llega zInject.
Para usarlo, definimos un atributo que hereda de InjectionBaseAttribute


    
public class TiempoAttribute : InjectionBaseAttribute
{
public TiempoAttribute()
{
}
        public override void BeforeExecute(string method, object target)
{
Empezo(method);
}
        public override void AfterExecute(string method, object target)  
{
Termino(method);
}
}

Después, simplemente agregamos el atributo a los métodos que se desea:


public class M
{
[Tiempo]
public void M1()
{
...
}

[Tiempo]
public void M2()
{
...
}

[Tiempo]
public void M3()
{
...
}
}

Ahora, dirán... Todo muy lindo, pero... ¿Cómo se ejecuta el código del atributo?

Para poder hacer esto hay que ejecutar el injector propiamente dicho. Esto se puede hacer tanto ejecutándolo desde linea de comandos una vez compilado el assembly, como usando una Post Build Action dentro de Visual Studio. Esta utilidad agregará dentro del IL del assembly las llamadas necesarias a los metodos ExecuteBefore y ExecuteAfter

To Do:

  • Evitar totalmente el uso de Reflection. Actualmente, el código inyectado utiliza reflection para ejecutar las acciones de los atributos, simplemente por simplicidad del desarrollo. A futuro, se inyectará directamente la llamda al atributo concreto.
  • Poder customizar cuales atributos aplicar y cuales no
  • UI para Windows/OS X/Linux
  • Quitar dependencias contra librerías externas

Les dejo la dirección del proyecto en CodePlex para bajar los binarios compilados y el código completo para bajarlo con sus tests para bajarlo y ver como se usa.

http://zInject.codeplex.com

Cualquier sugerencia es bienvenida!

Saludos!
Zaiden


2009-10-08

Interoperabilidad de WebServices con certificados entre .NET con WSE y Java

Pese a que el "espíritu" del standard de WebServices, WS-Security, y demas yerbas planteadas en las RFC supondrían una facilidad para la interoperabilidad ente diferentes plataformas, al intentar llevarlas a la realidad las asperezas surgen... y explotan en nuestra cara.

Hace un tiempo, en Lagash tuvimos que implementar un TokenManager (entre otras cosas) para poder traducir los llamados hechos desde WSE 3 a Java, utilizando certificados de seguridad.

Luego de estar funcionando sin problemas por casi dos años, el servicio comenzó a fallar al momento de recibir la respuesta de un pedido, con un mensaje que decía "WSE590: Failed to resolve the following key info"... y mostraba uno de los nodos de Key Info, conteniendo supuestamente el Subject Key Identifier del certificado necesario para desencriptar el mensaje.

El problema resultó ser que, dado que el nuevo certificado que comenzaron a usar no contenía la extensión de Subject Key Identifier, para poder identificarlo, tanto Java como WSE generaban un hash del certificado. El gran problema gran era que los hashes eran calculados de forma distinta!

Para poder solucionarlo, dentro del input filter de los mensajes hubo que reemplazar la porción de SOAP que indica el certificado a utilizar por una creada a mano que indique el certificado concreto (que, de hecho, siempre es el mismo que se utiliza al enviar el mensaje original).

Para mas información: http://support.microsoft.com/kb/922779/en-us (el problema no es exactamente el mismo, pero el approach para solucionarlo es muy similar).

Saludos!

Zaiden


2009-10-04

WPF y VMWare Fusion

Si alguna vez tratan de usar WPF desde una maquina virtual en VMWare Fusion, notarán que la aplicación se torna inusable.
Para poder solucionar esto hay que desactivar la aceleración por hardware de WPF dentro de la VM. Esto se hacer creando el siguiente DWORD dentro del registro de windows:
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Avalon.Graphics\DisableHWAcceleration
y seteando su valor a 1.

Fuente: http://blog.joachim.at/?p=19