Una sinfonía en C#

Un pequeño aporte a la comunidad de habla hispana.

ASP.NET MVC Series–Model Binder

Como dijimos antes, una de la piezas importantes del framework es el Model Binder, quien se encarga de asociar los datos enviados en un request HTTP con parámetros en las acciones de un controlador, es decir, si un usuario llena un formulario con su email y contraseña el Model Binder es el encargado de recuperar los datos del request y hacerlos llegar al controlador en forma de parámetros, por ejemplo.

Agregando parámetros en las acciones del controlador

Vamos a tomar el ejemplo que con el que hemos estado trabajando y agregar un nuevo método con un parámetro, del siguiente modo:

    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Saludar(string nombre)
        {
            return new ContentResult { Content = "hola " + nombre };
        }

    }

La acción Saludar, recibe un parámetro, del mismo modo que lo haría si fuera un método de una aplicación Winforms, de consola, etc.

Lo interesante es que el framework se va a encargar de asociar los datos que envía el usuario con ese parámetro de manera absolutamente transparente para nosotros, o como yo diría “mágico”

Para comprobarlo vamos a correr el sitio y escribir en la barra de navegación

http://localhost:54040/home/saludar

donde por supesto localhost:5404 el la dirección donde está corriendo el sitio. Hacemos esto y vemos lo siguiente:

image

Nada impresionante, vemos que llega el texto “hola” sin más, porque no le pasamos ningún parámetro al controlador durante el request, pero vamos a hacerlo, escribimos la siguiente dirección en el navegador:

http://localhost:54040/home/saludar?nombre=leonardo

y vemos esto:

image

Como vemos al pasar el parámetro nombre en la URL, el Model Binder automáticamente asigna su valor al parámetro del controlador, de esta manera dentro del mismo no nos tenemos que preocupar por detalles de HTTP ni nada parecido.

Tipos de datos

En el primer intento no le pasamos el parámetro en el request para que el Model Binder pueda asociarlo al del controlador sin embargo eso no fue un problema, la respuesta es sencilla: el parámetro nombre es del tipo string y en C# el tipo string es un tipo por referencia, es decir, permite valores nulos, por lo tanto sino podemos un valor no pasa nada.

La pregunta es qué pasa si el parámetro fuese un tipo que no es por referencia sino por valor? por ejemplo un int, vamos a probarlo:

    public ActionResult Numeros(int valor)
    {
        return new ContentResult { Content = "ingresaste " + valor };
    }

Agregamos una nueva acción que recibe un entero y escribimos en el navegador

http://localhost:54040/home/numeros

y vemos lo siguiente

image

y vemos que se rompe justamente porque no se puede asignar null a un entero, la forma de hacerlo funcionar es pasar como parámetro cualquier valor que pueda ser convertido en int por el Model Binder, por ejemplo.

image

Funciona muy bien. Sonrisa

Se pueden pasar objetos como parámetros?

La respuesta es sí, el Model Binder es muy potente y siempre hará su mejor esfuerzo por completar los parámetros, por ejemplo

    public class HomeController : Controller
    {
        public ActionResult Login(Usuario usuario)
        {
            return new ContentResult { Content = string.Format("nombre: {0}, clave: {1}", usuario.Nombre, usuario.Clave) };
        }
    }

    public class Usuario
    {
        public string Nombre { get; set; }
        public string Clave { get; set; }
    }

Compilamos y entonces:

image

Como se ve, el Model Binder detecta que queremos una variable del tipo Usuario como parámetro, intenta crear una instancia y llenar sus propiedades con los valores que llegan en el request.

Qué hay acerca de los formularios y el método POST?

Es lo mismo, podemos hacer un formulario y enviar los datos por POST hacia el mismo método y funcionaría igual, por ejemplo

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Login(Usuario usuario)
        {
            return new ContentResult { Content = string.Format("nombre: {0}, clave: {1}", usuario.Nombre, usuario.Clave) };
        }
    }

    public class Usuario
    {
        public string Nombre { get; set; }
        public string Clave { get; set; }
    }

la vista home.cshtml

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>Index</title>
</head>
<body>
    <div>
        <form action="/home/login" method="post">
            <p><input type="text" name="nombre" id="nombre" /><label for="nombre">Nombre</label></p>
            <p><input type="password" name="clave" id="clave" /><label for="clave">Clave</label></p>
            <input type="submit" value="Enviar" />
        </form>
    </div>
</body>
</html>

ejecutamos

image

Presionamos “Enviar” y listo

image

Mágico.

Por ahora es una buena introducción a Model Binder, la seguimos la próxima.

ASP.NET MVC Series–ActionResults

Todos los controladores en ASP.NET MVC tiene como tipo de resultado un ActionResult (o casi) la pregunta es por qué?

Los ActionResult con objetos que encapsulan respuestas HTTP

