¿Problemas al actualizar a jQuery 1.9?

jQuerySeguro que, como un servidor, muchos os habéis vuelto locos con la llegada de jQuery 1.9 al intentar actualizar vuestros proyectos, principalmente por los breaking changes introducidos que han provocado que tanto código propio como muchos plugins dejen de funcionar debido a la desaparición de métodos como live(), $.browser() y otros cambios de envergadura.

Nuestro código podemos modificarlo teniendo en cuenta los cambios de esta versión, hasta ahí sin problema. El dolor viene con los componentes de terceros sobre los que no tenemos control.

No hace demasiado, Eduard Tomás hablaba de los problemas con unobstrusive ajax de MVC, pero hay muchos más reportados, como jqGrid, el célebre plugin para la creación de rejillas de datos.

Normalmente la solución consistiría en actualizar las bibliotecas afectadas, pero eso no siempre es posible; a veces ni siquiera existe la actualización y otras veces, aunque exista (p.e., en el caso de jqGrid), no nos conviene aplicarla por los efectos secundarios que puedan aparecer. También podemos intentar modificar directamente el componente, pero esto, aparte de la dificultad que tiene en algunos casos, provoca que nos salgamos de la línea oficial del producto y puede traer dolores de cabeza en el futuro.

Bien, pues por esta razón, la última actualización de jQuery se lanzó junto con una nueva biblioteca llamada jQuery Migrate, cuyo objetivo facilitar la migración de código anterior a la versión 1.9, “taponando” los agujeros dejados al saltar a la versión más reciente y devolviendo a jQuery las funcionalidades eliminadas, a la vez que nos informará de los problemas existentes en el código para que podamos corregirlos ya con más tranquilidad.

Su uso es bastante sencillo, basta con incluir la biblioteca justo después de jQuery:

1
2
<script src="Scripts/jquery-1.9.0.min.js"></script>
<script src="Scripts/jquery-migrate-1.1.0.min.js"></script>

Si en lugar de incluir la versión minimizada (.min) de jQuery Migrate nos traemos la de desarrollo (sin el .min), en la consola del navegador nos aparecerán mensajes indicando los problemas detectados en el código:

Mensajes por consola de jQuery Migrate

Espero que os sea de utilidad. Al menos, es un apaño interesante hasta que todo se vuelva a normalizar tras la entrada de jQuery 1.9 en nuestras vidas, cual elefante en cacharrería 😉

Ah, por supuesto, jQuery Migrate también lo tenemos en Nuget bajo la denominación jQuery.Migrate.

Publicado en: Variable not found.

Desacoplando controladores ASP.NET MVC, paso a paso

ASPNETMVCHace poco, en el post donde trataba la inyección de dependencias y desacoplamiento de Hubs de SignalR, el amigo Maxxx comentaba que podría estar bien ver cómo podríamos emplear las mismas técnicas con ASP.NET MVC.

Y ciertamente, me ha parecido muy interesante porque es un escenario que encuentro habitualmente en empresas de desarrollo: comprenden los beneficios de reducir el acoplamiento entre componentes, pero les parece algo demasiado complejo como para aplicar en su día a día porque desconocen cuáles son y cómo usar las herramientas de que disponemos para conseguirlo.

Por tanto, en este post vamos a ver, paso a paso y de forma totalmente práctica, cómo evolucionar desde un controlador MVC fuertemente acoplado a clases del modelo hasta otro totalmente desacoplado usando inyección de dependencias y contenedores de inversión de control.

Y aunque las técnicas y ejemplos que mostraremos están muy enfocados a controladores MVC, los conceptos tratados son aplicables en cualquier tipo de tecnología y arquitectura.

0. Punto de partida

Vamos a partir de la siguiente clase del modelo, de la que sólo mostramos las partes importantes:

1
2
3
4
5
6
public class MyAppServices: IDisposable
{
    public IEnumerable<Product> GetAllProducts() { ... }
    public IEnumerable<Product> GetProductsByCategory(int categoryId) { ... }
    public void Dispose() { ... }
}

Y vemos ahora el siguiente controlador MVC, funcionalmente correcto, que utiliza la clase anterior para obtener datos con los que poblar las vistas. Como curiosidad, deciros que el código está basado en hechos reales:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ProductsController : Controller
{
    public ActionResult Index()
    {
        using (var services = new MyAppServices())
        {
            var data = services.GetAllProducts();
            return View(data);
        }
    }
    public ActionResult ByCategory(int categoryId)
    {
        using (var services = new MyAppServices())
        {
            var data = services.GetProductsByCategory(categoryId);
            return View(data);
        }
    }
}

Observad que en este controlador existe un acoplamiento total con la clase MyAppServices, que es instanciada en cada una de las acciones que hemos implementado. Mucho código repetido, una dependencia total respecto a la implementación de la clase MyAppServices, y la imposibilidad de realizar pruebas unitarias a los métodos.

A continuación, vamos a ir haciendo evolucionar este controlador hasta que alcancemos el punto donde queremos llegar: el desacoplamiento total, manteniendo intactas las funcionalidades proporcionadas.

1. Extraer código de creación y liberación de dependencias

Uno de los aspectos negativos que hemos notado en el controlador de partida es que el código de sus acciones es demasiado extenso, teniendo en cuenta que sólo deben retornar una vista con información obtenida desde el modelo. Esto rompe con el principio básico DRY (Don’t Repeat Yourself).

La utilización del bloque using es muy correcta, es importante asegurarse de que los recursos son liberados al finalizar el tratamiento de la petición. Sin embargo, la instanciación de la clase del modelo la estamos replicando en demasiados puntos… ¿Qué ocurriría si en el futuro no queremos que sea la clase MyAppServices, sino cualquier otra, la usada por las acciones? ¿O si hacemos que el constructor de dicha clase reciba un parámetro? Pues tendríamos que tocar demasiado código. Serían cambios con un impacto muy alto en todos los componentes cohesionados con esta clase.

Para minimizar este riesgo, una primera medida podría ser la refactorización del código, llevándonos las tareas comunes de instanciación y liberación de la clase del modelo a un lugar que pueda ser compartido por las acciones. El resultado podría ser el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ProductsController : Controller
{
    private MyAppServices _services;
    public ProductsController()
    {
        _services = new MyAppServices();
    }
 
    public ActionResult Index()
    {
        var data = _services.GetAllProducts();
        return View(data);
    }
 
    public ActionResult Category(int categoryId)
    {
        var data = _services.GetProductsByCategory(categoryId);
        return View(data);
    }
 
    protected override void Dispose(bool disposing)
    {
        if (disposing)
            _services.Dispose();
    }
}

Como podemos ver, los métodos de acción se han simplificado notablemente, eliminando todo el “ruido” que introducía el bloque using y la instanciación de la clase del modelo. Ahora estas acciones son más fáciles de leer y, por tanto, de modificar y mantener.

Siguiendo con el código anterior, la creación de la instancia nos la hemos llevado al constructor, por lo que si quisiéramos sustituir la clase del modelo por otra ya sólo tendríamos que tocar una línea de código en el controlador. Al llamar en un único punto el new, hemos eliminado casi completamente el pegamento que unía el componente instanciado con el instanciador.

Por último, seguimos manteniendo el control sobre el tiempo de vida de MyAppServices. Se instancia en el constructor del controlador, y se libera justo al acabar el proceso de la petición, aprovechando que podemos sobrescribir el método Dispose().

Vamos mejorando, pero aún hay mucho por hacer 🙂

2. Abstracción de las clases del modelo

Aunque la refactorización anterior nos ha llevado a un código más limpio, aún seguimos teniendo un controlador muy acoplado a la clase MyAppServices. El próximo paso será romper esta cohesión abstrayéndonos mediante interfaces.

La idea es eliminar de nuestro controlador la referencia a la clase concreta del modelo que estamos usando. Para ello, realizaremos dos operaciones:

  • En primer lugar, extraeremos un interfaz con los miembros que nos interesen desde la clase MyAppServices, a la que llamaremos IAppServices. Y por supuesto, reflejamos en la clase del modelo que implementa ese interfaz, de forma que el asunto quedaría algo así:    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public interface IAppServices: IDisposable
    {
        IEnumerable<Product> GetAllProducts();
        IEnumerable<Product> GetProductsByCategory(int categoryId);
    }
    public class MyAppServices: IAppServices
    {
        // ...
    }
  • En segundo lugar, modificamos el controlador, de forma que el miembro _services deje de ser del tipo MyAppServices y pase a usar el nuevo interfaz:    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class ProductsController : Controller
    {
        private IAppServices _services;
     
        public ProductsController()
        {
            _services = new MyAppServices();
        }
     
        // ... Action methods and Dispose
    }

