Como depurar fácilmente el código de ASP.NET5

¡Muy buenas! Para los que andamos trasteando con versiones alfas y betas con nula o poca documentación, poder depurar el código fuente de las librerías es una manera muy buena de ver qué hace y como lo hace. Cierto, solo leyendo el código fuente se puede aprender mucho, pero poder depurarlo paso a paso es todavía más útil.

El primer paso es, por supuesto, disponer del código fuente. En según que librerías eso no es posible, aunque siempre se podía tirar de los desensambladores (por más que eso pueda no ser legal). El problema de usar los desensambladores es que el código fuente obtenido no siempre es muy legible y que por otro lado no puedes depurarlo a no ser que tu desensemblador soporte la creación de PDBs.

Depurar ASP.NET MVC nunca ha sido un problema importante, en tanto el código fuente estaba disponible. Podías descargarte el código fuente de ASP.NET MVC, compilarlo en alguna carpeta local, pongamos c:mvc, junto con sus PDBs. Luego tenías que modificar tu proyecto web, quitar las referencias a ASP.NET MVC reales y sustituirlas por las versiones locales con PDBs. Con eso, podías depurar ASP.NET MVC sin muchos problemas. Pero era un poco peñazo el tener que sustituir las referencias reales por las tuyas compiladas, lo que podía redundar en algún cambio adicional de configuración (por estar firmadas las reales y no estarlos, o estarlo con otra clave, las locales).

En ASP.NET5 el proceso se ha vuelto ridículamente simple. El proceso es como sigue:

  1. Clona los repositorios de ASP.NET5 que quieras. P. ej. yo he clonado algunos de ellos en la carpeta c:tfsaspnet5.
  2. Crea un proyecto web con VS2015 que use ASP.NET5. O abre un proyecto existente, eso es lo de menos.
  3. Abre el fichero global.json que está en Solution Items

Este fichero contiene en “projects”, la lista de carpetas en las que VS2015 sabe que hay código que debe incorporar como parte de tu proyecto (por defecto las carpetas src y test). Añade la carpeta base en la cual has clonado los repos de aspnet5 que quieras depurar:

  1. {
  2.   "projects": [ "src", "test", "c:/tfs/aspnet5/mvc/src" ],
  3.   "sdk": {
  4.     "version": "1.0.0-beta8"
  5.   }
  6. }

En mi caso en c:tfsaspnet5mvc he clonado el repo de ASP.NET MVC6 así lo añado en projects (debo añadir el /src final que es donde hay los proyectos). Eso automáticamente me añade los proyectos de ASP.NET MVC6 a mi solución:

image

Además en el solution explorer VS2015 nos indica, con un icono distinto, qué referencias ha cargado en local:

image

Ahora puedes navegar por el código fuente y colocar breakpoints sin ningún problema… ejecutar tu aplicación y ¡depurar!

image

Eso sí, la clave para que te funcione es que tengas los repos sincronizados con la versión que estás usando. P. ej. si en el project.json estás referenciando la versión 1.0.0-beta8 debes tener los repos con el código fuente que se corresponda a dicha versión (todas las versiones tienen un tag de Git asociado, así que puedes obtener la que quieras). También que estés usando el entorno de ejecución correspondiente (no te funcionará si intentas depurar beta8 usando el dnx de beta5).

Observa que no es necesario cambio alguno en nuestro proyecto. Cuando hayas depurado, basta con que elimines del global.json el directorio con los fuentes y tu aplicación pasará a referenciar los paquetes NuGet oficiales.

Más fácil, ¡imposible!

Saludos!

PD: Antes de que me deis las gracias, se las dáis a Hugo Biarge (@hbiarge) que fue quien me lo contó. En este post hay más info (un poco desactualizada, ojo): http://blogs.msdn.com/b/webdev/archive/2015/02/06/debugging-asp-net-5-framework-code-using-visual-studio-2015.aspx

Variables privadas en clases ES2015

Una de las novedades de ES6 es la posibilidad de usar clases. Si bien esas clases son realmente sugar syntax sobre el patrón de función constructora, tienen alguna característica que simplifica el uso de dicho patrón y ofrecen una sintaxis que según como se mire puede ser más cómoda. Pero el estándard de ES2015 no tiene ningún mecanismo para indicar que una variable de una clase sea pública o privada. La visibilidad de variables en JavaScript es un clásico, sobre el que ya he escrito algún post. Pero las técnicas que usábamos hasta ahora para simular la visibilidad privada no aplican cuando usamos la sintaxis de clases… y debemos usar mecanismos alternativos. En este post veremos dos de ellos.