Tal cual, ActionResult no es más que una abstracción para respuestas HTTP, entonces podemos decir que todos los controladores retornan respuestas HTTP cosa que es muy lógica en un framework Web.

Diferentes tipos de ActionResults

Hay muchos, y dependiendo de la versión de ASP.NET MVC cambian, así que vamos a enumerar los más comunes:

ViewResult: éste es bien clásico, representa una vista, es decir, un HTML, en principio lo que hace es localizar una vista dada (si no indicamos cuál busca una vista con el mismo nombre de la acción) le pasa el modelo, la procesa y la devuelve al cliente como HTML, por ejemplo:

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    }

Y la respuesta es un HTTP 200 en el cual el Content-type es text/html

image

En este caso se buscará la vista llamada “index” dentro de la carpeta Views-home por ya que el nombre del controlador es “HomeController” (convención)

Nada impide que especifiquemos otra vista pasando el nombre como parámetro.

RedirectResult: éste es una respuesta HTTP del tipo 302 que indica una redirección, sería así

public ActionResult Ir()
{
    return Redirect("http://www.otro.com");
}

Si miramos el detalle de la respuesta HTTP vemos que no es más que una redirección

image

RedirectToAction: Es una redirección también, igual a la anterior nada más que sólo debemos indicar el nombre de la acción dentro del un controlador a la cual queremos redireccionar en lugar de una URL literal.

ContentResult: Éste es más interesante, nos permite devolver un contenido cualquiera, por ejemplo un archivo de texto, por supuesto es un HTTP 200 y tenemos que indicar el contenido y además el Content-type para que el navegador sepa interpretarlo

public ActionResult Contenido()
{
    return Content("hola mundo", "text/plain");
}

y la respuesta sería:

image

HTTPNotFound: Como su nombre indica es un código 404 HTTP para indicar que un contenido no existe

public ActionResult NoExiste()
{
    return HttpNotFound();
}

image

Generando ActionResults a mano

Estos ActionResults los tenemos como métodos porque existen en la clase base Controller de la cual hereda nuestro controlador, nada nos impide crear los nuestros, por ejemplo si quisiéramos un tipo de resultado HTTP 415 (Unsupported Media Type) podríamos hacerlo nosotros usando la clase ActionResult como clase base y configurando algunas propiedades, por ejemplo:

    public class HomeController : Controller
    {
        public ActionResult NoSoportado()
        {
            return new UnsoportedMediaTypeResult();
        }
    }

    public class UnsoportedMediaTypeResult : ActionResult
    {
        public override void ExecuteResult(ControllerContext context)
        {
            context.HttpContext.Response.StatusCode = 415;
            context.HttpContext.Response.StatusDescription = "Unsoported media type";
        }
    }

Simplemente heredamos de ActionResult y sobre-escribimos el método ExecuteResult, dentro del mismo recibimos como parámetro el context y dentro del él el HttpContext, es simple forzar valores en el objeto Response para lograr lo que buscamos.

image

Excelente, entonces, los ActionResult no son más que representaciones de respuestas HTTP. Existen muchos tipos predefinidos y muchos detalles más que veremos más adelante.

Hasta la próxima.

jQuery, Reemplazar “live” por “on”

 

Como sabemos nuestra querida librería jQuery sigue avanzando en versiones y las últimas actualizaciones han traído algunos cambios, algunos de ellos son más bien internos, transparentes para nosotros, pero otros no tanto

jQuery.live eventos a futuro

Una de las características que en algún momentos nos encontramos con la necesidad de usar es la posibilidad de asociar eventos a algún elemento, esto es bien común, sin embargo a veces ese elemento se genera dinámicamente (por ejemplo una listado que se actualiza) entonces, no existe cuando ejecutamos el código que asocia el evento.

http://007fanart.files.wordpress.com/2010/06/lald3.jpg

Asociar eventos a objetos que existen y existirán

Una forma de lograr esto fácil con jQuery es usar

$("a.boton").live("click", function(){
	alert("me apretaste!!!");
});

Es decir, utilizar la función live como usaríamos la función bind, con la diferencia que live se queda “mirando” los elementos que alcanza un selector después de su ejecución, entonces el evento será asociado a los elementos actuales (los haya o no) y a todos los futuros, para “apagar” esta funcionalidad basta con usar die.

$("a.boton").die("click");

Deprecado

A partir de jQuery 1.9 live y die ha sido deprecados y en su lugar hay que usar la función on y off, que de paso son más performantes, de la siguiente manera:

$("a").on("click",".boton", function(){
	alert("me apretaste!!!");
});
$("a").off("click",".boton");

Un detalle no menos es el segundo parámetro, en este caso selecciono todos los elementos del tipo a y luego hago un filtro por clase boton, podría no utilizar el filtro, pero no obtendría el efecto de live sino que sería un simple click común y corriente.

