Hola a todos, vuelvo con otro post sobre Web API, en esta ocasión quiero mostros como podemos implementar un sencillo sistema de caché para reducir las peticiones que se realizan a nuestro servicio y así poder mejorar el rendimiento del mismo, para el ejemplo implementaremos dicho sistema en la acción que retorna todo el listado de personas, recordando tenemos algo como:



public IEnumerable<Person> GetPerson() 
{ 
    var data = db.Person.AsEnumerable(); 
    return data;
}

La acción anterior simplemente consulta la fuente de datos y los retorna, sin embargo este tipo de comportamientos puede traernos problemas futuros ya que constantemente se está consultando la fuente de datos para traer todos los registros existentes y si dicha fuente de datos es una base de datos se debe tener presente el abrir y cerrar conexiones, el delay entre que se lanza el query y el momento en que el servidor de base de datos responde… ya vemos por donde va todo no?

Pensando en el problema anterior, una solución es implementar un sistema de caché para reducir las peticiones a la base de datos y en algunos casos (como este) también disminuir los request al servicio. Lo primero es añadir un nuevo botón que realice la petición a la acción GetPerson() para ver su comportamiento:


<input type="button" id="btnGetAll" value="Get all" data-bind="click:getAll" />;

Ahora probamos de nuevo la aplicación y para ver el comportamiento damos click varias veces en el botón creado anteriormente, con ayuda de firebug revisemos las peticiones:

firebug1

y el detalle de alguna de ellas:

no-cache

Resumiendo la prueba, cada vez que damos click en el botón se realiza una nueva llamada al servicio, y como se aprecia en el detalle de la petición, en el Header de la respuesta el Cache-Control tiene el valor* no-cache*, que como adivinan indica que no se está manejando.

Para aplicar caché, vamos a hacerle un refactoring a la acción GetPerson() teniendo en cuenta los siguientes puntos:

  • Se retornará HttpResponseMessage en lugar de IEnumerable.
  • Se definirá la caché en el header de la respuesta.

Con los dos puntos anteriores en mente, ahora la acción GetPerson() quedaría:


public HttpResponseMessage GetPerson() 
{ 
    var data = db.Person.AsEnumerable(); 
    var httpResponseMessage = Request.CreateResponse<<IEnumerable<Person>>(HttpStatusCode.OK, data); 
    httpResponseMessage.Headers.CacheControl = new CacheControlHeaderValue() 
    { 
        MaxAge = TimeSpan.FromMinutes(1) 
    }; 

    return httpResponseMessage; 
}

Lo primero es obtener los datos, luego se crea el objeto HttpResponseMessage, se define el tipo de dato que se retornará, en este caso un IEnumerable, el código de la respuesta es 200 (HttpStatusCode.OK) y los datos; y ahora para especificar el uso y tiempo de vida de la cache, modificamos el valor de la propiedad CacheControl del header y definimos que su tiempo de vida será de 1 minuto.


Si ahora repetimos la prueba realizada, y damos click varias veces seguidas en el botón para obtener todos los datos, visualizamos que ya no se realizan tantas peticiones como clicks,ya que la caché usada guarda los datos en JSON en el cliente y los utiliza cada vez que hacemos click, claro que una vez se complete 1 minuto, la siguiente petición SI se realizará normalmente y se volverá a cachear la respuesta, y para que no quede duda, revisemos de nuevo la información de la petición y su respuesta con firebug, la propiedad Cache-Control ahora tiene el valor max-age=60, es decir que usa caché con un duración de 60 segundos.

si-cache

Espero e post les haya gustado, nos vemos!

Saludos!

Descarga el ejemplo!