Eliminando acoplamiento en un controlador ASP.net MVC

Cuando desarrollamos aplicaciones web podemos caer en el error de dar demasiada responsabilidad a nuestros controladores lo que nos puede traer problemas en el futuro al intentar refactorizar ese código.

En este artículo veremos cómo partiendo de una acción donde la carga de datos se realiza desde el propio controlador podemos reducir el acoplamiento a la manera de guardar los datos. Con ello conseguiremos mejorar la reusabilidad y legibilidad del mismo, así como permitir realizar pruebas unitarias o cambiar componentes de manera sencilla.

Código inicial

Nuestro primer código es un simple controlador con un método que lista un catálogo de libros. Este controlador contiene un método que lista un catálogo de libros. Usaremos directamente sentencias SQL contra una base de datos LocalDB.

public class HomeController : Controller
{
    public ActionResult Books()
    {
        List<Book> books = new List<Book>();
        SqlConnection connection = new SqlConnection(@"Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Books.mdf;Integrated Security=True");
        SqlCommand cmd = new SqlCommand();
        SqlDataReader reader;

        cmd.CommandText = "SELECT Title,Author FROM [Table]";
        cmd.CommandType = CommandType.Text;
        cmd.Connection = connection;

        connection.Open();

        reader = cmd.ExecuteReader();
        if (reader.HasRows)
        {
            while (reader.Read())
            {
                books.Add(new Book
                {
                    Title = reader.GetString(0),
                    Author = reader.GetString(1)
                });
            }
        }

        connection.Close();
        return View(books);
    }
}