Entonces ya lo saben, a partir a ahora a usar on y off en nuestros eventos, nos leemos.

ASP.NET MVC Series–Hola MVC

Vamos a poner manos en el código rápido para ir viendo algunos conceptos en la práctica.

Primer ejemplo

Abrimos el Visual Studio 2012 Express for Web, creamos un nuevo proyecto y nos encontramos con las siguientes opciones:

image

Dentro de las opciones vemos un par de ASP.NET Web y un par de ASP.NET MVC, las que nos interesan a nosotros son las ASP.NET MVC, las otras son del tipo Web Forms.

Si bien tenemos las opciones ASP.NET MVC 3 y 4, vamos a empezar con la versión 3 ya que a mi entender la versión 4 tiene algunos cambios fuertes en comparación con la 2 y la 3 y va a ser más sencillo empezar por la 3 para después agregar los conceptos más nuevos.

Entonces creamos un proyecto ASP.NET MVC 3 y le ponemos un nombre, en un ataque se sagacidad y astucia se me ocurre ponerle “hola mundo”

image

La siguiente ventana nos da más opciones, en este caso vamos a elegir “Empty” y en la opción “View engine” dejamos Razor

Estructura del proyecto

Una vez creado el proyecto vemos unas cuantas particularidades en lo que se refiere a la organización:

image

Por defecto se crean varias carpetas:

  • Content
  • Controllers
  • Models
  • Scripts
  • Views

y además vemos algunos archivos

  • Global.asax
  • Web.config

(de momento ignoremos el resto)

Convención sobre configuración

Ya dijimos que una de las características del ASP.NET MVC es la utilización de convención sobre configuración, es decir, en lugar de tener que definir dónde se buscan ciertos recursos por convención se buscan en tal lugar, vamos a profundizar enseguida.

Cómo arranca el proyecto ASP.NET MVC?

Bien, ni lerdos ni perezosos vamos a presionar F5 para ejecutar el proyecto, luego de unos momentos se abre nuestro navegador por defecto y vemos lo siguiente:

image

Nada. Se rompió, y es lógico, dijimos que es el controlador quien recibe las peticiones del usuario y no hemos creado ninguno, por lo tanto no hay quien reciba la petición de la URL http://localhost:62078 (puede cambiar)

La pregunta es “cómo agregamos un controlador” y más importante aún “dónde lo agregamos”, bien, simplemente hacemos botón derecho sobre la carpeta “Controllers” (esta es una de las convenciones, todos los controladores deben estar ahí) y agregamos uno nuevo, vamos a ponerle “HomeController” como nombre y vamos a explicar por qué.

image

El nombre que pusimos tampoco es casual y sigue una convención, todos los controladores se llaman AlgoController (donde “Algo” es un nombre cualquiera)

image

El código generado tiene un método que se llama Index, esto es otra convención y funciona del siguiente modo: todo método público de un controlador es una acción visible desde el exterior, esto quiere decir que yo podría desde el navegador invocar ese método sin problema, más adelante vamos a ver la forma de evitarlo.

Cómo se invoca una acción de un controlador?

Nuevamente por convención, si vamos al navegador y escribimos

http://servidor:puerto/nombreControlador/nombreAccion

Vamos a invocar nuestro código, en este ejemplo sería:

http://localhost:62078/home/index

donde “home” es por HomeController e “index” el por el método Index, de esta manera ASP.NET MVC sabe que tiene que crear una instancia del controlador y llamar al método, siempre y cuando el controlador se llame HomeController, la acción sea un método público y el controlador se encuentre dentro de la carpeta “Controllers

Cómo se invoca una vista?

Si escribimos la dirección http://localhost:62078/home/index en el navegador nuevamente recibimos un error, esto es porque el controlador recibe la petición (llama al modelo que en este caso no existe) y retorna una vista, es claro que no hemos definido ninguna vista aún es por eso que falla, vamos a hacer

Creando una vista

La forma sencilla de crear una vista el posicionar el mouse sobre el método Index, presionar botón derecho y seleccionar “add view

image

Vemos que aparece una ventana con opciones y nos sugiere el nombre “Index” para la vista para que coincida con el de la acción (otra convención) destildamos la opción marcada y hacemos click en Add

image

Visual Studio crea la vista y la ubica dentro de la carpeta Views y crea una subcarpeta Home, que coincide con el nombre del controlador (otra convención)

Es por todas estas convenciones que la acción Index del controlador Home pude encontrar la vista correspondiente (si bien podríamos forzar otra)

image

No nos detengamos ahora en la vista, simplemente agreguemos dentro del div el mensaje “Hola MVC” y corramos la aplicación con F5

image

Ahora si funciona, lo que pasó fue que se invocó la acción Index del controlador Home y esta retornó la vista Index, realmente no tuvimos que configurar nada para que todo esto ocurra, mágico.

