ASP.NET MVC y Knockout : ViewModel

Una situación muy común que nos encontramos cuando comenzamos a trabajar con Knockout y ASP.NET MVC es la inicialización del modelo de KO (estructura JS) a partir del modelo de la vista (objeto C#). Una alternativa es inicializar el modelo de KO por medio de una llamada ajax al servidor (por ejemplo invocar un servicio WebAPI que nos devuelva el modelo ya serializado). Sin embargo como explica Eric Hexter en este excelente post, la experiencia de carga de la página por medio del renderizado del servidor (server side rendering) al parecer sigue siendo la más óptima.

Por lo tanto tenemos por un lado un renderizado inicial del lado del servidor utilizando un modelo de vista para tal propósito y por el otro lado tenemos KO con su propio modelo. La pregunta es cómo transformamos el viewmodel de ASP.NET MVC al viewmodel de KO sin utilizar llamas Ajax?

Investigando un poco encontré una simple solución propuesta por Eric Hexter (ver enlace de arriba). Lo que él propone es que simplemente convirtamos el modelo de la vista en un objeto Json dentro del código javascript de la página. En el ejemplo utilizaremos el view engine Razor para tal fin.

Manos a la obra!

En primer lugar vamos a crear el método de extensión ToJson() que nos permitirá representar objetos de .NET en formato JSON:

JsonExtension

JsonExtension

Por medio de esta extensión vamos a tener disponible el modelo de la vista en formato JSON, lo que nos posibilitará utilizarlo en nuestra lógica del lado del cliente (código javascript). Ahora lo que necesitamos es mapear el objeto JSON a los objetos observables que utiliza KO. Quien nos permite realizar tal actividad es el siguiente plugin de KO: KnockoutJS Mapping plugin  (disponible por medio de Nuget):

PM> Install-Package Knockout.Mapping

Veamos qué tan simple es su uso (continuamos con el ejemplo del post anterior):

Serializando el view model.

Serializando el view model.

Algunos puntos importantes:

  • Referencias a las librerías de KO y KnockoutJS Mapping plugin.
  • Generamos la representación JSON del modelo de la vista (del servidor) por medio del método de extensión ToJSon() y lo escribimos en el script por medio del helper HTML Raw.
  • El resto debería ser historia conocida 😉

Bien, finalmente tenemos el cuerpo del documento HTML:

Estructura HTML

Estructura HTML

Y la generación – mock – del modelo (en este ejemplo en el método de acción Index del controlador Home):

Método de acción Index

Método de acción Index

Corremos la aplicación y deberíamos obtener el siguiente resultado:

Resultado :)

Resultado 🙂

Como pueden ver esta es una forma muy simple de bindear el modelo de la vista del servidor al modelo de la vista del cliente.

Espero que les sea de utilidad!

Anuncios

Introducción a Knockout

Knockout es una pequeña biblioteca JavaScript  de código abierto (40 kb de tamaño) escrita por Steve Sanderson (quien trabajo para Microsoft y es el autor del libro Pro ASP.NET MVC Framework ente otras muchas otras publicaciones).

Esta librería nos ayuda a crear interfaces ricas, responsivas y declarativas permitiendo enlazar-sincronizar objetos Javascripts con elementos HTML utilizando para ello el patrón MVVM. Esto nos permite, entre otras cosas, tener el front-end mucho más organizado y en consecuencia un código más legible y mantenible.

Knockout

Knockout

Ahora bien, de que se trata esto de enlazar elementos HTML con objetos de javascript?. Bien para apreciar todo el potencial de Knockout antes vamos a trabajar en un ejemplo muy simple utilizando la ya famosa librería jQuery. La idea es mostrar información sobre bloggeros en la página.

Arranquemos definiendo la página HTML:

HTML -Estructura inicial

HTML -Estructura inicial

Es importante en este punto agregar la referencia a la librería de jQuery. Sin embargo en este punto no es necesario agregar la librería a KO. También agregué la referencia al archivo de script – Index.js – donde vamos a definir toda la lógica del lado del cliente.

Y ahora el turno del JS:

JS - "Enlazando" con jQuery objetos JS con elementos HTML.

JS – “Enlazando” con jQuery objetos JS y elementos HTML.

Pasemos a revisar lo que hicimos. En primer lugar creamos un objeto javascript y lo asignamos a la variable persona. En segundo lugar “enlazamos” (aunque vamos a ver que no es del todo correcta esta definición en esta instancia) cada propiedad de la persona con los elementos HTML correspondientes (utilizando selectores de jQuery para identificar dichos elementos).

