[Videos] Async-Await y ASP.NET Web API

Después del lanzamiento mundial de Visual Studio 2012 varios entusiastas de Latinoamérica nos reunimos de forma virtual en el Microsoft Café TV para celebrar este importante acontecimiento de la mejor forma que sabemos… socializando conocimientos 😀

Tuve la oportunidad de presentar dos demos en aquella ocasión, los dos los he colgado en mi SkyDrive para que les puedan echar un vistazo si lo desean.

El primero fue de C# 5, Async Await y el segundo de Web Api, el contenido de los videos ya se ha tratado en artículos anteriores en este blog, pero es la primera vez que intento algo audiovisual en este sitio… así que a ver cómo me va 😛

Async Await C# 5

ASP.NET Web API

Hasta el próximo post.

Anuncios
[Videos] Async-Await y ASP.NET Web API

[WEB API RC] Negociación de contenido

Por defecto WEB API solo nos permite responder a peticiones en formato json y xml, pero puede que en ocasiones necesitemos responder a una petición que nos solicita por ejemplo… imágenes.

En este post mostrare un par de posibles técnicas a implementar para responder a estas solicitudes.

Dada la clase Persona:

Y dado el controlador PersonaController:

    public class PersonaController : ApiController
    {
        private readonly List<Persona> _personas = Persona.Todos();

        public List<Persona> Get()
        {
            return _personas;
        }
        public HttpResponseMessage Get(int id)
        {
            var persona = _personas.FirstOrDefault(x => x.Id == id);
            if (persona == null)
            {
                var mensaje404 = new HttpResponseMessage(HttpStatusCode.NotFound);
                return mensaje404;
            }
            var personaMensaje = Request.CreateResponse(HttpStatusCode.OK,persona);
            return personaMensaje;
        }
    }

Al hacer una petición al servicio, este nos retornara el json o xml como estamos acostumbrados, incluso si especificamos en la cabecera de la solicitud que “queremos” una imagen:

Pero… ¿Como solucionamos esto?

  • Creando un controlador de imágenes:

La primera solución que pasa por la cabeza es simplemente crear un nuevo controlador encargado de retornarnos la fotografía de la persona dado su Id, sería algo como lo siguiente:

    public class FotoPersonaController : ApiController
    {
        private readonly List<Persona> _personas = Persona.Todos();

        public HttpResponseMessage Get(int id)
        {
            var persona = _personas.FirstOrDefault(p => p.Id == id);
            var message = new HttpResponseMessage();
            message.Content = new StreamContent(new MemoryStream(persona.Foto));
            message.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpg");
            return message;
        }
    }

Y a simple vista sí que funciona:

Pero aquí no hay negociación de contenido, siempre vamos a retornar una imagen a esta petición, sin importar que se quiera en la respuesta siempre le vamos a retornar una imagen. Además de esto, debemos escribir un método para cada una de las entidades que trabajen con este tipo de contenido… y eso ya es trivial.

  • Media Type Formatters al rescate.

Para crear un media formatter solo debemos implementar de una de estas clases: MediaTypeFormatter o BufferedMediaTypeFormatter, la diferencia es que la ultima implementa de MediaTypeFormatter y nos abstrae de un par de métodos asíncronos.

Creamos entonces una clase llamada JpegFormatter donde heredamos de la clase BufferedMediaTypeFormatter y seguimos los siguientes pasos:

  1. Definimos que tipos de contenido vamos a trabajar con este (en su constructor).
            public JpegFormatter()
            {
                SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpeg"));
            }
  2. Sobrescribimos los métodos booleanos CanReadType y CanWriteType, el primero indica que tipos podemos deserializar (en este ejemplo no aplica, así que siempre retorna false) y el segundo nos indica que tipos podemos serializar.
            public override bool CanReadType(Type type)
            {
                return false;
            }
    
            public override bool CanWriteType(Type type)
            {
                return (type == typeof (Persona));
            }
  3. Finalmente sobrescribimos el método WriteToStream()para que dada la solicitud con dicho encabezado nos retorne lo que necesitamos, una imagen.
            public override void WriteToStream(Type type, object value, System.IO.Stream stream,
                                               HttpContentHeaders contentHeaders)
            {
                var persona = value as Persona;
                if (persona != null)
                {
                    stream.Write(persona.Foto, 0, persona.Foto.Length);
                    stream.Flush();
                }
            }

El codigo completo de nuestra clase es el siguiente:

using System;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using MvcApplication2.Models;

namespace MvcApplication.MediaTypesFotmatters
{
    public class JpegFormatter : BufferedMediaTypeFormatter
    {
        public JpegFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpeg"));
        }

        public override bool CanReadType(Type type)
        {
            return false;
        }

        public override bool CanWriteType(Type type)
        {
            return (type == typeof (Persona));
        }

        public override void WriteToStream(Type type, object value, System.IO.Stream stream,
                                           HttpContentHeaders contentHeaders)
        {
            var persona = value as Persona;
            if (persona != null)
            {
                stream.Write(persona.Foto, 0, persona.Foto.Length);
                stream.Flush();
            }
        }
    }
}