Supongamos que tenemos una clase ES2015 como la siguiente:

  1. class Foo {
  2.     constructor(name) {
  3.         this._name = name;
  4.     }
  5.  
  6.     get name() {
  7.         return _name;
  8.     }
  9. }

El objetivo es que _name sea privado y solo pueda accederse a su valor a través de la propiedad name.

Símbolos al rescate

La primera solución implica el uso de un nuevo concepto de ES2015: los símbolos. Un símbolo permite definir un nombre único desconocido y que tan solo puede ser obtenido a partir de la referencia al símbolo original que ha creado dicho nombre.  El siguiente código explica el uso de símbolos:

  1. var sfoo = Symbol("foo");
  2. var a = {};
  3. a[sfoo] = "sfoo";
  4. console.log(a.sfoo); // undefined
  5. console.log(a[sfoo]);   // sfoo
  6. console.log(a[Symbol("foo")])    // undefined

Podemos asignar una propiedad de un objeto a un símbolo, y entonces requerimos del símbolo para poder obtener el valor de la propiedad. Observa que necesitamos el símbolo original (almacenado en sfoo), crear otro símbolo a partir de la misma cadena, no sirve. Los símbolos son únicos.

Por lo tanto ahora podemos simular variables privadas de la siguiente manera:

  1. const s_name = Symbol("name");
  2. export default class Foo {
  3.     constructor(name) {
  4.         this[s_name] = name;
  5.     }
  6.     get name() {
  7.         return this[s_name];
  8.     }
  9. }

Los objetos de la clase Foo tienen una variable cuyo nombre es el símbolo guardado en s_name. Esa variable “no es realmente pública”, pero no hay manera de encontrar su nombre fuera del módulo que declara la clase (la variable s_name que contiene el símbolo, es privada del módulo por lo que no es accesible desde el exterior). Observa que no basta que alguien mire el código fuente del módulo y se cree otro Symbol(“name”) para acceder a la variable “privada”: los símbolos son únicos, o lo que es lo mismo: Symbol("a") != Symbol("a").

Este método no genera variables totalmente privadas. Las variables que están almacenadas en una propiedad cuyo nombre es un símbolo, no se listan en Object.getOwnPropertyNames y tampoco participan de la iteración de for..in pero se pueden obtener todos los símbolos asociados a un objeto mediante Object.getOwnPropertySymbols, que devuelve un array con todos los símbolos usados como nombre de propiedad del objeto. Basta con usar los símbolos devueltos para acceder a las variables “privadas”.

Por lo tanto este sistema, vendría a equivaler a la visibilidad private de C# para entendernos: Por defecto es imposible acceder a la propiedad, pero tenemos un mecanismo (en C# es Reflection) que nos permite saltarnos esa protección y acceder al contenido de la variable “privada”.

Weak maps

El uso de weak maps nos permite tener variables completamente privadas. Para ello usamos el nuevo tipo WeakMap de ES2015, que básicamente es un diccionario clave, valor, pero es especial porque no impide al GC de JavaScript recolectar todos aquellos valores almacenados en el weak map, siempre y cuando la referencia a la clave que tenga el weak map sea la única restante. Es decir, a todos los efectos el weak map no cuenta para el GC: aunque un objeto esté almacenado en él, si la clave usada no está referenciado por ningún otro objeto, el GC lo podrá eliminar.

El código usando WeakMap es el siguiente:

  1. const privates = new WeakMap();
  2. export default class Foo {
  3.     constructor(name) {
  4.         privates.set(this, {name: name});
  5.     }
  6.     get name() {
  7.         return privates.get(this).name;
  8.     }
  9. }

La idea es muy sencilla: por cada objeto que se cree de Foo, se almacena un valor en el WeakMap privates. La clave de dicho valor es this, que es el propio objeto Foo que se crea. Este objeto (privates.get(this)) almacena todo el estado “privado” del objeto Foo en cuestión. Gracias al hecho de que privates es un WeakMap no hay memory leak: Cuando el objeto Foo deje de usarse podrá ser eliminado por el garbage collector, aunque esté referenciado por el WeakMap como una de las claves usadas (precisamente por ser un privates Weak Map).

La clave (nunca mejor dicho :P) del asunto está en usar this como clave del Weak Map privates.

Al igual que en el caso del símbolo, el Weak Map es una variable privada del módulo, por lo que no se puede acceder a fuera desde él. Y a diferencia del caso del símbolo, ahora si que no hay nada que nadie pueda hacer para acceder a la variable privada que almacena el valor del nombre.

Saludos!