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.