Por último dejo un video con el mismo ejemplo.

Nos leemos en la próxima.

ASP.NET MVC Series–El patrón MVC

ASP.NET MVC es una implementación del patrón de diseño MVC, el cual separa la aplicación en tres componente, el modelo la vista y el controlador.

Parte a parte

La vista es la representación de los datos, el ejemplo más claro en una aplicación web es el HTML de la pantalla, pero podría ser tranquilamente un JSON que expone una API.

El modelo es todo el dominio de la aplicación, con sus datos, su comportamiento y todo lo necesario para solucionar el problema de negocios, sin necesidad de ninguno de los otros dos componentes.

El controlador simplemente vincula la vista y el modelo, se encarga de recibir las peticiones del usuario (en una aplicación web serían las peticiones HTTP, por ejemplo cuando un usuario coloca una dirección URL o presiona un link, en el ejemplo de la API la invocación de un método de la misma) y retornar el resultado del modelo a la vista, de esto podemos sacar conclusiones importantes:

  • El modelo pude (y debería) funcionar sin la vista ni el controlador.
  • La vista no conoce el modelo, sino que recibe datos del controlador. (no siempre los datos que recibe una vista son objetos del modelo)
  • El modelo no recibe nunca una petición directa de la vista, todo llega a través del controlador.
  • El modelo representa todo el negocio.
  • Nunca debería existir lógica de negocios en el controlador.

Otras características

Gran extensiblidad

Vamos a ver que el framework está pensado de una manera en que todo se puede cambiar, si bien casi siempre los componentes que trae resuelven nuestro problema, para aquellos casos en que no sea así o queramos algo especial podemos hacerlo gracias a su capacidad de extensibilidad.

Convención sobre configuración

En general se busca minimizar la configuración necesaria y muchas del comportamiento se define por convención, por ejemplo: cuando se escribe la URL.

http://sitio.com/usuarios/list

ASP.NET MVC sabe que tiene que instanciar el controlador UsuariosController e invocar el método List, ya que así está definido por convención.

Hay muchas convenciones, las vamos a ir viendo a su tiempo, de todos modos casi siempre es posible modificar este comportamiento por defecto.

Motor de vistas

Una de las tres partes del patrón es la vista, existe una sintaxis especial programar en la vista (además del HTML) en el caso de ASP.NET MVC es posible cambiar el motor que interpreta lo que escribimos en la vista, por defecto tenemos dos, el mismo de Webforms que se llama ASP.NET y uno especialmente pensado para MVC que se llama Razor.

Motor de rutas

La forma de saber qué controlador será invocado cuando el usuario escriba una URL en el navegador es definida por el motor de ruteo, es muy flexible y permite hacer cosas muy interesantes que ayudan a la organización y a SEO

HTMLHelpers

Dentro de la vista no tenemos la posibilidad de usar controles como en Webforms pero podemos utilizar los llamados HTMLHelpers que son algo similar y permiten hacer cosas como generar el HTML de un combo (elemento select de HTML) a partir de un IEnumerable<T>, también podemos crear nuestros propios HTMLHelpers.

Action Filters

Las acciones del usuario llegan al controlador, esto lo sabemos, pero existe otro componente que recibe antes las invocaciones y también puede modificar las respuestas del controlador, se llaman intercepting filters según la definición del patrón MVC, en el caso de ASP.NET MVC se los llama Action Filters y permite hacer cosas como decorar un método del un controlador con una atributo y que esto impida que se llame al método sin tener una cookie dada ya que la llamada es recibida primero por el Action Filter, también podemos manipular la respuesta del controlador y agregarle un META TAG al HTML resultante o cualquier otra cosa que necesitemos.

Model Binder

Este componente se encarga de recibir los datos enviados por el usuario (tanto por GET como por POST, etc.) y generar un objeto a partir de ellos, es decir, si un controlador espera que el usuario le envíe un objeto “Mensaje” el model binder va a intentar crear uno y llenarlo con los datos que se enviaron en el request HTTP, vamos a verlo en más detalle después pero es casi mágico.

Action Result

Cuando un controlador consulta al modelo y éste devuelve un resultado, está listo para mostrarlo al usuario, la respuesta del controlador siempre se basa en un ActionResult, que no es más que un tipo que representa una respuesta HTTP, todos los tipos de resultados (o casi) heredan de ActionResult, el más común es el ViewResult que retorna una representación HTML, pero hay otros como por ejemplo JSONResult que devuelve un JSON, de nuevo, vamos a verlo más en detalle después.

image

El modelo quedaría más o menos así (simplificado y levemente modificado para mejor compresión)

Hay más

Existen otros componentes y muchos detalles que vamos a ir viendo más adelante, de momento con esto podemos empezar a meter mano en el código.

Nos leemos.