El resultado es una lista de objetos de tipo Book, que es un POCO (Plain Old C# Object) que contiene dos campos, Title y Author. La principal desventaja, y es la que intentaremos resolver a lo largo de este artículo, es que presenta un fuerte acoplamiento con el gestor de base de datos, y si cambiamos a MySQL o MongoDB, por poner un ejemplo, nos veríamos obligados a reescribir la esta implementación.

Primera aproximación, patrón Repository

El objetivo de un patrón Repository es crear una capa de abstracción entre la lógica de negocio (representada en este caso por el controlador) y la lógica de base de datos (representada por el acceso a SQL). Dicha capa de abstracción nos permite probar nuestro controlador de manera independiente a los datos y a la manera de almacenar los mismos.

La implementación de un patrón repository la podemos realizar usando una interfaz y su correspondiente implementación:

public interface IBookRepository
{
    List<Book> GetAllBooks();
}

public class BookRepository : IBookRepository
{
    private SqlConnection _connection;
    private string _connectionString = @"Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Books.mdf;Integrated Security=True";
    public BookRepository()
    {
        _connection = new SqlConnection(_connectionString);
    }

    public List<Book> GetAllBooks()
    {
        List<Book> books = new List<Book>();
        SqlCommand cmd = new SqlCommand();
        SqlDataReader reader;

        cmd.CommandText = "SELECT Title,Author FROM [Table]";
        cmd.CommandType = CommandType.Text;
        cmd.Connection = _connection;

        _connection.Open();

        reader = cmd.ExecuteReader();
        if (reader.HasRows)
        {
            while (reader.Read())
            {
                books.Add(new Book
                {
                    Title = reader.GetString(0),
                    Author = reader.GetString(1)
                });
            }
        }

        _connection.Close();
        return books;
    }
}

El código de la implementación es el mismo, ya que seguimos usando SQL para el acceso a datos, sin embargo hemos creado una abstracción que nos permite realizar pruebas unitarias y dejar los detalles de la implementación del acceso a datos al Repositorio.

El código del controlador se reduce al código siguiente:

public class HomeController : Controller
{
    private IBookRepository _bookRepository;

    public HomeController()
    {
        _bookRepository = new BookRepository();
    }

    public ActionResult Books()
    {
        return View(_bookRepository.GetAllBooks());
    }
}

Pese a que el repositorio se inicia desde el controlador, podríamos usar una solución de inyección de dependencias como Ninject o crear nuestra propia solución para que la inicialización de las dependencias se realice fuera del mismo.

Reduciendo acoplamiento en nuestro Repositorio

Una vez tenemos separados el controlador y el repositorio, tenemos varias alternativas para mejorar la legibilidad y la facilidad de uso del código

LINQ to SQL

Usar LINQ to SQL nos permite realizar un mapeado directo entre nuestra tabla y una clase, así como una capa de abstracción adicional sobre nuestro repositorio.

public class LinqToSqlBookRepository : IBookRepository
{
    private DataContext _db;
    private string _connectionString = @"Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Books.mdf;Integrated Security=True";
    public LinqToSqlBookRepository()
    {
        _db = new DataContext(_connectionString);
    }

    public List<Book> GetAllBooks()
    {
        Table<Book> book = _db.GetTable<Book>();
        return book.ToList<Book>();
    }
}

Para que el mapping funcione correctamente, hemos de decorar nuestro modelo con los nombres de las columnas equivalentes:

[Table(Name = "Table")]
public class Book
{
    [Column(Name = "Title")]
    public string Title { get; set; }
        
    [Column(Name = "Author")]
    public string Author { get; set; }
}

Esta aproximación nos da una capa de abstracción mayor, comprobación de tipos en tiempo de compilación, capacidad de debug, y facilidad de acceso, a costa de perder algo de flexibilidad y rendimiento.

Conclusiones y pasos adicionales

LINQ to SQL no es la única manera de agregar abstracciones a nuestros datos, también podemos usar sistemas más complejos como Entity Framework, NHibernate, o Massive, siendo este el último que he descubierto y al que espero dedicarle pronto un artículo. Cada capa de abstracción, como decíamos anteriormente, nos permite desacoplar el código que estamos usando, aumentar su facilidad para ser probado, y su legibilidad, a la vez que cumplimos con principios como el de responsabilidad simple.

El proyecto termina con 3 capas diferenciadas:

  • Capa de presentación (Controlador)
  • Capa de datos (Repositorio)
  • Capa de persistencia (SQL)

Podemos agregar capas de lógica de negocio (si queremos realizar validaciones sobre los datos antes de que lleguen a la base de datos) o de servicio (si tenemos varias interfaces para nuestra aplicación). Cada capa aumenta la complejidad de nuestra aplicación pero también aumenta nuestra capacidad para limitar las responsabilidades de cada clase.

Puedes ver el código completo en github

Lecturas adicionales

Extra: Código de creación de la base de datos y datos de ejemplo

El código de creación de la base de datos y de los datos de ejemplo también es muy simple (SQL)

CREATE TABLE [dbo].[Table]
(
    [Id] INT NOT NULL PRIMARY KEY IDENTITY, 
    [Title] NVARCHAR(50) NULL, 
    [Author] NVARCHAR(50) NULL
)
INSERT INTO [dbo].[Table] (Title,Author) VALUES ('Hamlet', 'William Shakespeare')
INSERT INTO [dbo].[Table] (Title,Author) VALUES ('El Ingenioso Hidalgo Don Quijote de la Mancha', 'Miguel de Cervantes y Saavedra')
INSERT INTO [dbo].[Table] (Title,Author) VALUES ('La divina comedia', 'Dante Alighieri')

Creando un motor de inyección de dependencias con C#

Read this article in English: Creating a Dependency Injection in C#

De acuerdo con la Wikipedia, la inyección de dependencias es un patrón de diseño de software que nos permite seguir el principio de inversión de dependencias mediante inversión de control, es decir, definir las dependencias de una clase desde fuera de la misma. En el caso de C# tenemos a nuestra disposición varios proyectos que generan todas las dependencias necesarias para nuestros objetos. Uno de estos es Ninject, un motor open-source con una sintaxis simple y plugins para ASP.net MVC y SignalR.

En este artículo veremos cómo funciona un motor de inyección de dependencias creando uno propio, basado en la sintaxis y la filosofía de Ninject.

Introducción

La inyección de dependencias nos ayuda a separar las responsabilidades entre las diferentes capas de nuestro código, así como mejorar la encapsulación y la facilidad de crear pruebas en nuestro código. Comencemos por un ejemplo simple, una lista de notas que nos permiten agregar una nota y guardarla llamando a _dataStorage, un objeto inicializado en el constructor:

public class NoteList
{
    private DataStorage _dataStorage;
    public NoteList()
    {
        _dataStorage = new DataStorage();
    }
    public void Add(string note)
    {
        if (string.IsNullOrEmpty(note))
        {
            throw new ArgumentException("Note cannot be empty");
        }

        _dataStorage.Save(note);
    }
}

DataStorage es una clase que escribe el contenido de una nota en disco, y que tiene el siguiente código para el método Save:

internal void Save(string note)
{
    using (StreamWriter writer = new StreamWriter("db.txt"))
    {
        writer.WriteLine(note);   
    }
}

El código de test se muestra a continuación:

//Arrange
var noteList = new NoteList();
var noteText = "myCustomNote";

//Act
noteList.Add(noteText);

//Assert
using (StreamReader reader = new StreamReader("db.txt"))
{
    var all = reader.ReadToEnd();
    Assert.IsTrue(all.Contains(noteText));
}

Como se puede ver, generamos un acoplamiento con DataStorage, esto significa que no podemos probar NoteList a menos que también probemos el comportamiento de DataStorage.

Eliminando el acoplamiento

El primer cambio que podemos hacer es abstraer DataStorage en una interfaz llamada IDataStorage. Seguidamente pasamos dicha interfaz como argumento en el constructor, en vez de inicializarla dentro de nuestra clase:

...
private IDataStorage _dataStorage;
public NoteList(IDataStorage dataStorage)
{
    _dataStorage = dataStorage;
}
...

El código de test cambia también, ya que pasamos a definir las dependencias fuera de la clase:

...
var dataStorage = new DataStorage();
var noteList = new NoteList(dataStorage);
var noteText = "myCustomNote";
...

Construyendo nuestro inyector

Una vez que tenemos una clase que recibe los parámetros como argumentos. Estos parámetros deben ser definidos e inicializados manualmente antes de llamar a nuestro constructor, con lo cual, el primer paso es generar dichos parámetros solicitando un tipo específico a nuestro Iniector. La primera versión es una clase estática con dos métodos y un diccionario interno para almacenar los mapeos, que tiene este aspecto:

private static Dictionary<Type, object> mappings
    = new Dictionary<Type, object>(); 

public static T Get<T>()
{
    return (T)mappings[typeof(T)];
}

public static void Map<T>(object o)
{
    mappings.Add(typeof(T), o);
}

Ahora podemos solicitar un objeto para la interfaz de nuestro test:

Injector.Map<IDataStorage>(new DataStorage());
var dataStorage = Injector.Get<IDataStorage>();

Este código presenta un problema, y es que siempre devolveremos el mismo objeto, y seguimos especificando el inyector en el constructor. Sería mucho más sencillo si el inyector devolviera una nueva copia de nuestro objeto, y si adicionalmente pudiéramos pedir nuestro objeto directamente desde el inyector:

Injector.Map<IDataStorage>(new DataStorage());
var noteList = Injector.Get<NoteList>();

Para poder llegar a estos resultados necesitamos una serie de mejoras importantes en nuestro inyector. El primer paso consiste en dividir el método Get en un método no genérico, de tal manera que podamos realizar llamadas recursivas como veremos más adelante:

public static T Get<T>()
{
    var type = typeof(T);
    return (T)Get(type);
}

El segundo paso consiste en cambiar la manera de almacenar los objetos, ya que en vez de una instancia, almacenaremos un tipo. De esta manera cambiamos el método Map para asegurarnos que no estamos almacenando un objeto específico, y que el tipo a almacenar hereda o implementa el tipo que se usará de clave:

public static void Map<T, V>() where V : T
{
    mappings.Add(typeof(T), typeof(V));
}

Finalmente, cambiamos nuestro método Get para invocar al constructor del tipo requerido, tras algunas comprobaciones adicionales:

private static object Get(Type type)
{
    var target = ResolveType(type);
    var constructor = target.GetConstructors()[0];
    var parameters = constructor.GetParameters();

    List<object> resolvedParameters = new List<object>();

    foreach (var item in parameters)
    {
        resolvedParameters.Add(Get(item.ParameterType));
    }

    return constructor.Invoke(resolvedParameters.ToArray());
}

Veamos este código paso a paso: En primer lugar se resuelve el tipo, es decir, se comprueba si hay algún mapping disponible para el tipo especificado, en caso contrario se devuelve el mismo tipo:

private static Type ResolveType(Type type)
{
    if (mappings.Keys.Contains(type))
    {
        return mappings[type];
    }

    return type;
}

Una vez nos hemos asegurado de estar usando el tipo de dato correcto, el siguiente paso es recuperar el constructor, y su lista de parámetros (si existe).

...
    var target = ResolveType(type);
    var constructor = target.GetConstructors()[0];
    var parameters = constructor.GetParameters();
...

Si el constructor tiene parámetros, para cada uno de ellos se intentará resolver (es decir, se repetirá el proceso de manera recursiva), y si la resolución tiene éxito, se agregará a una lista de parámetros resueltos. En este caso el orden es muy importante ya que debe coincidir con el orden en el que se especifican los parámetros en el constructor**.

    foreach (var item in parameters)
    {
        resolvedParameters.Add(Get(item.ParameterType));
    }

Finalmente se invoca el constructor con la lista de parámetros y se devuelve el objeto que se acaba de crear.

    return constructor.Invoke(resolvedParameters.ToArray());

La sintaxis final para obtener un nuevo objeto de nuestro inyector de dependencias es la siguiente:

Injector.Map<IDataStorage, DataStorage>();
var noteList = Injector.Get<NoteList>();

El resultado es una manera muy conveniente de generar un objeto sin preocuparnos de sus dependencias, que pueden estar definidas a un nivel mucho mayor.

Resumen

La inyección de dependencias no es un término oscuro ni mucho menos, nos permite crear arquitecturas desacopladas, y motores como el que acabamos de crear nos permiten crear la infraestructura necesaria a un nivel más alto, con lo cual el resto de las clases pueden tener solamente la lógica relacionada con su propio comportamiento (principio de responsabilidad simple) con un conjunto mínimo de dependencias. Por otro lado no es una pieza de software muy complicada, aunque en este caso es un ejemplo y el conjunto de casos cubiertos es mínimo.

Finalmente, las características de C# nos permiten hacer algo de metaprogramación al obtener tipos y parámetros de una función en tiempo de ejecución, así como crear objetos de manera dinámica, lo cual no está mal para un lenguaje fuertemente tipado. Sería interesante comprobar cómo podríamos crear una versión de este inyector en un entorno más dinámico y débilmente tipado.

Descarga el código!

Kata UpperCounter con Software Craftsmanship Madrid

El pasado martes 5 de agosto tuve la oportunidad de acudir a mi primer meetup de Software Craftsmanship Madrid, en el que se celebaba un coding dojo facilitado por Carlos Ble @carlosble. El objetivo de la sesión era hacer uso de un patrón diseñado por Robert “Uncle Bob” Martin llamado “Transformation Priority Premise” que nos lleva a una programación más genérica y funcional.

Tras sentarnos por parejas y escoger el entorno y el lenguaje de programación (En mi caso, C# con Visual Studio 2013 y XUnit como motor de pruebas) se desveló el objetivo de la kata:

Dada una cadena, devolver, en forma de array, las posiciones de dicha cadena cuyos caracteres sean la letra mayúscula

Ejemplos:
– A: {0}
– bA: {1}
– aBcdE: {1, 4}

Primera iteración, sin restricciones

Para esta primera iteración no teníamos ninguna limitación más allá de intentar resolver la kata. El resultado es el que se muestra en el vídeo:

El código completo, tanto del test como de la implementación se puede ver a continuación:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sample
{
public class UppercaseSearcher
{
internal int[] Search(string source)
{
var result = new List<int>();
if (source.Length > 0)
{
for (int i = 0; i < source.Length; i++)
{
var current = source[i];
if (char.IsUpper(source, i))
{
result.Add(i);
}
}
}
return result.ToArray();
}
private bool IsUpperCase(char current)
{
return current.ToString().ToUpper()
== current.ToString();
}
}
}

view raw
Source.cs
hosted with ❤ by GitHub

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Xunit.Extensions;
namespace Sample
{
public class Test
{
[Fact]
public void ShouldReturnEmptyArrayIfEmptyString()
{
//Arrange
var source = "";
var searcher = new UppercaseSearcher();
//Act
var result = searcher.Search(source);
//Assert
Assert.Empty(result);
}
[Fact]
public void ShouldReturnValidUppercaseLocation()
{
//Arrange
var source = "A";
var searcher = new UppercaseSearcher();
//Act
var result = searcher.Search(source);
//Assert
Assert.Equal(1, result.Length);
Assert.Equal(0, result[0]);
}
[Fact]
public void ShouldReturnValidUppercaseInSecondPlace()
{
//Arrange
var source = "bA";
var searcher = new UppercaseSearcher();
var expected = new int[] { 1 };
//Act
var result = searcher.Search(source);
//Assert
Assert.Equal(expected, result);
}
[Theory]
[InlineData("A", new int[] { 0 })]
[InlineData("bA", new int[] { 1 })]
[InlineData("bbAab", new int[] { 2 })]
[InlineData("babC", new int[] { 3 })]
//Multiple uppercases
[InlineData("bCbC", new int[] {1,3})]
//No uppercase
[InlineData("qwerty", new int[] { })]
public void ShouldBeValidInDifferentSituations(string source, int[] expected)
{
//Arrange
var searcher = new UppercaseSearcher();
//Act
var result = searcher.Search(source);
//Assert
Assert.Equal(expected, result);
}
}
}

view raw
Test.cs
hosted with ❤ by GitHub

El enfoque es iterativo, utilizando un bucle para recorrer los caracteres de la cadena y la comprobación es bastante artesanal (a mejorar en la segunda iteración) y además, como teníamos tiempo, pudimos probar las Theories de XUnit, que nos permiten utilizar, en el mismo test, diferentes conjuntos de entrada y esperar diferentes resultados.

Segunda iteración, con restricciones

En esta segunda iteración teníamos una limitación importante: No podíamos asignar variables, ni modificar valores existentes. Esto nos deja sin la posibilidad de usar bucles (ya que vamos actualizando la posición del iterador) y forzando nuestro código a que sea más funcional. El resultado es el que se muestra:

El código completo es el siguiente, con el que intentamos seguir a rajatabla la indicación de no asignar o modificar los valores de las variables. En este caso el tiempo no permitió pasar de unos pocos test, pero se aprecia una diferencia notable por una parte en el test y por otra en el código de implementación:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sample.WithLimits
{
class UppercaseSearcher
{
internal static int[] Search(string source)
{
return Search(source, 0);
}
internal static int[] Search(string source, int index)
{
if (IsOutOfBounds(source, index))
{
return new int[0];
}
if (char.IsUpper(source, index))
{
return new int[] { index }
.Concat(Search(source, index + 1))
.ToArray();
}
else
{
return Search(source, index + 1)
.ToArray();
}
}
private static bool IsOutOfBounds(string source, int index)
{
return source.Length == 0 || index >= source.Length;
}
}
}

view raw
Searcher.cs
hosted with ❤ by GitHub

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace Sample.WithLimits
{
public class TestClass
{
[Fact]
public void ShouldReturnEmptyArray()
{
//Arrange, act, assert
Assert.Equal(new int[0], UppercaseSearcher.Search(""));
}
[Fact]
public void ShouldReturn0IfOneLetterIsUppercase()
{
//Arrange, act, assert
Assert.Equal(new int[] {0}, UppercaseSearcher.Search("A"));
}
[Fact]
public void ShouldReturn1IfSecondLetterIsUppercase()
{
//Arrange, act, assert
Assert.Equal(new int[] { 1 }, UppercaseSearcher.Search("bA"));
}
}
}

view raw
Test.cs
hosted with ❤ by GitHub

Como nota adicional, gracias a @DanielRoz0 que me ha estado ayudando con la edición del vídeo, se pudo simplificar la comparación de una letra con su correspondiente mayúscula mediante el uso de la función char.IsUpper(source, index).

Información y enlaces:

Creating a Dependency Injection Engine with C#

According to the Wikipedia, dependency injection is a software design pattern that implements inversion of control and allows a program design to follow the dependency inversion principle. This patttern is implemented in C# with engines that generate all the required dependencies for our objects like Ninject, an open-source engine with a simple syntax and plugins for ASP.net MVC and SignalR.

In this article, we will see how does a dependency injection engine works by creating our own, based on Ninject’s syntax and philosophy.

Introduction

Dependency injection helps us to separate the concerns between the different layers of our code, and improve the encapsulation and testability of our code. Let’s start with a simple code, a list of notes that allows us to add a note, and saves it by calling _dataStorage, an object initialized in the constructor:

public class NoteList
{
    private DataStorage _dataStorage;
    public NoteList()
    {
        _dataStorage = new DataStorage();
    }
    public void Add(string note)
    {
        if (string.IsNullOrEmpty(note))
        {
            throw new ArgumentException("Note cannot be empty");
        }

        _dataStorage.Save(note);
    }
}

DataStorage is a class that writes the content of the note to disk, and has the following code for the Save method:

internal void Save(string note)
{
    using (StreamWriter writer = new StreamWriter("db.txt"))
    {
        writer.WriteLine(note);   
    }
}

The test code is the following:

//Arrange
var noteList = new NoteList();
var noteText = "myCustomNote";

//Act
noteList.Add(noteText);

//Assert
using (StreamReader reader = new StreamReader("db.txt"))
{
    var all = reader.ReadToEnd();
    Assert.IsTrue(all.Contains(noteText));
}

As we can see, we are generating a dependency on DataStorage (they are coupled), so this means that we cannot test NoteList unless we also test the behavior of DataStorage.

Removing coupling

The first thing we can do is to abstract DataStorage in an interface called IDataStorage. The following step is passing it as an argument, instead of initializing on the constructor:

...
private IDataStorage _dataStorage;
public NoteList(IDataStorage dataStorage)
{
    _dataStorage = dataStorage;
}
...

The test code also changes, so we define the dependencies from outside the class:

...
var dataStorage = new DataStorage();
var noteList = new NoteList(dataStorage);
var noteText = "myCustomNote";
...

Building our injector

Now we have a class that receives the parameters as arguments. These parameters must be defined and initialized manually before calling our constructor, so the first step is generating the parameters by asking our Injector for a specific type. The first version of our injector is a static class with two methods and an internal dictionary to hold the mappings, and it looks like this:

private static Dictionary<Type, object> mappings
    = new Dictionary<Type, object>(); 

public static T Get<T>()
{
    return (T)mappings[typeof(T)];
}

public static void Map<T>(object o)
{
    mappings.Add(typeof(T), o);
}

Now we can request an object for the interface in our test:

Injector.Map<IDataStorage>(new DataStorage());
var dataStorage = Injector.Get<IDataStorage>();

This code has an issue, that is that we always return the same object, and we are still specifying the injector in the constructor. It would be easier if the injector returns a new copy of the object and if we could also request our object directly from the injector:

Injector.Map<IDataStorage>(new DataStorage());
var noteList = Injector.Get<NoteList>();

For having these results we need to do some heavy improvements to our Injector. The first thing we are going to do is to divide the Get method into a non-generic one, so we can use recursion someway later:

public static T Get<T>()
{
    var type = typeof(T);
    return (T)Get(type);
}

The second thing we are going to do, instead of storing the object in our dictionary, is store the type, so we change also the Map method, this way we make sure of not storing a specific object:

public static void Map<T, V>() where V : T
{
    mappings.Add(typeof(T), typeof(V));
}

And finally, we are going to change our Get method to invoke the constructor of the requested type, after some extra checks:

private static object Get(Type type)
{
    var target = ResolveType(type);
    var constructor = target.GetConstructors()[0];
    var parameters = constructor.GetParameters();

    List<object> resolvedParameters = new List<object>();

    foreach (var item in parameters)
    {
        resolvedParameters.Add(Get(item.ParameterType));
    }

    return constructor.Invoke(resolvedParameters.ToArray());
}

Let’s review this code step by step: The first thing it does is resolving the type, this means checking if we have any mapping available for the specific type, if not, it returns the same type:

private static Type ResolveType(Type type)
{
    if (mappings.Keys.Contains(type))
    {
        return mappings[type];
    }

    return type;
}

After being sure about using the correct type, the next step is retrieving the constructor for the specified type, and the list of its parameters (if any).

...
    var target = ResolveType(type);
    var constructor = target.GetConstructors()[0];
    var parameters = constructor.GetParameters();
...

If the constructor has parameters, then each parameter type it will try to resolve it individually, and if the resolution was successful, it is added to a list of resolved parameters (the order here is very important, as it must match the order of the constructor signature).

    foreach (var item in parameters)
    {
        resolvedParameters.Add(Get(item.ParameterType));
    }

Finally, the constructor is invoked with the parameter list and returns the created object.

    return constructor.Invoke(resolvedParameters.ToArray());

The final syntax for getting a new object from our dependency injector is the following:

Injector.Map<IDataStorage, DataStorage>();
var noteList = Injector.Get<NoteList>();

The result is a very convenient way of generating an object without caring about its dependencies, that may be defined at a way higher level.

Recap

Dependency injection is not an obscure term, it allows us to create uncoupled architectures, and engines like the one we just created allow us to create the required infrastructure at a higer level, so the rest of the classes have only the logic related to its own behavior, with the minimum set of dependencies. It’s also not a very complicated piece of software, although ninject has a way more features and is far more robust that what we have seen here, but this is just step one.

Also, C#’s language features allow us to do some metaprogramming by getting types, parameters of a constructor and invoking it at runtime, which is not bad for a strongly typed language. It would be interesting to see how we could create a version of this injector in a more dynamic, loosely typed environment.

Get the code and play with it!

Cacheando con Varnish un proyecto ASP.net MVC5

Una caché, por definición, es un almacenamiento a corto plazo de información y con una altísima velocidad de acceso, permitiéndonos mejorar el rendimiento de nuestros sistemas. En el caso de la web podemos diferenciar dos tipos:

  • Caché de cliente, que se hace en el navegador y que nos permite no tener que traer de internet imágenes o ficheros de estilo una vez hemos obtenido una copia.
  • Caché de servidor, que guarda una copia de manera temporal para evitar sobrecarga de nuestro servidor de aplicaciones.

Esto último tiene una justificación, y es que el acceso a las aplicaciones (PHP, ASP.net, Ruby) es un proceso relativamente lento que suele estar acompañado de un acceso a una base de datos, una aplicación de la lógica de negocio y la composición final de la página.

Existen diferentes sistemas y tipos de caché, como Memcached o Redis. En este artículo hablaremos de Varnish, un proyecto open-source que se instala sobre sistemas UNIX (aunque tiene soporte para Windows mediante Cygwin).

La principal peculiaridad que tiene este sistema, además de sus casi-infinitas opciones de configuración, es que permite dividir nuestra página en trozos y cachearlos de manera independiente, en función del intervalo de actualización de los mismos, un proceso conocido como Edge Side Includes (ESI) y que veremos a lo largo del artículo.

Instalación y configuración

La instalación de Varnish es un proceso tan simple como brew install varnish si usamos homebrew en mac. Una vez instalado, para ejecutarlo usamos el siguiente comando:

sudo /usr/local/opt/varnish/sbin/varnishd -n /usr/local/var/varnish -f /usr/local/etc/varnish/default.vcl -s malloc,1G -T 127.0.0.1:2000 -a 0.0.0.0:8082

pasando como parámetros las siguientes opciones:

  • Ruta del fichero de configuración
  • Puerto de registro de log
  • Máximo consumo de RAM
  • Puerto de escucha (en nuestro caso el 8082)

El fichero de configuración default.vcl, para nuestro ejemplo, contiene las siguientes directivas:

backend default {
    .host = "127.0.0.1";
    .port = "8087";
}

sub vcl_recv {
	if (req.http.cookie) {
		unset req.http.cookie;
	}
}

sub vcl_fetch {
	
	if (req.url == "/layout/*") {
       set beresp.ttl = 2m;      /* Sets a one minute TTL on        */
    } else {
       set beresp.do_esi = true; /* Do ESI processing               */
       set beresp.ttl = 30s;     /* Sets the TTL on the HTML above  */
    }
    unset beresp.http.set-cookie;
}

sub vcl_deliver {

    if (obj.hits > 0) {
            set resp.http.X-Cache = "HIT";
    } else {
            set resp.http.X-Cache = "MISS";
    }
}

Los comandos que hemos implementado son:

  • backend: Permite especificar qué servidores estarán funcionando al otro lado, se puede especificar una IP o un nombre DNS.

  • vcl_recv: En el caso de ASP.net, se genera una cookie de sesión al acceder al sitio, lo cual no siempre es lo deseable. En este ejemplo se borran todas las que provienen del servidor, de manera que se pueda cachear la página.

  • vcl_fetch: Se ejecuta cuando obtenemos un elemento desde el servidor, y en este caso especificamos que si estamos solicitando algún elemento de “layout” como el menú o la cabecera, ha de cachearlo durante 2 minutos, en caso contrario configuramos para que haga el procesamiento ESI (es decir, que intente unir los pedazos) y cachee el conjunto durante 30 segundos.

  • vcl_deliver: Nos permite editar la cabecera HTTP para saber si ha podido resolver el elemento en la caché o si ha tenido que acceder al servidor de aplicaciones.

Cacheando voy, cacheando vengo:

En este ejemplo hemos usado una plantilla de bootstrap que tiene el siguiente aspecto dentro de una aplicación prácticamente vacía en MVC5:

goal

Lo primero que podemos apreciar son tres zonas claramente diferenciadas, una cabecera, una barra lateral, y, finalmente, un área de contenido principal.

Estructura

Para mostrar la página, empleamos un controlador muy sencillo que genera una espera de 3 segundos para simular carga del servidor y almacena la fecha de generación en el ViewData:

public class HomeController : Controller
{
	public ActionResult Index ()
	{
		ViewData ["now"] = String.Format ("{0:HH:mm:ss}", DateTime.Now);
		System.Threading.Thread.Sleep (3000);
		return View ("Index");
	}
}

De manera adicional y para poder aplicar ESI, necesitaremos dividir nuestra vista en tres vistas diferentes que correspondan a acciones diferentes del controlador, que serán:

  • / <- que genera el contenido de la página
  • /layout/header <- que genera la cabecera
  • /layout/sidebar <- que genera la barra lateral

Las dos acciones del controlador Layout son idénticas, como muestra el código:

public class LayoutController : Controller
{
    public ActionResult Sidebar()
    {
		ViewData ["now"] = String.Format ("{0:HH:mm:ss}", DateTime.Now);
		System.Threading.Thread.Sleep (3000);
        return View ("Sidebar");
    }

	public ActionResult Header()
	{
		ViewData ["now"] = String.Format ("{0:HH:mm:ss}", DateTime.Now);
		System.Threading.Thread.Sleep (3000);
		return View ("Header");
	}
}

Nótese que por cada acción hemos agregado otros 3 segundos de retraso, teniendo un total de 9 segundos en el caso peor.

Para poder activar el ESI en las vistas, usamos etiquetas HTML que tienen el siguiente formato:

<esi:include src="/layout/sidebar" onerror="continue"/>

Además, a modo de prueba, podemos agregar algo de código javascript que se ejecute una vez cargada la página para apreciar la diferencia entre hora de generación y hora de renderización. Si todo ha ido bien, cuando carguemos por primera vez nuestra caché, se encontrará vacía, y sufriremos la espera de los 9 segundos.

En la imagen, G muestra la hora de generación en el servidor y R la hora de renderización en el cliente:

miss

Si volvemos a acceder, comprobaremos que el contenido de la página ya se ha cacheado, que las fechas de generación y de ejecución distan más de tres segundos, y que el inspector nos muestra el tiempo total de acceso a la página (700 milisegundos aprox):

hit

Conclusiones

Ha sido una prueba de concepto muy interesante, el hecho de descubrir que podemos tener nuestra web dividida en secciones con cachés diferentes nos da mucha movilidad al hacer portales con información dinámica. Varnish es una herramienta suficientemente compleja para ser tomada en serio y requiere que estudiemos a fondo sus características antes aplicarla a un sistema en producción.

Lecturas adicionales y enlaces

Probando módulos de NancyFx

En el artículo anterior de la serie de NancyFx hablábamos de diferentes tipos de respuesta así como el uso de plantillas en la plataforma. En este artículo veremos cómo crear pruebas unitarias para asegurarnos que nuestros módulos funcionan correctamente.

Creando nuestro primer test

Desde la documentación de Nancy se recomienda usar un proyecto diferente (es decir, un ensamblado diferente) para nuestros tests, ya que los módulos se descubren de manera automática por el “bootstrapper”. Una vez creado nuestro proyecto, necesitamos agregar las siguientes referencias, via nuget o de manera manual:

  • NUnit (o XUnit, o el framework que deseemos)
  • Nancy
  • Nancy.Testing

Una vez tenemos las referencias, podemos crear nuestro primer test (que tiene el original nombre de RoutesTest.cs). Dicho test estará dividido en tres partes:

  • Arrange: Toda la preparación necesaria para poder llevar a cabo el test
  • Act: La ejecución de nuestro test
  • Assert: La fase de comprobación de los resultados
[Test ()]
public void TestPut ()
{
        //Arrange
	var bootstrapper = new DefaultNancyBootstrapper();
	var browser = new Browser(bootstrapper);

        //Act
	var result = browser.Put("/routes", with => {
		with.HttpRequest();
	});

        //Assert
	Assert.AreEqual (HttpStatusCode.OK, result.StatusCode);
	Assert.AreEqual ("Response with Put\n", result.Body.AsString());
}

Qué hace el test?

  • Arrange: Para este test el primer paso es crear nuestro Bootstrapper que descubrirá los módulos existentes, seguido de un Browser con el que simularemos las llamadas a nuestros módulos.

  • Act: Una vez tenemos el browser, el siguiente paso es generar la peticion, en este caso Put, a una ruta especificada.

  • Assert: Con el resultado de la ejecución, comprobamos el estado de la respuesta (en este caso 200 OK) y que el texto corresponda con lo que necesitamos, que es “Response with Put\n”.

Una vez tenemos las referencias, recordemos qué contenía el módulo que queríamos probar:

public class Routes : NancyModule
{
	public Routes ()
	{
		Get["/routes"] = _ => "Response with GET\n";
		Post["/routes"] = _ => "Response with POST\n";
		Put["/routes"] = _ => "Response with Put\n";
                ...
	}
}

Podemos identificar claramente una línea donde el verbo PUT devuelve “Response with Put\n”, con lo cual nuestro test es correcto

Probando una ruta errónea

Al igual que podemos probar rutas correctas, los test son igual de válidos para comprobar que el acceso a una ruta no autorizada o no implementada se controla correctamente, como sucede a continuación:

[Test ()]
public void TestNotFound ()
{
	//Arrange
	var bootstrapper = new DefaultNancyBootstrapper();
	var browser = new Browser(bootstrapper);

	//Act
	var result = browser.Delete("/routes", with => {
		with.HttpRequest();
	});

	//Assert
	Assert.AreEqual (HttpStatusCode.MethodNotAllowed, result.StatusCode);
}

En este caso, la ruta no está implementada, con lo cual el resultado será un error de tipo “Method Not Allowed”.

Conclusiones

Con pocas líneas de código podemos comenzar a probar nuestros módulos de NancyFx, podemos probar la respuesta de los mismos, así como códigos de error. El sistema de test permite, adicionalmente, pasar parámetros (simulando el uso de un formulario) o navegar a través del DOM del HTML devuelto, si usamos un ViewEngine.

Balanceo de carga y escalabilidad con ASP.net, primer contacto

Una de los problemas a los que no he tenido la oportunidad de enfrentarme, de manera profesional, es manejar carga de servidores web, así que esta semana me he dispuesto a montar un sistema para balancear dos sitios ASP.net alojados en Azure. En este artículo veremos cómo ponerlo en marcha. Ha sido una aventura muy interesante, así que te invito a que sigas leyendo.

La arquitectura

Últimamente tenemos muchas capas de servicios que nos abstraen de la lógica necesaria para todo esto: los Azure Websites pueden escalar automáticamente, Azure proporciona su propio balanceador de carga a través del componente Traffic Manager, y Amazon tiene su Elastic Load Balancer.

Para este escenario, sin embargo, quería montarlo de manera un poco más artesanal, y esta es la arquitectura:

  • Dos Azure Websites diferentes, uno alojado en North Europe y otro en West US.
  • Una máquina virtual, con Linux (aquí meteremos el balanceador de carga) alojada en East Asia.

¿Por qué Linux? Linux tiene una gran importancia en la actualidad en el área de servidores. Llevaba tiempo sin trabajar con él y además parecía divertido combinar las diferentes plataformas.

Identificando las instancias

Un detalle que puede pasar desapercibido si vamos a nuget.org, es que en el pie de página identifican el servidor en el que estamos (You are on XXXX), con lo cual, si refrescamos la página, veremos otro servidor.

nuget

Para esta prueba sería muy útil saber qué servidor está sirviendo los contenidos, así que lo primero que haremos será crear un proyecto por defecto de ASP.net, y sustituir la acción Index de HomeController por:

public ActionResult Index()
{
    ViewBag.Title = &quot;Home Page&quot;;
    ViewBag.ServerName = System.Environment.MachineName;
    return View();
}

Por otro lado sustituimos el código de Index.cshtml (la vista) por:

<div class="jumbotron">
    <h1>Load balancing testing</h1>
    <p class="lead">You are on @ViewBag.ServerName</p>
</div>

El resultado (en local) es este:

Lb_local

Una vez que tenemos nuestro sitio funcionando, el siguiente paso es subirlo a dos servidores diferentes, que son en este caso:

Cada máquina tiene un identificador diferente, de esta manera, cuando hagamos el balanceo de carga, podremos saber en qué máquina estamos.

Agregando el balanceador

Para el balanceador he optado por un Ubuntu Server 12 hospedado en una máquina virtual también en Azure. Una de las cosas que no debemos olvidar es abrir el puerto 80 para poder recibir tráfico normal de Internet (para este ejemplo dejamos de lado temas relacionados con HTTPS, certificados SSL y similares). Con Linux tenemos muchas opciones. Estuve probando las siguientes:

Fair

Es una opción muy sencilla para empezar, pero tiene un problema, ya que necesita un componente en cada máquina que queremos balancear, lo cual nos limita el radio de acción. Puede que en otra ocasión…

Balance

A diferencia de Fair, no necesita un componente en cada máquina, lo que era un plus. Sin embargo, el hecho de estar basado en comandos y no en configuración no me acababan de convencer. Finalmente, no pude hacerlo funcionar por problemas de puertos, permisos y otros.

HAProxy

HAproxy es, según he podido leer, el balanceador más completo y configurable. Funciona mediante un fichero de configuración y necesita direcciones IP fijas, ya que, según los ejemplos, está pensado para que los servidores a balancear estén en la misma red. Después de varios intentos, no conseguí que el balanceador funcionara, así que desistí.

Apache

Por último, descubrí que Apache tiene un módulo específico para proxy y balanceo, que se parecía bastante a lo que necesitaba. Aunque parezca matar moscas a cañonazos, al final resultó ser bastante fácil de configurar.

Instalando y configurando Apache

El primer paso es instalar Apache en nuestro sistema:

sudo apt-get install apache2

El siguiente paso es habilitar los componentes necesarios para el balanceador:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_balancer

Una vez tenemos activados todos los componentes, debemos escribir la configuración al final (justo antes de la directiva </IfModule>) de /etc/apache2/mods-available/proxy.conf:

<VirtualHost *:80>
ProxyRequests off
<Proxy balancer://mycluster>
    # WebHead1
    BalancerMember http://scaledemo7844.azurewebsites.net:80

    # WebHead2
    BalancerMember http://scaledemoamerica.azurewebsites.net:80

                Order Deny,Allow
                Deny from none
                Allow from all

    ProxySet lbmethod=byrequests

</Proxy>
        ProxyPass / balancer://mycluster/
</VirtualHost>

Finalmente reiniciamos el servicio:

sudo apache2 restart

Si todo ha ido bien (y espero que sí), podemos acudir a http://ubuntubalancer.cloudapp.net/ (actualmente offline), donde accederemos indistintamente a cualquiera de las dos instancias y podremos ver su identificador.

Conclusiones

En este artículo hemos visto cómo podemos escalar nuestra página y usar un balanceador intermedio para gestionar las peticiones. Es un primer paso y todavía quedaría mucho por hacer. En el próximo artículo de esta serie, veremos cómo compartir la sesión entre las diferentes páginas que componen nuestro pequeño cluster.

Enlaces Interesantes:

Preparando el examen 70-484

El pasado 30 de mayo aprobé el examen 70-484 de desarrollo de aplicaciones para Windows 8 con C#, lo que me acerca un paso más al MCPD en desarrollo de apps para la plataforma, y es a su vez una excusa y un reto para aprender más de la misma.

Al comentarlo por Twitter, algunos desarrolladores me preguntaron qué recursos había usado, y aquí va un pequeño resumen.

Leer más “Preparando el examen 70-484”

Charla desarrollo Windows 8 en Valencia: Slides y código de ejemplo

El pasado 4 de abril tuve la oportunidad de volver a Valencia por tercera vez consecutiva para charlar con los alumnos de la’Escola Tècnica Superior d’Enginyeria (ETSE) sobre desarrollo de aplicaciones móviles en general, y en aplicaciones para Windows 8 y Windows 8 en particular.

Durante algo más de una hora estuvimos intentando dar respuesta a las siguientes preguntas:

  • ¿Merece la pena meterse en el mundo de desarrollo para aplicaciones móviles?
  • ¿Cuanto cuesta comenzar?
  • ¿Qué son los live tiles?
  • ¿Cómo integrarnos con el sistema operativo?
  • ¿Qué opciones de publicación tenemos?
  • Y muchas más.

Para ello, estuvimos desarrollando una pequeña aplicación con las siguientes características:

  • Cliente REST para consumir la API de datos de youtube.
  • Múltiples pantallas para poder ver detalles sobre un vídeo concreto
  • Posibilidad de cargar datos desde disco, usando el File Picker
  • Preferencias integradas en el cuadro de diálogo “Settings”.
  • Posibilidad de compartir con otras aplicaciones a través del Share contract

El código fuente de ejemplo está disponible aquí: https://app.box.com/s/d5d6iot8y6v5ankz5kfy

Finalmente, la presentación se encuentra disponible en slideshare

Happy hacking!

My february pet project: RealPoll (10+ technologies + a lot of fun)

Test it live: Realpoll at Azure

After my fist side-project (which I might publish on march or april) with Angular.js, I’ve been playing with different web technologies by doing a remake of a hackathon idea: Meet realpoll.

welcomeToRealPoll

The Idea

Teachers and speakers often need a way to engage the audience and give them the possibility to participate in the talk or the subject. Today is very common to see students tweeting from class, so this means they do have portable, wireless internet. The response of some centers is to block communications, but, why not use it the other way?

This web app allows the teachers to previously prepare some questions, choose the number of answers, the correct ones, and display the question on a projector. The students can then, use the url or capture the QR code generated from their cell phones. Once the question is generated, the trainer can choose the time that will be the poll open (in seconds).

When the time is up, the dashboard will mark the correct answers and those who answered correctly. The only data that is saved is the question and the answers, so you can come back and repeat it.

The voting interface is very, very simple: Just add a name and click on your chosen answer. It will be send inmediately to the dashboard.

Remake of a classic

The fact is that realpoll is a previous project done in a hackathon using a completely different tooling:

  • 100% HTML + Javascript
  • redis for the data layer
  • socket.io for handling the real time interaction
  • express.js for handling routing and views
  • google charts for the graphics
  • plain jquery for DOM management
  • Heroku as cloud host
  • developed with VIM

For this project, I wanted to keep the idea, but change completely the technologies used:

  • 50% HTML + Javascript, 50% C#
  • sql + entity framework for the data layer
  • signalr for the real-time interaction
  • ASP.net MVC for handling routing and views
  • Chart.js for the graphics
  • jquery and Angular.js for handling the views
  • RazorEngine for the views
  • Git/github as SCM
  • Windows Azure as cloud host (connected to github)
  • Visual Studio + IE dev tools + Chrome dev tools (+ Safari dev tools on mac)
  • Sendgrid for mailing.

Items

Architecture

The backend is pure ASP.net MVC with the data stored in a SQL Server database, and some services (such as email) for making my life a little bit easier.

The system uses the database for storing the questions, so we can access later from a single URL. The URL is a hash based on the question ID. The voting process is not stored, so it resets when we refresh the dashboard. The communication between the database and the app is done by using Entity Framework, Microsoft’s open source ORM.

For being able to use data without having to worry about the ORM, I used dependency injection techniques to inject a fake data source. The Depencency Injection framework chosen was ninject, and while I had to create two different classes for ASP.net MVC and SignalR dependency solvers, I had a single entry point to replace the fake access with the ORM data source.

Flow

Architecture

New question

The “New” page looks like this, It’s bootstrap for the UI and angular for handling the UI updates when the question number changes:

CreateQuestion

Created

When we create a question, data is updated in the database and we see a confirmation page like this:

Created

For generating the e-mail sent I use RazorParser, a nuget-available dll that allows me to generate an html view from a model and a file, and once generated use it as a string. The e-mail is sent through sendgrid’s SMTP, using the standard SMTP functions.

Result/dashboard Page

The result page is one of the most complicated, the charts are created by using chart.js with a wrapper for angular, the qr code is generated by using the qrickit API, and it’s updated in real time by using signalR and angular.js for handling the views.

Dashboard

When the time is up, the correct solution is highlighted, and those whose answer matches are highlighted also

Mobile Interface

Mobile

As Bootstrap is mobile ready, I had to do few changes to make the ui work flawlessly, had to do some debugging on Safari for Mac (whose web developer tools are way less powerul than Chrome/IE’s) connected to an iPhone. The cookie consent also adapts so, no issues here.

Stats and cookies

As the goal of the project was to play with technology, I havne’t been playing troo much with stats, but I did have added a google analytics code in each page. Also as I’m on the EU, there is a strict control of which cookies can be installed in the user’s machine (even more strict in Spain) so I’ve used the cookie consent code that allows the user to control the analytics tracking.

Source control, deploy and debug.

The project has been done by using git as source control manager, github as repository and the deployment has been done in Windows Azure. Azure has a hook for git, so when I push to github it will deploy to azure. As is git-based, it allows me to rollback inmediately while keeping the continuous deployment options available.

Finally, for remote debugging I added Elmah (Error Logging Modules and Handlers) to track down exceptions and issues that happened in Azure.

Issues, curious and weird things

  • There is a bug with angular an Visual Studio’s browser link that causes constant debugger stops on frontend code, be aware.
  • For adding dependency injection with ninject for signalR and MVC, you need to define two different dependency solvers, because they belong to different assemblies and implement different interfaces.
  • Validating input data has become way easier with HTML5, butS afari (and specially safari for iPhone) do not support the required tag for html, a useful guide is caniuse
  • For debugging on Safari for iPhone you need Safari running on Mac OS X.
  • When you re-deploy a solution to azure, (with the configuration by default) you lose all the exceptions tracked by elmah
  • I’ve used some funny xml transformations for handling local, remote and fake databases.

Room for improvement

Of course, there are always things that may go better, I didn’t write a single line of test code (other than my fake db wrapper) so it should be considered fairly unstable. The goal of this mini-project was to integrate as many technologies as possible to create a ready-to-deploy real-time web application. I would have added some UI tests with selenium, and maybe some unit testing for both angular and mvc controller.

Try it!

You can test it live on Realpoll at Azure or you can get the source code from the project’s github repository and deploy it by yourself. You will need your own API keys and your own database for making it work. Comments will also be apreciated, and if you want to contribute back, just send a pull request!