Aunque pueda parecer lo contrario, lo que hemos hecho es realmente importante. Ahora, salvo en el constructor, no queda en nuestra clase controlador ninguna referencia a la clase concreta del modelo que estamos utilizando. De cara a la implementación de las acciones, nos da igual qué objeto se encuentre almacenado en _services, lo único que nos interesa es que cumpla el contrato definido por la interfaz IAppServices; el uso de esta abstracción es un paso más hacia el desacoplamiento total.

Veamos ahora cómo resolver ese “salvo en el constructor”…

3. Inyección de Dependencias

En este momento tenemos ya un código de controlador bastante limpio y desacoplado de la clase del modelo, pero aún seguimos teniendo un poco de “pegamento” en el constructor.

Si quisiéramos sustituir la implementación MyAppServices por otra, aún tendríamos que modificar todos los controladores que usaran esta técnica.

Tampoco seríamos capaces aún de realizar pruebas unitarias a las acciones, puesto que éstas implicarían la ejecución de código de MyAppServices. Y sabemos que esto no serían pruebas unitarias, sino de integración, ¿verdad?

Bien, ¿y cómo podríamos solucionar esto? Pues mediante la inyección de dependencias. Este principio de diseño sugiere la eliminación de dependencias rígidas de un componente (como la provocada por el uso del new en el constructor) haciendo que sea otro componente el que suministre al primero todos aquellos objetos que necesite para funcionar.

En otras palabras, si desde ProductsController necesitamos para funcionar una instancia de cualquier tipo que implemente las operaciones definidas en el interfaz IAppServices, simplemente debemos obligar a que alguien nos la suministre.

La implementación práctica de este principio en nuestro ejemplo se podría materializar de la siguiente forma, modificando ligeramente el constructor:

1
2
3
4
5
6
7
8
9
10
11
public class ProductsController : Controller
{
    private IAppServices _services;
 
    public ProductsController(IAppServices services)
    {
        _services = services;
    }
 
    // Action methods and Dispose
}

Observad que ahora el constructor de la clase exige que alguien le suministre las dependencias, u objetos que necesita para funcionar correctamente; no se podrá instanciar el controlador de otra forma. Y dado que tenemos ya definido el interfaz, no es necesario indicar un tipo concreto, simplemente el contrato que define las operaciones que usaremos desde el controlador, sea cual sea la clase que las implemente.

En estos momentos ya hemos eliminado por completo el acoplamiento entre ProductsController y MyAppServices: de hecho, no queda ninguna referencias hacia la clase concreta del modelo que usamos en el controlador.

Otra ventaja de haber dado este paso es que nos permite ya realizar pruebas unitarias completas sobre nuestros métodos de acción. Desde el código de test podríamos instanciar la clase ProductsController, suministrarle una referencia hacia un objeto falso (que implemente el interfaz requerido) y comprobar el funcionamiento de las acciones, sin salir de su ámbito.

Ah, antes de continuar, permitidme un consejo que suelo dar a los equipos de desarrollo con los que trabajo:

Programa siempre tus componentes como si fueras a hacerles pruebas unitarias.
Aunque no las hagas.

Es decir, el hecho de no realizar pruebas unitarias no debe valer como excusa para no aplicar principios y buenas prácticas, como el desacoplamiento o la inyección de dependencias, cuyo uso sólo traerá beneficios a vuestras aplicaciones.

Por recapitular un poco, el código del controlador lo tendríamos en este momento de la siguiente forma:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ProductsController : Controller
{
    private IAppServices _services;
 
    public ProductsController(IAppServices services)
    {
        _services = services;
    }
 
    public ActionResult Index()
    {
        var data = _services.GetAllProducts();
        return View(data);
    }
 
    public ActionResult Category(int categoryId)
    {
        var data = _services.GetProductsByCategory(categoryId);
        return View(data);
    }
 
    protected override void Dispose(bool disposing)
    {
        if (disposing)
            _services.Dispose();
    }
}

Sin embargo, si en estos momentos ejecutamos nuestra aplicación, veremos que no funciona: ASP.NET MVC es incapaz de crear un controlador ProductsController, puesto que no dispone de un constructor sin parámetros. Es totalmente lógico: el framework no puede llamar al constructor porque no sabe qué parámetro enviarle.

4. Suministrando dependencias al controlador con un Dependency Resolver

Ojo, que lo que vamos a ver en este punto es sólo por “cultura general”, para conocer los mecanismos que hay por detrás de ASP.NET MVC, pero no es estrictamente necesario. Las técnicas mostradas aquí son ampliamente superadas por las que utilizaremos en el siguiente epígrafe.

Bueno, antes hemos comentado que para instanciar un controlador del tipo ProductsController, “alguien” debe suministrarle las dependencias, es decir, llamar a su constructor pasándole como parámetro la instancia de la clase del modelo a utilizar. 

La instanciación del controlador es un proceso que se lleva a cabo desde el interior del framework, aunque existen varias fórmulas que permiten intervenir en este proceso. Una posibilidad es usar el Dependency Resolver, de forma similar a como describimos hablando de SignalR.

El Dependency Resolver es un mecanismo incluido en ASP.NET MVC que actúa como suministrador de instancias centralizado. Cuando el framework necesita crear un objeto de cualquier tipo, en primer lugar solicita la nueva instancia al Dependency Resolver, y sólo si éste no se la facilita, lo crea de forma manual.

Así, cuando ASP.NET MVC va a instanciar el controlador ProductsController, primero pregunta al Dependency Resolver si le puede proporcionar una instancia. Si tomamos el control en este punto, podríamos automatizar la inyección de dependencias en los controladores.

Para ello, debemos crear una clase que implemente el interfaz IDependencyResolver, e informar al framework que se trata del nuevo componente encargado de la resolución. El código simplificado de esta clase podría ser el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyDependencyResolver: IDependencyResolver
{
    public object GetService(Type serviceType)
    {
        if (serviceType == typeof (ProductsController))
            return new ProductsController(new MyAppServices());
        return null;
    }
 
    public IEnumerable<object> GetServices(Type serviceType)
    {
        return Enumerable.Empty<object>();
    }
}

Como seguro podéis intuir, el método GetService() será el llamado por ASP.NET MVC en el momento de instanciar el controlador. Por otra parte, es necesario registrar en el framework este componente, lo cual podemos conseguirlo mediante el siguiente código, ejecutado durante la inicialización de la aplicación (en el método Application_Start() del global.asax puede ser un buen lugar para hacerlo):

1
DependencyResolver.SetResolver(new MyDependencyResolver());

De esta forma, al ejecutar nuestra aplicación, veríamos que todo funciona de nuevo. El framework está llamando al nuevo Dependency Resolver, y nuestro controlador está siendo creado junto con las dependencias que necesita satisfacer, en este caso el objeto que implemente IAppServices.

Además, en el Dispose() del controlador seguimos manteniendo la liberación de recursos de nuestra clase del modelo, por lo que todo seguirá funcionando correctamente.

Pero esto es demasiado trabajo, ¿no? Pensad que podemos tener controladores con dependencias hacia varios objetos, y que incluso éstos podrían tener, a su vez, dependencias con otros objetos, por lo que la instanciación manual del controlador podría ser bastante tediosa. También deberíamos introducir en los controladores la llamada a la liberación de recursos de las dependencias, y es bastante fácil que se nos olviden algunos…

5. Usar Contenedores de Inversión de Control

La solución definitiva a nuestros problemas pasa por el uso de los llamados contenedores de inversión de control (IoC Containers), que, entre otras cosas, son componentes especializados en la creación de instancias de objetos, así como en la gestión del ciclo de vida de éstas. En cierto sentido son similares a los dependency resolvers que hemos comentado anteriormente, pero van más allá y nos lo pondrán todo bastante más fácil.

Muy resumidamente, un contenedor IoC mantiene un registro de asociaciones entre interfaces y clases concretas. Cuando un componente externo solicita al contenedor una instancia de un tipo determinado, éste utiliza su registro para satisfacer las dependencias que sean requeridas en cada momento.