Simple, no?… pero pensemos un poco… trabajar de esta forma implica que vamos a necesitar una línea de código (sentencia de jQuery) por cada nueva propiedad que queramos enlazar al HTML. Es posible que en el corto plazo surjan nuevas propiedades de la persona que nos interese mostrar, por lo este código se puede llegar a tornar engorroso y  molesto, no?

Bien, unas líneas más arriba les comentaba que el término “enlace” no era del todo correcto. Supongamos que modificamos alguna de las propiedades de la persona: el valor se actualizará en el objeto HTML? Y sí modificamos el contenido del objeto HTML, en la propiedad de la persona se verá reflejado tal cambio? En ambos casos la respuesta es NO (al menos no de una manera simple y prolija).

Es el turno de que entre en escena Knockout (KO) y nos solucione el problema (aplausos!)

Arranquemos adaptando el HTML (ahora sí es necesaria la referencia a las librería KO, pueden descargarla desde acá):

HTML - Bindings declarativos

HTML – Bindings declarativos

Podrán observar que los atributos Id ya no son necesarios y en su lugar agregamos atributos data-bind, los cuales nos permitirán enlazar los datos entre los elementos destino y el objeto de origen. Estos atributos forman parte del sistema de bindings declarativos que proporciona KO.

JS - Enlanzado datos con KO.

JS – Enlazando datos con KO.

Un punto importante es comentar que el espacio de nombres de Knockout es ko (lo equivalente al $ de jQuery). Al llamar a la función applyBindings(model) Knockout enlaza el objeto especificado con los elementos de la página que tengan el atributo data-bind correspondiente. Como mencionamos arriba, esto forma parte del sistema de binding declarativos que nos permiten crear vínculos uni o bidireccionales entre elementos HTML y las propiedades o acciones del modelo javascript.

En los atributos data-bing podemos especificar  de que forma de enlazar los valores (en nuestro ejemplo hemos especificado enlace de textos y de valor ). Existen varios tipos de enlaces integrados proporcionados por KO que nos facilitan el enlace entre las propiedades de los objetos JS con los elementos del DOM:

  • “text: propiedad”: tipo de enlaces de texto (utilizados en elementos p y span).
  • “visible: propiedad”: tipos de enlaces de visibilidad (valores posibles true o false).
  • “value: propiedad”: tipo de enlaces de valor (utilizados en elementos input, select y textarea).
  • “css: propiedad”: tipo de enlaces de estilo (aplica al css de los elementos).
  • “checked: propiedad”: tipo de enlaces de ckeck (utilizado en elementos checkbox).
  • “click: propiedad”: tipo de enlace a eventos javascript (utilizado en elementos button, input y a).
  • “attr: {src: propiedadUrl, alt: propiedadTexto}”: tipo de enlace para enlaces (se utiliza en elementos img).

La forma en que KO aplica los enlaces integrado en los elementos de DOM variará entre otras cosas del tipo y versión del navegador.

Ahora bien, vamos a hacer algunos unos pequeños cambios en nuestro código. En primer lugar vamos a agregar un elemento <span> donde visualizar el nombre de la persona-blogger:

HTML - Agregando elemento span para visualizar nombre.

HTML – Agregando elemento span para visualizar nombre.

Y vamos a cambiar el nombre de la variable por algo más representativo al patrón que estamos aplicando:

JS - Renombrando al modelo.

JS – Renombrando al modelo.

Abramos la página:

Página Web v1.0

Página Web v1.0

Qué pasa si ahora cambiamos el nombre de la persona:

v1.0 no se comporta como esperamos

v1.0 no se comporta como esperamos

Mmmm… si ambos elementos HTML están enlazados a la misma propiedad del modelo,por qué no se actualizo el nombre del blogger en el mensaje de bienvenida cuando los modificamos en el campo de texto?

Para poder mantener sincronizados todos los elementos con el modelo KO utiliza el concepto de observables. Los observables permiten el seguimiento de las dependencias y son objetos que pueden notificar a unos agentes de escucha cuando los valores cambian.  Para definir una propiedad como observable simplemente debemos asignarle la función ko.observable(default_value).

Los observables pueden aplicarse a todas las propiedades de un modelo, o solo a las que nos interesa tener sincronizados:

JS - Definiendo propiedades como observables.

JS – Definiendo propiedades como observables.

Ahora si cambiamos el valor desde la caja de texto vamos a observar que cambia el mensaje de bienvenida también:

Página Web v2.0

Página Web v2.0

Esta característica se la conoce como seguimiento de dependencias y permite detectar los cambios que ocurren en la vista (elementos del DOM) como en el modelo-vista (objetos javascripts) para propagarlos hacia todos los objetos/elementos dependientes.