Como paso final, registramos nuestro Type Formatter, si estamos usamos hosting asp.net lo registramos en el global.asax en el metodo Application_Start, así:

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            //REGISTRAR TYPE FORMATTER 
            GlobalConfiguration.Configuration.Formatters.Add(new JpegFormatter());
        }

Con esto ya no necesitamos ese controlador adicional pues podemos responder a este tipo de contenido desde nuestro PersonaController.

La solicitud aceptando JSON:

Solicitud aceptando Image/jpeg:

Como vemos podemos extender de una forma muy fácil la negociación de contenido de WEB API haciendo uso de todo el poder de http.

Hasta el próximo post.

[WEB API RC] Negociación de contenido

[WEB API RC] Migrando de WEB API Beta a WEB API RC

Con la llegada de Visual Studio 2012 RC a mis manos, y mi gran interés por lo que ofrece MVC y WEB API, intente continuar con un proyecto que llevaba y al tratar de abrirlo (ejecutarlo) oh sorpresa, me he encontrado con el siguiente error: Method not found: ‘Void System.Net.Http.Headers.Http Headers.Add Without Validation(System.String, System.Collections.Generic.IEnumerable`1<System.String>)’. Así que luego de leer un poco la documentación me di cuenta que debía actualizar los ensamblados desde Nuget, este desinstala los antiguos y pone los nuevos. El paquete oficial en nuget

Adiós a los HttpResponseMessage Genéricos

Una vez hecho esto y al compilar intentar compilar una nueva sorpresa L, YA NO SE PERMITEN los HttpResponseMessage GENERICOS, que es lo que había explicado en el post anterior. ¿Qué quiere decir esto? Que debemos construir la respuesta a partir de la petición. Ya hablaremos de esto en próximas entradas, por lo pronto todo lo que tenía con HttpResponseMessage<Tipo> debe estar ahora como HttpResponseMessage y se construye la respuesta con:

var respuesta = Request.CreateResponse(HttpStatusCode.OK, objeto);

¿Y en Visual Studio 2010 y Windows 7?

Como aun sigo trabajando varios proyectos con la versión anterior de Visual Studio pues sería un desperdicio de tiempo no poder trabajar MVC 4 RC con esta versión del IDE. La solución muy similar a la primera, solo que claro, es necesario instalar esta versión del Framework.

[WEB API RC] Migrando de WEB API Beta a WEB API RC

[WEB API]Usando el HttpResponseMessage

Una de las muchas ventajas que nos ofrece el WEB Api es el poder trabajar con los cuerpos de las respuestas http de una manera muy natural, esto lo logramos haciendo uso de la clase HttpResponseMessage que nos ofrece una completa suite de elementos para lograr respuestas claras y precisas.

Pero, ¿qué quiere decir es esto?… pues veámoslo en un ejemplo.

Teniendo una clase Persona como la siguiente:

    public class Persona
    {
        public int Id { getset; }
        public string Nombre { getset; }
    }

Y en nuestro PersonaController tenemos el siguiente código:

    public class PersonasController : ApiController
    {
        private static readonly List<Persona> Personas = CrearPersonas();

        private static List<Persona> CrearPersonas()
        {
            var personas = new List<Persona>();
            personas.Add(new Persona { Id = 1, Nombre = "Nicolas" });
            personas.Add(new Persona { Id = 2, Nombre = "Santiago" });
            return personas;
        }

        public List<Persona> Get()
        {
            return Personas;
        }

        public Persona Get(int id)
        {
            var persona = Personas.FirstOrDefault(x => x.Id == id);
            return persona;
        }
    }

Al consumir nuestra Api con la siguiente peticion dese un cualquier cliente obtendríamos las siguientes respuestas:

Pero, ¿qué pasa si preguntamos por un recurso que no existe? Se verá como lo siguiente:

Fijémonos que nuestra api nos está retornando un 200 (OK) pese a que claramente ese recurso no existe!! ¿Pero entonces como solucionamos este problema?

HttpResponseMessage Al rescate:

El uso de HttpResponseMessage es bastante sencillo y nos va a salvar de este lio, simplemente redefinimos nuestro método de la siguiente manera:

        public HttpResponseMessage<Persona> Get(int id)
        {
            var persona = Personas.FirstOrDefault(x => x.Id == id);
            if (persona == null)
            {
                var mensaje404 = new HttpResponseMessage<Persona>(HttpStatusCode.NotFound);
                return mensaje404;
            }
            var personaMensaje = new HttpResponseMessage<Persona>(persona);
            return personaMensaje;
        }

Si consumimos ahora nuestra Api y preguntamos por un recurso que no existe, veremos algo como lo siguiente:

Como vemos su uso es bastante sencillo, simplemente hacemos uso de la clase genérica definiéndola del tipo de nuestra clase, y empleando dos sobrecargas del constructor, una con el resultado en el Content-type que nos piden (json-xml) y la otra haciendo uso del enumerador HttpStatusCode
para retornar el código adecuado.

Un ejemplo adicional es con el verbo Post usado para agregar un nuevo recurso y obtener un 201, además podemos informar de la ubicación del recurso una vez se ha agregado. Podemos definir entonces este método en nuestro controlador de la siguiente forma:

        public HttpResponseMessage<Persona> Post(Persona nuevaPersona)
        {
            nuevaPersona.Id = Personas.Count + 1;
            Personas.Add(nuevaPersona);
            var personaMensaje = new HttpResponseMessage<Persona>(nuevaPersona, HttpStatusCode.Created);
            personaMensaje.Headers.Location = new Uri(Request.RequestUri,
                                                      string.Format("api/personas/{0}", nuevaPersona.Id));
            return personaMensaje;
        }

Y al consumirlo desde un cliente con la siguiente petición:

Tendremos una respuesta como la siguiente:

Espero les sea de utilidad.

Hasta el próximo post.

[WEB API]Usando el HttpResponseMessage

Servicios REST en WCF – Mucho trabajo mismo resultado

Desde que surgió WCF siempre se ha estado en constante evolución hacia lograr hacer servicios web totalmente sobre HTTP, intentando dar soporte por supuesto a los servicios RestFul y centrando su atención en todos los poderes del protocolo http para empezar a verlo como lo que es, un protocolo de aplicación.

Mucha gente se esforzó por darle el rumbo correcto a este producto, varios APIs se vieron ir y venir en CodePlex, siempre persiguiendo el mismo objetivo. Finalmente en la versión 3.5 y 4 de WCF se llego a decir que era posible la construcción de servicios RESTFul.

Personalmente nunca me han gustado los servicios WCF y no puedo decir que sea un experto en la materia, pero el hecho de tener que trabajar con tantos y tantos tipos de configuraciones en archivos .config donde no te saldrá un error de compilación si algo está mal [Siempre será una linda pantalla de error con un mensaje que nunca entiendes, y no lo niegues que es así :P], donde testear estos servicios requiere de un cliente o aplicación [WCF Test Client por ejemplo] donde por cada forma de consumo se debe teclear un nuevo EndPoint, tener que decorar con tantos atributos los métodos para tener algún tipo de funcionalidad personalizada y un gran etc. que hace que no me termine de gustar esta tecnología.

Entonces sí! Pensar en construir servicios Rest con WCF “puede llegar a ser” posible, si estás dispuesto a trabajar con todo ese gran “cascaron” que envuelve a WCF. Para la muestra un par de entradas que muestran un paso a paso de cómo construir un servicio rest haciendo uso de los vervos de http y la “negociación” de contenido. Vi este en CodeProjet y este ultimo a un compañero de BDotNet. En ellos se plantea una buena solución al problema, pero para mí sigue sin ser Rest, ¿por qué? A simple vista no se está haciendo uso de una negociación de contenido, simplemente se definen dos métodos distintos decorados de forma diferente haciendo uso del atributo WebInvoke y dejando de lado el uso de los encabezados de http. Además de cómo se muestran en los artículos se hace uso de “todo” el poder de los Bindings y Endpoints y del conocido webHttpBinding.

Esta solución no me convenció y encontré este artículo muy detallado en MSDN, la verdad no lo termine e implementar y es que es muy complejo y ¡me desgasta mucho!

Una visión más clara, ASP.NET Web API

Con la llegada de MVC 4 salió WEB API, este framework SI se pensó para la construcción de servicios sobre http, a diferencia de todas las modificaciones de WCF que desde un inicio se pensó para soportar SOAP y nada más que SOAP, la verdad no sé si se reescribió de cero [creo que no], pero si se pensó bien, muy bien como debía trabajar.

A diferencia de los WCF con WEB API no debemos preocuparnos por archivos de configuración de grandes magnitudes, ni de decorar con una gran cantidad de atributos a nuestros métodos para que trabajen con los verbos de http.

Basta con crear una nueva aplicación de ASP.NET MVC 4, y seleccionar la opción Web Api. Uno de los primeros beneficios es el método MapHttpRoute, que nos permitirá hacer uso de los verbos de http sin tener que esforzarnos como lo haríamos con un método WCF que queremos responda a un Get o a un Post.

Si consumimos este servicio, desde un navegador y vemos el cuerpo de la respuesta veremos que por defecto en IE9 nos regresa un JSON, para mí, esto ya es una ventaja 😀 ya no tenemos esos feos envolve que teníamos con SOAP. Una muestra de lo anterior:

Y en este caso nosotros tenemos una completa negociación de contenido haciendo uso del encabezado de la solicitud y sin escribir una línea de más. Así:

Como vemos WEB API incorpora todos estos beneficios de fabrica, y no tenemos que preocuparnos por construir enmarañados WCF para “simular” Y NO NIEGO QUE SE PUEDA LOGRAR, que yo no lo he logrado hacer es otra cosa, pero por ahí he oído de gente muy buena en esto de los servicios WEB que si es posible… de lo que si estoy seguro es que les toca escribir mas líneas que a mí 😛

Espero les sea de utilidad.

Hasta el próximo post.

Servicios REST en WCF – Mucho trabajo mismo resultado