Así, si alguien solicita al container una instancia de la clase “X” cuyo constructor requiere como parámetro una instancia del interfaz “I”, el contenedor buscará en su registro la clase asociada a dicho interfaz y obtendrá automáticamente una instancia de ésta. Una vez la tenga, instanciará la clase “X” pasándole como parámetro a su constructor el objeto creando anteriormente.

Existen gran cantidad de contenedores de inversión de control (Ninject, Unity, Automapper, Autofac, Windsor, etc.), y la elección de uno u otro es muchas veces sólo cuestión de preferencias personales. Además, dado que se trata de componentes estándar y válidos para casi cualquier tipo de proyecto, se pueden encontrar extensiones que facilitan su integración en ASP.NET MVC, por lo que es conveniente siempre elegir uno que ya esté preparado para este framework.

Todos los contenedores son conceptualmente iguales; para un uso básico simplemente notaremos que hay entre ellos diferencia de sintaxis, por lo que vamos a centrarnos en uno de los más populares: Unity.

Unity (http://unity.codeplex.com/) es un potente contenedor promovido por  la iniciativa de Patterns & Practices de Microsoft. Como otros, dispone de extensiones específicas para ASP.NET MVC y se puede instalar muy fácilmente a través de Nuget usando el package “Unity.Mvc3” (ojo, que a pesar de su desafortunado nombre es válido también para la versión 4 del framework):

PM> Install-Package unity.mvc3

Una vez instalado, el siguiente paso es registrar en el contenedor las asociaciones entre interfaces y clases concreta en el archivo bootstrapper.cs que la instalación habrá dejado en el raíz de nuestro proyecto. Como la ubicación por defecto de este archivo es terrible, os recomiendo moverla a App_Start, puesto que el registro de clases se debe ejecutar durante el arranque de la aplicación y así seguimos las convenciones de ubicación de archivos.

En nuestro caso, lo único que tenemos que indicar es que cuando alguien solicite al contenedor una instancia para el interfaz IMyServices, se debe obtener y retornar un objeto de la clase concreta MyAppServices. Además, vamos a indicar que su tiempo de vida se limitará a la petición actual, es decir, que debe ser liberada cuando la petición haya sido procesada; el framework detectará que implementa IDisposable e invocará su método Dispose() de forma automática.

Todo esto se consigue en Unity introduciendo en bootstrapper.cs la siguiente línea:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// File: bootstrapper.cs:
public static class Bootstrapper
{
    public static void Initialise()
    {
        var container = BuildUnityContainer();
        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
    }
 
    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();
        container.RegisterType<IAppServices, MyAppServices>(
            new HierarchicalLifetimeManager()
        );
        return container;
    }
}

Nota: si sois de los que preferís remangaros y hacer las cosas por vosotros mismos, os recomiendo que leáis este brutal post de Eduard donde trata sobre la inyección de dependencias y cómo conseguir que las instancias tengan un tiempo de vida per-request. Muy aconsejable.

Volviendo al código, observad que si en el futuro queremos sustituir en la aplicación la implementación de MyAppServices por otra cualquiera que implemente el interfaz IAppServices, sólo tendríamos que modificar el registro en el contenedor IoC. El controlador no se vería afectado de ninguna forma.

En este mismo punto incluiríamos todas las dependencias necesarias para que puedan construirse los objetos. Si, por ejemplo, MyAppServices depende a su vez de una clase que implementa IDataContext, debemos registrar también una asociación para dicho interfaz, de forma que el contenedor tenga toda la información necesaria para satisfacer las dependencias necesarias y construir el grafo de objetos completo.

En cualquier caso, una vez registradas todas las asociaciones en el método BuildUnityContainer(), sólo nos faltaría introducir una llamada a Bootstrapper.Initialize() en el método Application_Start() del global.asax, de forma que se ejecute durante la inicialización del sistema.

Además, dado que hemos indicado al contenedor que la instancia creada debe ser liberada al finalizar la petición, su método Dispose() será ejecutado automáticamente, por lo que ya podemos eliminar del controlador la implementación de Dispose(), desde donde antes realizábamos esta operación de forma manual.

Y hechos estos dos últimos ajustes, podemos decir que hemos terminado 🙂

6. Resumiendo

Como podemos ver a continuación, hemos conseguido que nuestro controlador quede bastante limpio y testeable, y sus acciones muy concisas y centradas en sus objetivos funcionales. Además, su constructor deja clarísimas las dependencias del mismo, y se mantiene un total desacoplado de las clases del modelo utilizadas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ProductsController : Controller
{
    private IAppServices _services;
 
    public ProductsController(IAppServices services)
    {
        _services = services;
    }
 
    public ActionResult Index()
    {
        var data = _services.GetAllProducts();
        return View(data);
    }
 
    public ActionResult Category(int categoryId)
    {
        var data = _services.GetProductsByCategory(categoryId);
        return View(data);
    }
}

Hemos eliminado también el código de liberación de dependencias, y hemos delegado al contenedor la instanciación, a veces compleja, de todos los componentes usados.

Aunque al hacerlo paso a paso el post ha quedado un poco extenso y podría llegar a parecer complejo, nada más lejos de la realidad. Lo único que tenemos que hacer y tener en cuenta para conseguir este tipo de controladores es, a modo de resumen:

  • Detectar cuáles son los objetos de los que depende nuestro controlador, es decir, determinar las dependencias que vamos a eliminar.
  • Preparar el constructor para recibir las dependencias, siempre en forma de interfaces, y almacenarlas en miembros privados.
  • Desde las acciones, usar los componentes externos a través los miembros privados en los que los hemos almacenado en el constructor.
  • Instalar un contenedor IoC y registrar en él las asociaciones entre las interfaces y clases, con objeto de que los controladores puedan ser instanciados automáticamente, siempre teniendo en cuenta la gestión del tiempo de vida de los objetos.
  • Si las dependencias así lo requieren, implementar en ellas el interfaz IDisposable, de forma que el container se encargue de liberar sus recursos al finalizar el proceso de la petición.

Podéis descargar el proyecto que hemos implementado en este post desde mi Skydrive.

Espero que os sea útil, y los que todavía no habéis dado el salto a este tipo de diseño os animéis a probarlo. Os aseguro que no os vais a arrepentir 🙂

Publicado en Variable not found.

Mi libro: Introducción a ASP.NET SignalR

Seguro que estaréis al tanto de que durante los últimos tiempos he estado trabajando junto con los amigos de Krasis/CampusMVP en la publicación de un libro sobre SignalR. De hecho, probablemente también sabréis que la versión en inglés del mismo se presentó y comenzó a distribuir para Estados Unidos (bueno, y para todo el mundo) hace unas semanas, cuando aún SignalR se encontraba en Release Candidate, y ha conseguido atraer a varios miles de lectores y muy buenas críticas durante este periodo.

Introducción a ASP.NET SignalRBueno, pues ya de forma oficial, me complace informaros de que desde hace unos días en la tienda de Krasis está disponible mi primer libro, y el primero del mundo sobre este nuevo framework: Introducción a ASP.NET SignalR. Revisado, actualizado a la versión 1.0.1 de SignalR y, por supuesto, en español 🙂

Ante todo, agradecer a Krasis, y en concreto a José Manuel Alarcón, su continuo apoyo, colaboración e imparable empuje, sin los cuales no habría sido posible llegar a materializar este proyecto.

Es un libro relativamente corto, unas ochenta páginas, que de momento va a ser distribuido exclusivamente en formato electrónico. De esta forma, se evitan los costes asociados a la impresión, manipulación y logística, y se permite su comercialización a un precio creo que bastante razonable 😉

Y ya entrando en los contenidos, a lo largo del texto hace una introducción a los protocolos, tecnologías y técnicas que hay por detrás de las aplicaciones multiusuario en tiempo real, e introduce SignalR desde cero, mostrando mediante código y ejemplos cómo podemos sacarle partido a este impresionante marco de trabajo y construir increíbles aplicaciones web  (¡y no web!) de forma pasmosamente sencilla.

