Patrón PRG

En esta oportunidad vamos a hablar del patrón PRG (Post-Redirect-Get) el cual es aplicable en el desarrollo web. Tal como el nombre nos sugiere, lo que se logra con esta técnica es que la respuesta a una petición POST sea una re-dirección que nos permita obtener una nueva página por medio de una petición GET.

Antes que nada veamos, utilizando un escenario bastante común en los sitios web, el problema de no aplicar este patrón. Imaginemos un formulario de contacto, en donde el usuario carga información y se envía a un servidor web que la recibe y procesa. Por último informamos al usuario que la operación se realizó con éxito por medio de una nueva página.

En este último punto es donde arriba el problema, ya que si el usuario por esas cosas de la vida se le ocurre actualizar esta última página (F5) aparecerá el siguiente cuadro de dialogo:

Dialogo

Dialogo

El primer problema con esta advertencia es que el usuario posiblemente no entienda el mensaje (en el cual se pregunta si quiere volver a enviar la información del formulario). Por este motivo posiblemente intente reenviar la información cuando ya lo hizo!.

En el caso de hacerlo (botón “Reintentar”) se volverá a realizar la petición POST y nuevamente estaremos procesando la lógica del formulario de contacto (o el formulario que corresponda). Esto, entre otros problemas, nos puede generar registros duplicados, notificaciones duplicadas, etc …  :/

Para prevenir estos casos lo que PRG nos sugiere es lo siguiente:

  1. Recibimos una petición POST con los datos del formulario y ejecutamos la lógica que corresponda.
  2. Respondemos al cliente con una redirección (código de estados HTTP 30x) para que el navegador sepa que debe solicitar otra página (en el ejemplo sería la pantalla que informa que los datos de contacto se enviaron correctamente).
  3. El navegador obtiene esta página mediante una petición GET.

Vista la teoría, vamos a la práctica.

Aclaración: en el siguiente ejemplo voy aplicar el patrón PRG en una aplicación ASP.NET MVC pero es totalmente posible hacerlo en cualquier otra tecnología web (WebForms, PHP…).

Siguiendo el ejemplo de arriba, nuestro método de acción debería quedar  mas o menos así:

Aplicando el patrón PRG

Aplicando el patrón PRG

Muy simple, no?! En un post anterior vimos lo facil que es hacer re-direcciones en ASP.NET MVC. Veamos la respuesta del servidor luego de procesar la petición POST:

Respuesta del servidor

Respuesta del servidor

En primer lugar la respuesta a la petición POST es una re-dirección (HTTP Status 302). En segundo lugar se solicita la página “de agradecimiento” por medio de una petición GET, la cual es devuelta con éxito (HTTP Status 200). Si ahora al usuario se le ocurriera actualizar la página, el navegador le retornará la última petición realizada (petición GET).

Como pueden ver, aplicar esta patrón es muy simple, aún más con ASP.NET MVC (solo basta con modificar la respuesta en nuestro método de acción).

Espero que les sea de utilidad 🙂

Anuncios

REST con ASP.NET Web API

Una de las novedades que más entusiasmaron de la versión beta de ASP.NET MVC 4  son los templates de proyectos ASP.NET Web API. Estos nuevos “tipos” de proyectos nos permiten crear, de una manera muy simple, aplicaciones cuyo propósito es exponer servicios bajo el protocolo HTTP utilizando el estilo de arquitectura REST  (Representational State Transfer).

Antes de continuar con Web API, veamos de que se trata REST.

REST (Representational State Transfer) es un estilo de arquitectura de software para sistemas hipermedias distribuidos tales como la Web. El término fue introducido en la tesis doctoral de Roy Fielding  en el año 2000, quien es uno de los principales autores de la especificación de HTTP.

Los servicios web basados en REST intentan trabajar de manera similar al protocolo HTTP, ya que la interfaz de los mismos será establecida a partir de un conjunto conocido de operaciones estándar (por ejemplo GET, POST, PUT,…). De esta forma, nos abstraernos de los protocolos basados en patrones de intercambio de mensajes, como los utilizados en los servicios web basados en SOA (de seguro estará pensando en el viejo y conocido protocolo de servicios web SOAP).