Pero aún hay más, que pasa si queremos adaptar el mensaje de bienvenida con el siguiente formato: “Bienvenido Nombre, felicitaciones por su blog Blog!!!”. Una solución muy simple sería agregar un nuevo elemento <span> y enlazarlo a la propiedad blog por medio de un observable. El problema es que cuanto más datos querramos visualizar en el mensaje, más elementos span deberíamos agregar, y en este punto nos volvemos a encontrar con un problema que deberíamos evitar con KO.

Por suerte KO nos provee de observables calculados.

Veamos como utilizarlos, modificando la estructura del documento HTML:

HTML - Creamos un elemento donde enlazar el mensaje.

HTML – Creamos un elemento donde enlazar el mensaje.

Acto seguido, modificamos el script JS:

JS - Enlazando por medio de un observable calculado.

JS – Enlazando por medio de un observable calculado.

Pero que de cambios!… en primer lugar es hora de definir nuestro view model de manera tal que se comporte de una forma similar a un objeto de C# (salvando las distancias y limitaciones del lenguaje) y que no sea una simple estructura. En segundo lugar la función ko.computed(function(){…}) nos permite definir una función enlazante que actualiza esta propiedad calculada cuando cambia alguno de los observables de los que su evaluación depende.

Página Web v3.0

Página Web v3.0

Y aún hay más!

Imaginemos ahora que queremos visualizar una lista de bloggeros. Lo primero que debemos hacer es crear un array del modelo de persona y de alguna manera enlazarlo a los elementos del DOM, correcto? Bien avancemos entonces y lo primero que vamos a modificar es la estructura del HMTL:

HTML - Definiendo los elementos y enlaces para visualizar la lista de personas.

HTML – Definiendo los elementos y enlaces para visualizar la lista de personas.

Apliquemos los cambios al archivo JS:

JS - Definiendo un view model para un array de objetos y enlazarlos.

JS – Definiendo un view model para un array de objetos y enlazarlos.

Como podemos observar agregamos un nuevo view model que tiene como atributo una función observableArray (en KO las matrices de objetos se deben definir siempre con dicha función). En las propiedades que son observableArray cada vez que se le agrega o elimina un elemento, estos cambios son notificados a los elementos enlazados (en nuestro caso una lista) y por supuesto irán modificando el DOM.

Resultado:

Página Web v4.0

Página Web v4.0

Para listar los elementos usamos el control de flujo foreach, sin embargo KO también nos provee de otros controles adiciones tales como if, ifnot y with.

Veamos un ejemplo muy simple del control de flujo if y ifnot (el primero evalúa una condición verdadera y el segundo una condición falsa):

HTML - Declarando controles de flujo.

HTML – Declarando controles de flujo.

Resultado:

Página Web v5.0

Página Web v5.0

Por último el control de flujo with es útil en objetos que tienen relaciones con otros objetos (por ejemplo una persona podría tener una objeto dirección y un objeto informaciónContacto relacionados). With nos permite entonces enlazar de una manera muy simple estos elementos:

HTML - Declarando control de flujo with.

HTML – Declarando control de flujo with.

Conclusión: KO nos permite trabajar del lado del front-end de una forma mucho mas organizada, prolija y sencilla, evitándonos mucho trabajo en lo que refiere en enlace de datos con los elementos del DOM. También nos permite tener un comportamiento mucho más fluido en la UI y por ende una experiencia de uso mucho mas agradable (similar a una aplicación Win 8). Seguramente habrá que evaluar el tipo de proyecto antes de implementar KO, pero en general considérelo como una buena alternativa.

Espero que les haya resultado útil!

ASP.NET MVC – Gestionando la memoria Cache

Hace un tiempo que estoy leyendo acerca de HTML y algunos de los temas que me llamo la atención fueron sobre la directiva HEAD. Esta directiva corresponde al encabezado de un documento HTML y contiene información que nos ayuda a interpretar y mantener el contenido de su cuerpo – BODY.

<html>
<head>
<title>Title of the document</title>
</head>
<body>
The content of the document……
</body>
</html>

Una de las directivas que componen el encabezado es META. Esta directiva suele tener dos usos: como contenedor de meta-información sobre el documento (generalmente utilizada para indexar dichos documentos con los navegadores), o como contenedor de información adicional relacionada con el protocolo HTTP . Si deseamos utilizar la directiva META para el primer caso, debemos hacer uso del atributo NAME y para el segundo caso el atributo HTTP-EQUIV. Un ejemplo de ambos uso es el siguiente:

<head>
<meta name=”description” content=”Free Web tutorials” />
<meta name=”keywords” content=”HTML,CSS,XML,JavaScript” />
<meta name=”author” content=”Hege Refsnes” />
<meta http-equiv=”content-type” content=”text/html;charset=UTF-8″ />
</head>

La etiqueta HTTP-EQUIV, nos permite tener control sobre los navegadores, y suelen ser utilizadas para: recargas automáticas de página, controlar la cache del navegador, especificar la fecha de espiración del documento o el lenguaje “nativo” del mismo entre otras opciones.

En esta oportunidad, nos vamos a enfocar en la administración de la cache del documento, la cual esta espeficiada por el valor “cache-control“:

<meta http-equiv=”cache-control” content=”no-cache” />

Nota: para los nostálgicos, en Netscape la misma se representaba de la siguiente manera:

<meta http-equiv=”pragma” content=”no-cache/cache” />

Los valores posibles del encabezado cache-control son:

  • public: las caches de los clientes y las cachés compartidas (de servidores proxy) pueden almacenar la respuesta.
  • private: la respuesta sólo se almacena en la memoria caché del cliente y no en memorias caché compartidas (servidor proxy).
  • no-cache: no cache.
  • no-store: se realiza la cache del contenido pero no es archivada.

Veremos más adelante que .NET provee un enumerado de dichos valores.

Otros atributos que podemos especificar en este encabezado son los siguientes:

  • max-age: representa el tiempo de caducidad, especificado en segundos, y se cuenta a partir del momento en que se realiza la petición del recurso, por lo que ofrece mayor flexibilidad.
  • s-maxage: similar a max-age, pero sólo se aplica a cachés proxy.
  • must-revalidate: comunica a las cachés que deben seguir estrictamente todas nuestras reglas sobre la caducidad de los recursos. El protocolo HTTP da a las cachés cierta libertad a este respecto, la cual se puede restringir con esta directriz.
  • proxy-revalidate: similar a must-revalidate, pero sólo se aplica a cachés proxy.

Ahora bien, teniendo en cuenta todo esto, podríamos crear un filtro de acción en ASP.NET MVC para establecer que nuestras páginas sean almacenen en la memoria cache. Para esto vamos a crear la clase CacheAttribut que deberá heredar de la clase ActionFilterAttribute.

Una de las propiedades de dicha clase será la duración de la cache (representada en segundos) y la segunda el valor del encabezado HTTP Cache-Control representado por enumerado HttpCacheability:

Valores posibles del encabezado HTTP Cache-Control

Valores posibles del enumerado HttpCacheability

Para poder indicarle al navegador que queremos almacenar en la chace la página que estamos sirviendo, necesitamos interceptar la ejecución de la misma y agregar en el encabezado directivas META con el atributo http-equiv correspondiente al manejo de la cache. Para esto vamos a sobre-escribir el método OnActionExecuted en el nuevo filtro de acción:

Como vemos, el parametro que recibe este método es del tipo ActionExecutedContext y representa el contexto en el cual se esta ejecutando una acción. Una de las propiedades es del tipo HttpCachePolicyBase la cual nos permitirá establecer las políticas de caché de la página web.

Veamos una definición mas completa que no brinda MSDN sobre el namespace System.Web.HttpCachePolicyBase:

Actúa como clase base para las clases que contienen métodos para establoecer los encabezados HTTP específicos de la memoria caché y para controlar la memoria caché de resultados de las páginas ASP.NET.

Ok, ahora ya tenemos listo nuestro ActionFilter, vamos a ponerlo a prueba. 🙂

Lo primero será ejecutar nuestra aplicación sin el uso de cache, para eso definimos una vista llamada Index de la forma habitual, y veamos la respuesta del servidor:

Respuesta del servidor

Respuesta del servidor

Sin especificar nada en el proyecto, ASP.NET MVC retorna páginas con el tipo de cache Private sin ningún otro tipo de especificación.

Ahora vamos a agregarle el atributo Cache, especificando que será del tipo Public con una duración de 60 segundos:

Ejecutemos y veamos la respuesta:

Respuesta del servidor

Respuesta del servidor

Como veran, la memoria cache esta especificada como Public, con una duración (max-age) de 60 segundos. También tenemos con información del encabezado la fecha y hora en que expira la misma.

Para terminar, quiero decirles que ASP.NET MVC ya nos provee de un filtro de acción que nos permite establecer cuestiones propias de la cache: el action filter OutputCache. Veamos un ejemplo rápido de su uso, en este caso para especificar que no queremos utilizar ningun tipo de cache en la vista:


La respuesta del servidor es la siguiente:

Respuesta del servidor

Respuesta del servidor

Vean que la fecha de espiración de la cache es la misma fecha en la que es devuelto el documento, por lo que al servir nuevamente la página la misma se obtendrá directamente del servidor y no de la cache del servidor proxy o del cliente. Utilizando esta librería podemos realizar configuraciones del manejo de la cache de manera global al sitio, o crear distintos perfiles de cache especificandolos en el archivo web.config.

Recomiendo que lean el siguiente tutorial del sitio oficial de ASP.NET MVC acerca de este tema.

Quienes quieran descargar el proyecto pueden hacerlo desde acá: MyMvcApplication – ManejoMemoriaCache.rar.

Espero que les sea de utilidad!

ASP.NET MVC : Entendiendo ResponseRedirect

Quienes desarrollamos en algún momento en ASP.NET Webform no necesitábamos tener conocimientos web de bajo nivel ya que los mismos eran abstraídos por el mismo framework. Esto se debía a que ASP.NET, en ese entonces, había sido pensado para atraer a los desarrolladores de aplicaciones de escritorio que se resistían pasar al desarrollo de aplicaciones web. Por lo tanto, la estrategia de MS fue seguir con esa misma filosofía.

En el momento en que uno hace el pase a ASP.NET MVC – cosa que recomiendo a todo desarrollador web de .NET 🙂 – tiene la necesidad de conocer más en profundidad estas cuestiones (HTTP, HTML, CSS…), ya que es parte de la naturaleza del framework y facilita enormemente el desarrollo sobre el mismo.

Como mencione anteriormente, una de las cuestiones web son los protocolos y  hace un tiempo atrás participé de la excelente VAN que presento Leonardo Micheloni sobre HTTP (llamada “HTTP y las ruedas de la web“) donde uno de los tema que toco fueron los distintos códigos de estado que provee este protocolo.

Para quienes no conozcan demasiado de este tema cuando uno hace una petición por medio de una URL se inicia una transacción desde el cliente que termina con una respuesta del servidor que generalmente viene compuesta por el recurso solicitado (sea un HTML, XML…). Uno de los datos que viajan en el encabezado de la respuesta es el código de estado (de los cuales los más conocidos son 200 OK o 404 NOT FOUND).

Estos códigos de estado se encuentran agrupados según su función y uno de esos grupos corresponden a las Redirecciones : 3xx.

Todo esto me hizo pensar en como funcionaba realmente el método RedirectToAction que nos provee la clase Controller de ASP.NET MVC.  Y mis sospecha – no demasiadas brillantes – eran ciertas, la solicitud a una vista que utiliza RedirectToAction retorna HTTP Code Status 302.

Antes de continuar, veamos un poco más en profundidad, de que se trata el código 302 viendo una definición de Wikipedia:

Este es el código de redirección más popular, pero también un ejemplo de las prácticas de la industria contradiciendo el estándar. La especificación HTTP/1.0 (RFC 1945) requería que el cliente realizara una redirección temporal (la frase descriptiva original fue “Moved Temporarily”), pero los navegadores populares lo implementaron como 303 See Other. Por tanto, HTTP/1.1 añadió códigos de estado 303 y 307 para eliminar la ambigüedad entre ambos comportamientos. Sin embargo, la mayoría de aplicaciones web y bibliotecas de desarrollo aún utilizan el código de respuesta 302 como si fuera el 303.

Luego de esta larga introducción, vayamos al grano y definamos dos vistas, la primera la llamaremos Index y la segunda Final. Lo que hará la primer vista será simplemente redireccionar a la segunda:

1: public class HomeController : Controller
2: {
3:     public ActionResult Index()
4:     {
5:         return RedirectToAction("Final");
6:     }
7:
8:     public ActionResult Final()
9:     {
10:         return View();
11:     }
12: }

Ejecutemos y analicemos la respuesta del servidor:

Respuesta HTTP

Respuesta HTTP

Vemos que la petición GET a la URL “http://localhost…/Index&#8221; retorna el código 302 Found, y seguido se hace una nueva petición a “http://localhost…/Final&#8221; que finalmente es devuelta exitosamente (retornando el código 2oo OK).

Para saber donde tiene que hacer la redirección, uno de los datos que viajan en el encabezado de la respuesta es Location el cual contiene dicha información:

Encabezado de la respuesta HTTP

Encabezado de la respuesta HTTP

Es importante que entendamos como funcionan estas cuestiones, que si bien son simples, uno muchas veces las desconoce pensando que todo es resuelto “magicamente” por el framework.

Espero que les haya sido de utilidad.