A grandes rasgos, el recorrido que hacemos es el siguiente:

  • En primer lugar, tras una breve introducción, explicamos detalladamente las limitaciones de HTTP para la implementación de sistemas multiusuario en tiempo real, y estudiamos detalladamente los protocolos y técnicas que podemos usar para implementar escenarios Push.
  • A continuación, presentamos SignalR y proporcionamos una visión de alto nivel del framework.
  • Seguidamente, se describe la implementación de servidores y clientes javascript usando persistent connections, el nivel más bajo de abstracción facilitado por SignalR.
  • En el siguiente capítulo ascendemos de nivel de abstracción y comenzamos a desarrollar utilizando Hubs en servidor y distintos enfoques para consumir los servicios desde javascript.
  • A continuación estudiamos cómo enlazar aplicaciones más convencionales con servicios en tiempo real proporcionados por SignalR, gracias a la capacidad de consumirlos desde procesos externos.
  • Y por último, demostrando que este framework no sólo es utilizable en entornos web, aprenderemos a acceder a servicios SignalR desde clientes de todo tipo, y a alojarlos en procesos no ASP.NET, como podría ser una aplicación de consola o un servicio del sistema operativo.

Exceptuando los dos primeros bloques, que son de contenido más teórico, todo el texto está salpicado con mucho código, y los capítulos acaban con la implementación de un ejemplo completo para ilustrar los conceptos tratados a lo largo de los mismos. Estos ejemplos, por supuesto, pueden ser descargados para probarlos y juguetear con ellos directamente.

Espero que lo disfrutéis y, sobre todo, os sea de utilidad para abriros a nuevas posibilidades e introducir en vuestras aplicaciones sorprendentes funcionalidades multiusuario en tiempo real. ¡Uau!

El árbol, los hijos, el libro… creo que ya no me falta nada 😉

Publicado en Variable not found.

Eliminar el botón de los campos password de IE10

Internet Explorer 10Hace sólo unos días veíamos cómo eliminar y personalizar los botones que Internet Explorer 10 añade a nuestros cuadros de edición estándar, pero nos dejábamos por detrás un caso especial: los controles de edición de contraseñas, o sea, los <input type="password"> de toda la vida.

En esta ocasión, IE10 muestra por cortesía un pequeño icono con forma de ojo, que permite visualizar el contenido del campo mientras lo mantenemos pulsado:

Botón de visualizar contraseñas en IE10
Si por cualquier razón queremos eliminar este botón, debemos utilizar una técnica similar a la que vimos en el post anterior, esta vez utilizando el pseudoselector -ms-reveal, así:

1
2
3
input::-ms-reveal {
    display: none;
}

Y por supuesto, podríamos utilizar también este enfoque para personalizarlo y adaptarlo mejor al look de nuestro sitio web:

1
2
3
4
input::-ms-reveal {
    color: white;
    background-color: red;
}

Con lo que tendríamos un resultado:

image

Publicado en: Variable not found.

Eliminar el botón de limpiado de controles de IE10

Internet Explorer 10Va un truquillo rápido. Los que ya habéis saltado a Internet Explorer 10 seguro habréis notado el pequeño botón que este navegador añade a los cuadros de edición estándar cuando obtienen el foco, y que permite limpiar rápidamente su contenido:

Botón de limpiar campo de IE10
Pues bien, hay veces que a nivel de diseño no nos interesa que se muestre la pequeña “X” en los controles, su posición entra en conflicto con otro elemento visual, o simplemente no queremos aportar esta funcionalidad,  por lo que es posible desactivar esta característica de los <input> usando CSS:

1
2
3
input::-ms-clear{
    display: none;
}

Tan sencillo como eso.

Pero seguro que te estás preguntando, ¿y en vez de eliminarla puedo personalizarla? Pues un poco también 😉 Observad el siguiente código:

1
2
3
4
5
input::-ms-clear{
    background-color: red;
    color: white;
    border: 1px solid #808080;
}

En tiempo de ejecución, esa discreta e insípida “X” se habría convertido en algo bastante más contundente 😉

image

Publicado en: Variable not found.

¿Añadir una barra al final de las URL?

ASP.NET MVCHace poco veíamos que el nuevo sistema de routing usado por proyectos MVC 4 permitía una cierta configuración del formato de URL generadas por la aplicación al usar helpers como Url.Action() o Html.ActionLink(), y cómo usando una simple línea de código podíamos hacer que las rutas se generaran usando sólo minúsculas.

Pues bien, al igual que en ese caso, en los proyectos que usen la última versión del ensamblado System.Web.Routing, por ejemplo si compilamos aplicaciones Webforms, MVC 3 o 4 para .NET 4.5, también es posible hacer que las URLs generadas acaben con una barra inclinada estableciendo a true la propiedad AppendTrailingSlash :

1
2
3
4
5
6
7
8
9
10
11
12
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
    routes.AppendTrailingSlash = true;
 
    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

La siguiente tabla muestra algunos ejemplos de cómo afecta el valor de esta propiedad a la hora de generar una ruta:

Instrucción AppendTrailingSlash
true false
Url.Action("About", "Home") /Home/About/ /Home/About
Url.Action("Edit", "Product", new {id = 1}) /Product/Edit/1/ /Product/Edit/1
Url.Action("Edit", "Product", new {id = 1, x=2}) /Product/Edit/1/?x=2 /Product/Edit/1?x=2

Pero, ¿por qué tendríamos que añadir una barra al final de las URL?

Es cierto que, siguiendo las tradiciones y buenas costumbres de siempre, una URL debería acabar en una barra si no apunta a un archivo con objeto de facilitar la vida al servidor. Una petición a la dirección servidor.com/algo es ambigua porque el servidor, a priori, no puede conocer si el recurso solicitado «algo» es un archivo o un directorio; si, en cambio, la petición se realiza hacia servidor.com/algo/ queda más claro que lo que se pretende es obtener el contenido de una carpeta, y en teoría podría agilizarse el proceso de búsqueda del recurso.

No he encontrado tampoco directrices que indiquen claramente en qué afecta la aparición de esa terminación en la respuesta que debe enviar el servidor. Podemos encontrar servidores que ante una petición como servidor.com/algo retornan el mismo recurso que si la URL incluyera la barra final; en otros, en cambio, se opta por retornar una redirección hacia servidor.com/algo/ (con la barra) con objeto de indicar al cliente que «esa dirección es la buena» y evitar contenidos duplicados (el mismo contenido accesible desde distintas URL). Esto último podéis comprobarlo creando una aplicación web cualquiera y accediendo a localhost:xxx/content mientras trazáis las peticiones con Fiddler o las developer tools.

En aplicaciones ASP.NET en las se usa el sistema de routing, donde no existe el concepto «directorio» como tal, el uso de estas barras no tienen demasiado sentido. Por ejemplo, en MVC las peticiones se mapean contra acciones en un controlador; en la práctica, da igual si una URL acaba o no con una barra, puesto que será procesada por la misma acción y retornará el mismo resultado.

Por tanto, con este tipo de sistemas probablemente la elección se trate más de una cuestión de gustos que otra cosa. Simplemente va de decidir un estilo y ceñirse a él en toda la aplicación; y si lo que elegimos es acabar las URL con barras, ya sabemos que el sistema de routing de ASP.NET lo soporta de serie 🙂

Por mi parte, hasta ahora nunca he usado las barritas en las URL y, salvo que encuentre algún buen motivo, creo que seguiré sin hacerlo.

Y vosotros, ¿qué opináis del tema? ¿Barra sí o barra no? (Y no me refiero a las de los bares ;-P)

Publicado en: Variable not found.

Inyección de dependencias en Hubs de SignalR

Cuando estamos implementando Hubs de SignalR, podemos encontrarnos fácilmente con que éstos necesitan utilizar componentes externos para llevar a cabo su tarea. Por ejemplo, es bastante probable que un servicio en tiempo real proporcionado por un Hub tenga que utilizar una clase de servicios o cualquier otro componente externo de una aplicación, como en el siguiente código:

1
2
3
4
5
6
7
8
9
10
11
public class MyHub: Hub
{
    public Task sendMessage(string text)
    {
        using (var services = new LogServices())
        {
            services.Log(Context.ConnectionId, text);
            return Clients.All.receiveMessage(text);
        }
    }
}

Como puede intuirse, en el interior del método sendMessage() se utiliza un componente externo, implementado en la clase LogService, para guardar una traza con los mensajes enviados a través de nuestro sistema.

Aunque funcionaría bien, el código anterior introduciría un acoplamiento demasiado fuerte entre el Hub y la clase LogService, y está claro que eso no puede ser bueno. Estaríamos haciendo totalmente dependiente la primera clase de la segunda y esto podría afectarnos en el futuro vistas al mantenimiento y evolución del software, o imposibilitar la realización de pruebas unitarias de forma correcta.