Es importante que quede claro que REST no es un estándar, sino un estilo de arquitectura que se basa en ciertos estándares, como HTTP, URL, XML, JSON y MIME entre otros.

Volviendo a Web API, algunas de las características  de este framework son:

  • Integración con el mecanismo de routing.
  • Negociación de contenidos (cliente y servidor pueden negocias el formato del intercambio de información).
  • Soporte de Model Bindings, Validations y Actions Filters.
  • Soporte de consultas con OData.
  • Hosting autocontenido (podes publicar nuestra API en IIS o directamente con un ejecutable).

Que mejor forma de explicar todo lo que estuvimos viendo que un ejemplo ;). Para eso vamos a crear un nuevo proyecto ASP.NET MVC 4 al que llamaremos MvcWebApi. Pero ojo, para trabajar Web API debemos seleccionar, dentro de las templates del framework, la nueva plantilla de proyectos “Web Api”:

Template de proyecto Web API

Template de proyecto Web API

Podemos observar que la estructura del proyecto es similar a la de una aplicación web ASP.NET MVCtradicional” (por ejemplo los directorios utilizados por convención del framework siguen existiendo: Models, Views y Controllers como así también los archivos de configuración).

Estructura de un proyecto ASP.NET Web API

Estructura de un proyecto ASP.NET Web API

Analicemos el controlador que Visual Studio nos genera por defecto:

Definición de ValuesController

Definición de ValuesController

El primer “gran cambio” con el cual nos vamos a encontrar es que los controladores ya no heredan de Controller sino que lo hacen de ApiController. Este nuevo tipo de controlador me permite que los métodos  de acción no retornen “vistas” (ActionResult) sino que, por el contrario, devuelvan los datos propiamente dichos (el formato en que viajaran los datos, Json o XML por ejemplo, se negociara entre el cliente y el servidor). Por último, Web API trabaja por convención en lo que respecta a los nombres de los métodos de acción y los verbos HTTP, por lo tanto no es necesario decorar un método con el atributo [HttpPost] para establecer que es un método POST. Lo que tenemos que hacer es simplemente llamar al método de acción Post() (también podemos modificar el nombre del método,  siempre que el mismo termine con el nombre del verbo HTTP, como por ejemplo: ClientPost()).

Detengamonos un momento en este último punto, y retornemos a REST. Un aspecto muy importante de este estilo de arquitectura es que trabaja con recursos. Esto que quiere decir?… que cada servicio que invoquemos, intentará realizar una operación, de un conjunto conocido de operaciones, sobre un recurso o una serie de recursos (cada uno de estos recursos serán identificados mediante URIs como veremos más adelante).

Dicho esto, se podrán imaginar que existe cierta similitud entre los tipos de petición HTTP y las operaciones que podemos realizar sobre los recursos con nuestro servicio. Una aproximación podría ser la siguiente:

HTTP OPERACIÓN ACCIÓN
POST CREATE Crear un nuevo recurso
GET RETRIEVE Obtener la representación de un recurso
PUT UPDATE Actualizar un recurso
DELETE DELETE Eliminar un recurso

Sabiendo esto, vamos a definir las operaciones de nuestro servicio (que por el momento trabajara con el recurso “Cliente”):

RECURSO MÉTODO
Cliente GET Obtener la representación de un cliente
Todos los clientes GET Obtener la representación de una la lista de clientes
Cliente POST Crear un cliente
Cliente PUT Actualizar un cliente
Cliente DELETE Eliminar un cliente

Volvamos al proyecto para definir el modelo que representará al recursoCliente”. Para eso vamos a agregar la clase Cliente dentro de la carpeta “Models” > click derecho sobre Models > Add > Class > Cliente.cs:

Definición del modelo Cliente

Definición del modelo Cliente

Ahora es el momento de trabajar sobre el controlador. Para eso vamos a crear un nuevo controller  llamado ClientesController haciendo click derecho sobre el directorio Controllers > Add > Controller… y una vez que se nos despligue la ventana “Add Controller” seleccionaremos dentro de los templates disponible la opción “Empty API Controller”:

Creando nuestro API Controller

Creando nuestro API Controller

Escribamos las acciones (operaciones) usando como en base lo que definimos en la tabla anterior:

Definición de ClientesController

Definición de ClientesController

Si ejecutamos el proyecto e intentamos recuperar un cliente utilizando nuestro servicio REST, nos encontraremos con que no se encuentra el recurso solicitado :(:

Error al acceder a nuestro servicio

Error al acceder a nuestro servicio

Por qué ocurrió esto? Si inspeccionamos las entradas en el mecanismo de routing de ASP.NET MVC (dentro de Global.asax), nos vamos a encontrar con una “nueva” entrada llamada DefaultApi que será utilizada por nuestra Web API REST. Como observación, van a notar que la misma es registrada por el método MapHttpRoute, a diferencia de los mapeos tradicionales de ASP.NET MVC que son realizados con el método MapRoute.

DefaultApi

DefaultApi

Conclusión, cuando llamemos a las URL de nuestros servicios REST, vamos hacerlo anteponiendo “api” en la URL. Por ejemplo, para recuperar la lista de clientes debemos acceder de la siguiente manera:

http://localhost:49171/Api/Clientes

Pasemos de la teoría a la práctica 🙂

Nuestro servicio REST en marcha!

Nuestro servicio REST en marcha!

En este caso la negociación entre cliente-servidor definió que el contenido devuelto sea en formato XML, sin embargo esto no debe ser necesariamente así (veremos en otros post como definir el formato que más cómodo-útil nos resulte).

Habrán notado también es que no fue necesario especificar el nombré de la acción en la URL (es más, si prestan atención a la regla DefaultApi del enrutador, la acción no es tenida en cuenta). Para saber qué método se debe invocar ante cada petición, lo que hace el framework es trabajar por convención, esto quiere decir que ante cada request, se accederá al método de acción llamado de la misma forma que el verbo HTTP que lo invoca,  teniendo en cuenta también los parámetros enviados.

Veamos como quedaría la tabla teniendo en cuanta las operaciones a realizar sobre nuestro recurso:

RECURSO MÉTODO
Cliente GET http://localhost:49171/Api/Clientes/5
Todos los clientes GET http://localhost:49171/Api/Clientes/5/sebis
Cliente POST http://localhost:49171/Api/Clientes/5
Cliente PUT http://localhost:49171/Api/Clientes
Cliente DELETE http://localhost:49171/Api/Clientes/5/sebis

Otra cosa interesante, es que a diferencia de las aplicaciones web ASP.NET MVC, podemos definir más de un método con el mismo nombre. Por ejemplo podemos tener los métodos Get(), Get(int id) y Get(int id, string name). Para este último caso, simplemente debemos agregar un nuevo mapeo HTTP en el mecanismo de routing:

Definiendo nuestra entrada personalizada

Definiendo nuestra entrada personalizada

El procesador se encargará de acceder al método correspondiente a partir del tipo de petición realizada (GET, POST, PUT…) y de los parámetros enviados.

A esta altura muchos se preguntarán por qué usar servicios basados en REST con Web API si ya disponemos en .NET de otras tecnologías o frameworks para trabajar con web services (ASMX, WSE, WCF,… , WCF Web Api)?  Una respuesta es que ASP.NET Web Api integra de una manera muy sencilla lo mejor de WCF Web API y ASP.NET MVC – excelente noticia quienes desarrollamos con ASP.NET MVC :). Otra buena respuesta a esta pregunta es que REST esta construido sobre los pilares de la web, y esta por demás decir la misma ha sido muy exitosa. Recuerdo un artículo donde decía que “la Web ha sido la única aplicación distribuida que ha conseguido ser escalable al tamaño de Internet” y debido a que REST se basa en ella, podemos decir con seguridad que estamos tomando el camino correcto.

Espero que les haya sido de utilidad, y en próximos post vamos a ver la forma de utilizar los servicios por medio de jQuery y otras características de Web API.

Puedes encontrar este articulo en MSExpertos.

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” retorna el código 302 Found, y seguido se hace una nueva petición a “http://localhost…/Final” 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.