1. Desacoplando componentes

Como buenos seguidores que somos de los principios SOLID, seguro que ya sabemos que la solución pasa por aplicar Inyección de Dependencias (la “D” de SOLID) y la abstracción de la implementación concreta mediante interfaces. Lo que estaríamos buscando es una codificación funcionalmente equivalente a la anterior pero con un mínimo nivel de acoplamiento, como la siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyHub: Hub
{
    private readonly ILogServices _logServices;
 
    public MyHub(ILogServices logServices)
    {
        _logServices = logServices;
    }
 
    public Task sendMessage(string text)
    {
        _logServices.Log(Context.ConnectionId, text);
        return Clients.All.receiveMessage(text);
    }
}

Observad las dos diferencias principales respecto al código que vimos al principio del post:

  • MyHub ha dejado de depender de la clase LogService. Cualquier referencia a las operaciones que necesitamos realizar se hacen a través del interfaz ILogService, que será el encargado de abstraernos de la implementación concreta a utilizar.  
  • No instanciamos ningún objeto. El componente externo que proporciona las operaciones requeridas por el interfaz nos llega en el constructor del Hub y lo guardamos en un miembro privado de la clase para usarlo posteriormente.

Con esta implementación hemos conseguido un método sendMessage() mucho más legible y hemos roto la fuerte dependencia entre éste y la clase que usaremos para guardar el mensaje en el log, lo cual podría permitirnos en el futuro sustituir su implementación de forma transparente siempre que se siga cumpliendo el contrato establecido por el interfaz. Y, por supuesto, podríamos hacer pruebas unitarias sobre la clase muy fácilmente.

Sin embargo, el Hub anterior no funcionaría de forma directa puesto que SignalR no sería capaz de crear una instancia de MyHub ante la llegada de un mensaje desde el lado cliente al no existir un constructor sin parámetros. Es un fenómeno similar al que encontramos en sistemas ASP.NET MVC o WebAPI cuando nuestros controladores no tienen constructores públicos sin parámetros.

¿Y cómo solucionamos esto?

2. Registrando el Hub en el Dependency Resolver

SignalR, como otras tecnologías pertenecientes al stack ASP.NET como MVC o WebAPI, utiliza en una gran cantidad de puntos un mecanismo llamado Dependency Resolver para crear instancias de clases que necesita para trabajar. El Dependency Resolver utilizado por SignalR es un objeto de tipo IDependencyResolver  que se encuentra almacenado en la propiedad GlobalHost.DependencyResolver.

Su funcionamiento, a grandes rasgos, es el siguiente: cuando SignalR necesita instanciar un objeto de cualquier tipo, lo primero que hace es ponerse en contacto con el Dependency Resolver para ver si éste puede ofrecérsela (algo así como “oye, ¿me puedes facilitar una instancia del tipo XYZ?”).

Si el Dependency Resolver puede proporcionar una instancia del tipo que se le está solicitando, la retornaría directamente (“pues sí, ahí la llevas”). En caso contrario retornaría un valor nulo, con lo cual SignalR sería el encargado de crear la instancia.

Y los Hub no son una excepción. Si un cliente se conecta, desconecta, o realiza una llamada a un método de MyHub, SignalR llamará al mecanismo de resolución de dependencias para ver si puede proporcionarle una instancia de dicho tipo, que es la que procesará el mensaje. Lo único que tenemos que hacer para que todo funcione es instruir adecuadamente al Dependency Resolver, es decir, decirle cómo debe instanciarla cuando esta solicitud se produzca.

Esto podríamos conseguirlo de la siguiente forma:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Global : System.Web.HttpApplication
{
 
    protected void Application_Start(object sender, EventArgs e)
    {
        GlobalHost.DependencyResolver.Register(
            typeof (MyHub),
            () => new MyHub(new LogServices())
        );
        RouteTable.Routes.MapHubs();
    }
 
}

Observad que el método Register() permite asociar un tipo de datos (MyHub) a un delegado, en este caso implementado mediante una función lambda que retorna el objeto instanciado, y donde ya estamos pasando a su constructor las dependencias que requiere. Cuando alguien solicite al Dependency Resolver una instancia de MyHub, se le retornará el resultado de ejecutar la función especificada.

Por supuesto sería totalmente posible utilizar un contenedor de inversión de control que se encargara de parte del trabajo sucio asociado a la instanciación de objetos y, sobre todo, si se trata de grafos complejos. El siguiente ejemplo muestra cómo podríamos integrar en el código anterior un kernel de Ninject, aunque sería bastante parecido si usamos cualquier otro:

1
2
3
4
5
6
7
8
9
10
11
12
protected void Application_Start(object sender, EventArgs e)
{
    var kernel = new StandardKernel();
    kernel.Bind<ILogServices>().To<LogServices>();
    // ... register other dependencies
 
    GlobalHost.DependencyResolver.Register(
        typeof(MyHub),
        () => kernel.Get<MyHub>()
    );
    RouteTable.Routes.MapHubs();
}

Aunque la verdad es que si vamos a utilizar un contenedor de IoC, la opción más razonable sería crear un Dependency Resolver personalizado y decirle a SignalR que lo utilice…

3. Creando un Dependency Resolver personalizado

La propiedad GlobalHost.DependencyResolver que hemos usado anteriormente para acceder al componente encargado de resolver las dependencias es de lectura/escritura, lo que sugiere la posibilidad de sustituirlo por otro más a nuestra medida.

En este caso, el componente utilizado debe implementar el interfaz IDependencyResolver presente en el espacio de nombres Microsoft.AspNet.SignalR, aunque nos costará menos trabajo crear una clase que herede de DefaultDependencyResolver, la implementación por defecto que viene de serie con SignalR, en la que sobrescribiremos los métodos cuyo comportamiento nos interese modificar:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyDependencyResolver : DefaultDependencyResolver
{
    private IKernel _kernel;
 
    public MyDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }
 
    public override object GetService(Type serviceType)
    {
        var instance = _kernel.TryGet(serviceType);
        return instance ?? base.GetService(serviceType);
    }
 
    public  override IEnumerable<object> GetServices(Type serviceType)
    {
        var instances = base.GetServices(serviceType);
        return _kernel.GetAll(serviceType).Concat(instances);
    }
}

Una vez creado nuestro componente de resolución de dependencias, podemos crear una instancia y establecerla en GlobalHost.DependencyResolver o bien pasarla como parámetro en el momento de registrar las rutas de los Hubs, quedando así un código de inicialización más simple:

1
2
3
4
5
6
7
8
protected void Application_Start(object sender, EventArgs e)
{
    var kernel = new StandardKernel();
    kernel.Bind<ILogServices>().To<LogServices>();
    // ... register other dependencies
 
    RouteTable.Routes.MapHubs(new MyDependencyResolver(kernel));
}

De nuevo, estos ejemplos están implementados usando Ninject, pero realmente costaría bastante poco trabajo adaptarlos a cualquier otro contenedor IoC.

Publicado en Variable not found.

Simular una conexión lenta con Fiddler

Me abuuuuurroNormalmente hacemos pruebas de nuestros desarrollos web sobre nuestro propio equipo, donde la transferencia de datos es prácticamente inmediata, en servidores de prueba ubicados en una red de área local, o incluso sobre un servidor de producción al que accedemos mediante una conexión a Internet de gran capacidad.

Sin embargo, nuestras aplicaciones web son muy diferentes cuando el cliente no dispone de una conexión de alta velocidad. Lo que nosotros percibimos en tiempo de desarrollo como una maravilla de agilidad, espectacularidad y facilidad de uso, puede ser un auténtico desastre para el cliente si no hemos tenido en cuenta que no todo el mundo puede disfrutar de conexiones de alta calidad.

Por esta razón, es interesante realizar de vez en cuando pruebas de nuestros sistemas reduciendo de forma artificial el ancho de banda disponible, de forma que podamos detectar en qué puntos podemos mejorar la experiencia del usuario en estos escenarios.

FiddlerUna forma muy sencilla para hacerlo es utilizando Fiddler. Probablemente todos lo conoceréis, pues es una de esas herramientas gratuitas que con el tiempo se han hecho indispensables para los desarrolladores, ayudándonos a ver qué es lo que pasa por debajo de aplicaciones que utilizan HTTP para enviar o recibir datos desde el exterior.

Básicamente se trata de un proxy que intercepta todas las conexiones HTTP/HTTPS originadas en nuestro ordenador permitiéndonos guardaras en un registro, inspeccionarlas en detalle, repetirlas, e incluso modificar su contenido sin demasiado esfuerzo. Además, incluye un potente mecanismo que permite extenderlo mediante reglas programadas en lenguaje JScript.NET o plugins en forma de ensamblados .NET.

Rules > Performance > Simulate modem speeds

Fiddler trae de fábrica un conjunto de reglas que permiten personalizar el tratamiento de las peticiones HTTP que entran y salen de nuestra máquina, y una de ellas tiene el expresivo nombre “Simulate modem speeds”. Seguro que podréis intuir su utilidad 😉

Así, basta con acudir al menú “Rules” de Fiddler, abrir el submenú “Performance” y seleccionar la opción oportuna:

Rules > Performance > Simulate modem speeds

La selección de esta opción hará que la velocidad de transmisión y recepción se reduzca a la habitual en un módem de 56Kbps. En concreto:

  • Se introduce en la petición un retardo de 300ms por cada Kbyte enviado desde el navegador u aplicación cliente.
  • Por cada Kbyte recibido en la respuesta de la petición, se introduce un retardo de 150ms.

De esta forma ya podemos tener una primera solución para poder probar nuestra web a una velocidad muy inferior a lo habitual, y comenzar a ver qué puntos podríamos mejorar.

Modificar los ajustes

La lógica de cada una de esas opciones que podéis activar o desactivar en el menú “Rules” está implementada mediante scripting, lo que deja abierta la posibilidad de alterarlas para adaptarlas a nuestras necesidades.

Por ejemplo, podríamos definir tiempos de retardo a nuestro antojo, y así probar cómo funcionaría nuestro sistema con distintas configuraciones de red para determinar cuál sería el mínimo razonable para utilizar un servicio.

Customizing rules in FiddlerAccediendo al menú “Rules > Customize Rules” tendremos acceso al código fuente del script de reglas usado por Fiddler, que se abrirá automáticamente en el bloc de notas de Windows para que podamos modificarlo a nuestro antojo. Eso sí, siempre con precaución, aunque si metemos la pata podemos seguir estas instrucciones para dejarlo todo como estaba.

El código que introduce los retardos podemos localizarlo fácilmente buscando el texto “modem” en el script, y es como sigue:

1
2
3
4
5
6
if (m_SimulateModem) {
   // Delay sends by 300ms per KB uploaded.
   oSession["request-trickle-delay"] = "300";
   // Delay receives by 150ms per KB downloaded.
   oSession["response-trickle-delay"] = "150";
}

La variable m_SimulateModem contiene un valor booleano que indica si la opción del menú está marcada o no, y, en caso afirmativo, los valores de los retardos se introducen en los parámetros request-trickle-delay y response-trickle-delay del objeto oSession, que contiene distintos settings que permiten modificar  el comportamiento de Fiddler. En concreto, estos dos parámetros indican los milisegundos a esperar antes de cada kbyte enviado, y antes de cada kbyte recibido, respectivamente.

Por tanto, si queremos limitar la velocidad de descarga aproximadamente a 100KBytes/s en un entorno local, bastaría con introducir en response-trickle-delay un retardo de 10ms:

1
2
// Delay receives by 10ms per KB downloaded.
oSession["response-trickle-delay"] = "10";

Al salvar el archivo se aplicarán los cambios en la configuración.

Añadir nuevas configuraciones

Vale, con lo visto anteriormente ya podemos modificar la velocidad de descarga, pero siempre machacando los valores utilizados por la opción del menú “Simulate Modem Speeds”. Sin embargo, podemos mejorar esto bastante creando nuestras propias opciones en el menú que nos permitan activar y desactivar de forma sencilla otras configuraciones, por ejemplo para seleccionar distintas velocidades a simular.

Para ello, primero localizamos el lugar del script donde se añade la opción “Simulate Modem Speeds”, y añadimos una opción similar para nuestro objetivo:

1
2
3
4
5
6
7
// Cause Fiddler to delay HTTP traffic to simulate typical 56k modem conditions
public static RulesOption("Simulate &Modem Speeds", "Per&formance")
var m_SimulateModem: boolean = false;
 
// Cause Fiddler to delay HTTP traffic to 100Kbytes/sec
public static RulesOption("Simulate 100Kbytes/sec", "Per&formance")
var m_Simulate100K: boolean = false;

A continuación, introducimos la condición para activar los límites cuando la variable booleana que hemos definido sea true. Para no complicarnos mucho, lo hacemos justo debajo del lugar donde ya hemos visto anteriormente que se establecen estos valores dependiendo de m_SimulateModem:

1
2
3
4
5
6
if (m_Simulate100K) {
   // For example, delay sends by 40ms per KB uploaded
   oSession["request-trickle-delay"] = "40";
   // Delay receives by 10ms per KB downloaded.
   oSession["response-trickle-delay"] = "10";
}

Salvando el archivo, ya tenemos una nueva opción en el menú para activar nuestro tope de velocidad:

Custom rule

¡Y esto es todo! Así de fácil es usar Fiddler para simular lentitud en las comunicaciones y poder comprobar la usabilidad en ese tipo de escenarios.

Pero antes de que se me olvide, un último comentario importante: todo lo dicho no es válido sólo en aplicaciones web. Estas comprobaciones pueden resultar también bastante clarificadoras en otro tipo de sistemas, como pueden ser aplicaciones Windows Store o de otro tipo que accedan a recursos externos mediante HTTP. Fiddler funcionará con la mayoría de ellas sin problema.

Publicado en Variable not found.

Documentación automática de servicios WebAPI

ASP.NETCuando trabajábamos con los Servicios Web de toda la vida, las herramientas de desarrollo incluían sistemas para generar la documentación básica de los servicios que implementábamos. El estándar WSDL (Web Services Description Language), era un lenguaje basado en XML que permitía describir las funcionalidades de un servicio web aportando gran cantidad de detalles sobre las operaciones, tipos de datos, o direcciones de acceso a las mismas.

Gracias a esto, los desarrolladores podíamos conectarnos fácilmente a un servicio para consultar sus especificaciones técnicas, o incluso generar de forma automática código cliente o proxies que facilitaran el acceso remoto a las funciones publicadas en la red.

Y para los que venimos de esos tiempos, una de las primeras dudas que surgen al comenzar a trabajar con WebAPI es si existe algo similar. Y la respuesta es sí, pero no ;-P

De momento no existe ningún estándar ni especificación que permita describir los servicios WebAPI con la riqueza y formalización que permite WSDL. Esta tecnología se basa únicamente en HTTP, por lo que, a lo sumo, podríamos intuir el comportamiento de los sistemas partiendo de las direcciones de los recursos y los verbos HTTP utilizados, siempre que estén diseñados conformes al estilo REST, por supuesto.

Lo que sí tenemos es un paquete, descargable a través de Nuget, que nos puede ayudar bastante a generar páginas de ayuda y documentación para nuestros API partiendo de la documentación XML que incluyamos en el código. A diferencia de WSDL, en este caso no tendremos una definición formal de las operaciones que pueda ser consumida por otros sistemas debido a la ausencia de un estándar para ello, pero sí podremos conseguir un documento bastante razonable para que un desarrollador ser haga una idea clara de cómo usar nuestros servicios.

1. Empezando por el final…

Para que os hagáis una idea del resultado antes de ver cómo conseguirlo, ahí van un par de capturas de pantalla de la página de ayuda generada para un controlador WebAPI como el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class CustomerController: ApiController
{
    /// <summary>
    /// Gets a Customer
    /// </summary>
    /// <param name="id">Customer's Id</param>
    /// <returns>The Customer</returns>
    public Customer Get(int id)
    {
        // Code
    }
    /// <summary>
    /// Creates a new Customer
    /// </summary>
    /// <param name="customer">The customer</param>
    /// <returns>HTTP response with the result of this operation</returns>
    public HttpResponseMessage Post(Customer customer)
    {
        // Code
    }
    /// <summary>
    /// Updates a Customer
    /// </summary>
    /// <param name="customer">The customer</param>
    /// <returns>HTTP response with the result of this operation</returns>
    public HttpResponseMessage Put(int id, Customer customer)
    {
        // Code
    }
    /// <summary>
    /// Deletes a customer
    /// </summary>
    /// <param name="id">Customer's id</param>
    /// <returns>HTTP response with the result of this operation</returns>
    public HttpResponseMessage Delete(int id)
    {
        // Code
    }
}

Las páginas de ayuda generada tienen esta pinta:

Página de ayuda de WebAPI

Página de ayuda de WebAPI
Veamos ahora cómo conseguirlo.

2. Instalación del paquete

El componente que incluye la magia necesaria para generar la documentación se distribuye a través de Nuget, en el paquete Microsoft.AspNet.WebApi.Help. Su instalación, como siempre, es inmediata:

Install-Package Microsoft.AspNet.WebApi.HelpPage –Pre

La única particularidad que podéis ver en la línea anterior es la inclusión del parámetro “–pre”. Esto es necesario en la actualidad porque se trata de un componente en versión preliminar, pero una vez se publique la versión final ya no será necesario. Por tanto, si lo hacéis desde el IDE de Nuget, tenéis que recordar seleccionar la opción de permitir prereleases para que os aparezca el paquete y podáis descargarlo.

imageEn cualquier caso, tras descargar e instalar este paquete, el principal cambio que notaremos en el proyecto es la inclusión de un Área (MVC) llamada HelpPage, tal y como se muestra en la captura de pantalla adjunta.

El código incluido en este área es el responsable de registrar la ruta de acceso a las páginas de ayuda (por defecto en /help), y de procesar las peticiones de consulta. Internamente se usa ApiExplorer, una característica incluida en la última versión de System.Net.Http, que implementa todos los mecanismos de introspección necesarios para obtener las descripciones de las clases y métodos que componen nuestro API.

Dentro de la misma podemos encontrar también el código de la clase XmlDocumentationProvider, que será la encargada de extraer la documentación partiendo de los archivos XML generados durante la compilación a partir de los comentarios incluidos en el código.

3. Activación de comentarios XML

Por tanto, lo siguiente que debemos hacer es activar la generación del archivo XML de documentación en las propiedades del proyecto, indicando su nombre y ubicación:

Activar la documentación XML

Hecho esto, como podremos comprobar la primera vez que compilemos, los comentarios sobre las clases y métodos del proyecto sean incluidos en el archivo XML. Sin embargo, también veremos que tiene un pequeño efecto colateral bastante molesto: Visual Studio mostrará un warning por cada miembro o tipo público que no describamos.

Warning: falta comentario XML

Para solucionarlo, de nuevo sobre la pestaña “Build” de las propiedades del proyecto, podemos desactivar el aviso de warning 1591, que es el que nos está mostrando:

image

4. Registrar y configurar el proveedor de documentación basado en comentarios XML

El siguiente paso es registrar el proveedor XmlDocumentationProvider e informarlo de la ruta donde se encuentra el archivo de documentación generado. Esto lo hacemos descomentando una línea en el archivo /Areas/HelpPage/App_Start/HelpPageConfig.cs y estableciendo la ruta configurada anteriormente:

1
2
3
4
5
6
7
8
9
10
11
12
public static class HelpPageConfig
{
    public static void Register(HttpConfiguration config)
    {
        //// Uncomment the following to use the documentation from XML documentation file.
        config.SetDocumentationProvider(
            new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/bin/WebApiDemo.xml"))
        );
 
        [...] // Code ommited for brevity
    }
}

¡Y esto es todo lo que hay que hacer! 🙂 A partir de este momento, ya podremos acceder a la URL /help (o la indicada en la ruta del área) y consultar las ayudas generadas. Por defecto el sistema incluirá documentación para todos los controladores WebAPI del proyecto, salvo aquellos que sean decorados con el atributo ApiExplorerSettings de la siguiente forma:

1
2
3
4
5
6
// This controller will be ignored
[ApiExplorerSettings(IgnoreApi = true)]
public class MyController : ApiController
{
   [...]
}

5. Personalizar la apariencia y comportamiento

El hecho de que este paquete se distribuya en forma de área tiene como ventaja que su código fuente se introducirá en nuestro proyecto, permitiéndonos modificar con bastante libertad la forma en que estas páginas son generadas.

En el mismo archivo /Areas/HelpPage/App_Start/HelpPageConfig.cs que ya hemos modificado anteriormente es posible modificar diversos aspectos de la documentación, como los valores a usar para los distintos tipos de dato cuando se muestran ejemplos o en acciones concretas, entre otros. Vale la pena echarle un vistazo y jugar con las distintas opciones, que vienen comentadas sobre el código fuente del archivo.

También en la carpeta de vistas del área, ubicada en /Areas/HelpPage/Views encontraremos los archivos .cshtml utilizados para visualizar el índice general y la página de detalle de una acción (index.cshtml y api.cshtml respectivamente), así como las vistas parciales usadas para mostrar cada uno de los elementos mostrados al usuario (controladores o grupos de API, parámetros de las acciones, etc.). También encontraremos un Layout básico en la carpeta /Views/Shared, que por supuesto podemos ignorar completamente si cambiamos la referencia al mismo en el archivo _ViewStart.cshtml que encontramos sobre la misma carpeta de vistas del área. En este artículo podéis encontrar información sobre el contenido de cada archivo y ejemplos de personalizaciones.

Por último, es posible modificar la forma en que se genera el código de ejemplo, que encontraremos implementados en la carpeta /SampleGeneration del área, lo que puede resultar muy útil cuando existe algún motivo que impide que el sistema infiera correctamente los tipos de datos usados para serializarlos (por ejemplo, esto ocurre cuando nuestras acciones retornan un objeto HttpResponseMessage). Podéis ver algunos ejemplos de uso de generadores personalizados en este post.
 
Publicado en Variable not found.

Actualizar todos los paquetes Nuget de un proyecto

NugetAunque a muchos pueda parecer simple, hay gran cantidad de desarrolladores que para actualizar los paquetes Nuget de un proyecto acuden a la herramienta de gestión incluida en el IDE y van actualizando uno por uno los componentes instalados.

Pues bien, resulta que desde hace algún tiempo, Nuget soporta la actualización automática de todos los paquetes de una solución. Para ello, basta con acudir a la consola de administración de paquetes (Tools > Library Package Manager > Package Manager Console) e introducir el comando update-package:

Consola de administración de paquetes
Por ejemplo, sobre una aplicación MVC 4 recién creada, el resultado es el siguiente:

PM> update-package
Updating 'Modernizr' from version '2.5.3' to '2.6.2' in project 'MyMvcProject'.
Successfully removed 'Modernizr 2.5.3' from MyMvcProject.
Successfully installed 'Modernizr 2.6.2'.
Successfully added 'Modernizr 2.6.2' to MyMvcProject.
Successfully uninstalled 'Modernizr 2.5.3'.
No updates available for 'Microsoft.jQuery.Unobtrusive.Validation' in project 'MyMvcProject'.
No updates available for 'Microsoft.jQuery.Unobtrusive.Ajax' in project 'MyMvcProject'.
No updates available for 'Microsoft.AspNet.WebPages.OAuth' in project 'MyMvcProject'.
No updates available for 'Microsoft.AspNet.WebPages.WebData' in project 'MyMvcProject'.
No updates available for 'Microsoft.AspNet.WebPages.Data' in project 'MyMvcProject'.
No updates available for 'Microsoft.AspNet.WebApi' in project 'MyMvcProject'.
No updates available for 'Microsoft.AspNet.WebApi.WebHost' in project 'MyMvcProject'.
No updates available for 'Microsoft.AspNet.WebApi.Core' in project 'MyMvcProject'.
No updates available for 'Microsoft.AspNet.WebApi.Client' in project 'MyMvcProject'.
Updating 'Newtonsoft.Json' from version '4.5.6' to '4.5.11' in project 'MyMvcProject'.
Successfully removed 'Newtonsoft.Json 4.5.6' from MyMvcProject.
Successfully installed 'Newtonsoft.Json 4.5.11'.
Successfully added 'Newtonsoft.Json 4.5.11' to MyMvcProject.
Successfully uninstalled 'Newtonsoft.Json 4.5.6'.
No updates available for 'Microsoft.Net.Http' in project 'MyMvcProject'.
No updates available for 'Microsoft.AspNet.Web.Optimization' in project 'MyMvcProject'.
Updating 'WebGrease' from version '1.1.0' to '1.3.0' in project 'MyMvcProject'.
Successfully removed 'WebGrease 1.1.0' from MyMvcProject.
You are downloading WebGrease from webgrease@microsoft.com, the license agreement to which is available at http://www.microsoft.com/web/webpi/eula/msn_webgrease_eula.htm. Check the package for additional dependencies, which may come with their own license agreement(s). Your use of the package and dependencies constitutes your acceptance of their license agreements. If you do not accept the license agreement(s), then delete the relevant components from your device.
Successfully installed 'WebGrease 1.3.0'.
Successfully added 'WebGrease 1.3.0' to MyMvcProject.
Successfully uninstalled 'WebGrease 1.1.0'.
No updates available for 'Microsoft.AspNet.Mvc' in project 'MyMvcProject'.
No updates available for 'Microsoft.AspNet.WebPages' in project 'MyMvcProject'.
Updating 'Microsoft.AspNet.Razor' from version '2.0.20710.0' to '2.0.20715.0' in project 'MyMvcProject'.
Successfully removed 'Microsoft.AspNet.Razor 2.0.20710.0' from MyMvcProject.
You are downloading Microsoft.AspNet.Razor from Microsoft, the license agreement to which is available at http://www.microsoft.com/web/webpi/eula/WebPages_2_eula_ENU.htm. Check the package for additional dependencies, which may come with their own license agreement(s). Your use of the package and dependencies constitutes your acceptance of their license agreements. If you do not accept the license agreement(s), then delete the relevant components from your device.
Successfully installed 'Microsoft.AspNet.Razor 2.0.20715.0'.
Successfully added 'Microsoft.AspNet.Razor 2.0.20715.0' to MyMvcProject.
Successfully uninstalled 'Microsoft.AspNet.Razor 2.0.20710.0'.
No updates available for 'Microsoft.Web.Infrastructure' in project 'MyMvcProject'.
Updating 'knockoutjs' from version '2.1.0' to '2.2.0' in project 'MyMvcProject'.
Successfully removed 'knockoutjs 2.1.0' from MyMvcProject.
Successfully installed 'knockoutjs 2.2.0'.
Successfully added 'knockoutjs 2.2.0' to MyMvcProject.
Successfully uninstalled 'knockoutjs 2.1.0'.
Updating 'jQuery.Validation' from version '1.9.0.1' to '1.10.0' in project 'MyMvcProject'.
Successfully removed 'jQuery.Validation 1.9.0.1' from MyMvcProject.
Successfully installed 'jQuery.Validation 1.10.0'.
Successfully added 'jQuery.Validation 1.10.0' to MyMvcProject.
Successfully uninstalled 'jQuery.Validation 1.9.0.1'.
Updating 'jQuery.UI.Combined' from version '1.8.20.1' to '1.9.0' in project 'MyMvcProject'.
Successfully removed 'jQuery.UI.Combined 1.8.20.1' from MyMvcProject.
Successfully installed 'jQuery.UI.Combined 1.9.0'.
Successfully added 'jQuery.UI.Combined 1.9.0' to MyMvcProject.
Successfully uninstalled 'jQuery.UI.Combined 1.8.20.1'.
Updating 'jQuery' from version '1.7.1.1' to '1.8.2' in project 'MyMvcProject'.
Successfully removed 'jQuery 1.7.1.1' from MyMvcProject.
Successfully installed 'jQuery 1.8.2'.
Successfully added 'jQuery 1.8.2' to MyMvcProject.
Successfully uninstalled 'jQuery 1.7.1.1'.
No updates available for 'EntityFramework' in project 'MyMvcProject'.
Updating 'DotNetOpenAuth.AspNet' from version '4.0.3.12153' to '4.1.3.12303' in project 'MyMvcProject'.
Successfully removed 'DotNetOpenAuth.AspNet 4.0.3.12153' from MyMvcProject.
Successfully removed 'DotNetOpenAuth.OAuth.Consumer 4.0.3.12153' from MyMvcProject.
Successfully removed 'DotNetOpenAuth.OAuth.Core 4.0.3.12153' from MyMvcProject.
Successfully removed 'DotNetOpenAuth.OpenId.RelyingParty 4.0.3.12153' from MyMvcProject.
Successfully removed 'DotNetOpenAuth.OpenId.Core 4.0.3.12153' from MyMvcProject.
Successfully removed 'DotNetOpenAuth.Core 4.0.3.12153' from MyMvcProject.
Successfully installed 'DotNetOpenAuth.Core 4.1.3.12303'.
Successfully added 'DotNetOpenAuth.Core 4.1.3.12303' to MyMvcProject.
Successfully installed 'DotNetOpenAuth.OpenId.Core 4.1.3.12303'.
Successfully added 'DotNetOpenAuth.OpenId.Core 4.1.3.12303' to MyMvcProject.
Successfully installed 'DotNetOpenAuth.OpenId.RelyingParty 4.1.3.12303'.
Successfully added 'DotNetOpenAuth.OpenId.RelyingParty 4.1.3.12303' to MyMvcProject.
Successfully installed 'DotNetOpenAuth.OAuth.Core 4.1.3.12303'.
Successfully added 'DotNetOpenAuth.OAuth.Core 4.1.3.12303' to MyMvcProject.
Successfully installed 'DotNetOpenAuth.OAuth.Consumer 4.1.3.12303'.
Successfully added 'DotNetOpenAuth.OAuth.Consumer 4.1.3.12303' to MyMvcProject.
Successfully installed 'DotNetOpenAuth.AspNet 4.1.3.12303'.
Successfully added 'DotNetOpenAuth.AspNet 4.1.3.12303' to MyMvcProject.
Successfully uninstalled 'DotNetOpenAuth.AspNet 4.0.3.12153'.
Successfully uninstalled 'DotNetOpenAuth.OAuth.Consumer 4.0.3.12153'.
Successfully uninstalled 'DotNetOpenAuth.OAuth.Core 4.0.3.12153'.
Successfully uninstalled 'DotNetOpenAuth.OpenId.RelyingParty 4.0.3.12153'.
Successfully uninstalled 'DotNetOpenAuth.OpenId.Core 4.0.3.12153'.
Successfully uninstalled 'DotNetOpenAuth.Core 4.0.3.12153'.
No updates available for 'DotNetOpenAuth.OAuth.Consumer' in project 'MyMvcProject'.
No updates available for 'DotNetOpenAuth.OAuth.Core' in project 'MyMvcProject'.
No updates available for 'DotNetOpenAuth.OpenId.RelyingParty' in project 'MyMvcProject'.
No updates available for 'DotNetOpenAuth.OpenId.Core' in project 'MyMvcProject'.
No updates available for 'DotNetOpenAuth.Core' in project 'MyMvcProject'.
PM> 

De esta forma, acabamos de ahorrarnos un buen rato buscando e instalando actualizaciones manualmente sobre el proyecto 🙂

La instrucción anterior realiza la actualización sobre una solución completa, pero podemos hilar un poco más fino. El siguiente comando restringe la instalación de actualizaciones al proyecto cuyo nombre especificamos como parámetro:

PM> update-package -ProjectName ProjectToUpdate

También podemos actuar de forma algo más prudente. Por defecto, Nuget instalará las versiones más recientes de todos los paquetes usados en el proyecto o solución, pero a veces, esto podría introducir errores en la aplicación, sobre todo si el salto de versiones es demasiado grande.

Por ello, podemos indicar que las actualizaciones se realicen en “modo seguro” añadiendo el switch -safe al comando, como se observa en el siguiente ejemplo:

PM> update-package -ProjectName AnotherProject –Safe

De esta forma conseguiremos que las actualizaciones no se realicen a la última versión disponible, sino a la última build dentro de la misma versión usada del componente. Es decir, una biblioteca que use un código de versionado del tipo major.minor.build.revision, sólo será actualizado hasta la versión major.minor.maxbuild de la misma.

Por ejemplo, si en un proyecto usamos un componente versión 1.0.1 y en el feed de Nuget existen las versiones 1.0.4, 1.1, y 2.0 de este componente, tras llamar a update-package a secas, este componente será actualizado a la versión 2.0. En cambio, si usamos –safe , se actualizará a la 1.0.4.

En definitiva, una característica de lo más útil y que espero que os ahorre bastante tiempo a los que aún no la conocíais.

Publicado en: Variable not found.