[ASP.NET Web API] Autenticación basada en tokens y líos con el CORS

No era la primera vez que implementaba este tipo de autenticación en un proyecto de ASP.NET Web Api + ASP.NET MVC + OWIN y ya sabía (o al menos creo saber) los retos de trabajar con estos pipelines, digo, líneas como config.SuppressDefaultHostAuthentication(); en el  WebApiConfig hacen su magia, conocí la clase OAuthAuthorizationServerProvider y en su momento dejé en mis favoritos entradas como esta como fuente de consulta. Con el tema de CORS creí que todo estaba resuelto con el uso del atributo EnableCors que hizo esto más sencillo.

La semana pasada este requerimiento surgió de nuevo pero con un componente adicional: El token es solicitado en un cliente desde otro dominio. De entrada parece que nada cambia, pero si que lo hace, o al menos si hay que agregar unas cuantas líneas. Sabía que en mis favoritos aún estaban los enlaces a las fuentes que había usado como referencia en implementaciones anteriores, así que volví a consultar una serie de tutoriales muy, muy completos de este blog. Y por primera vez me percaté que existen dos “enable cors”! (o algo así) uno a nivel del pipeline de OWIN y el que siempre uso en Web API. El que siempre uso, el de Web API, viene en el paquete Microsoft.AspNet.WebApi.Cors y el que no conocía, el de Katana, viene en el paquete Microsoft.Owin.Cors.

¿Qué diferencia tienen WebApi.Cors y Owin.Cors?

No encontré nada en la documentación oficial, pero viendo el nombre, entendiendo algo de OWIN y habiendo usado Katana, se puede suponer que el primero es solo para el Framework Web API y lo que hay en el, es decir, los ApiControllers. El segundo es un middleware que agrega soporte para el resto del pipeline, como el middleware para generar los tokens! Igual apliqué un poco de GOD (google oriented development) y encontré una explicación similar en Stack Overflow.

¿Y cómo se usan los dos?

Lo primero que hice, desde el desconocimiento, fue agregar en el Startup la línea app.UseCors(CorsOptions.AllowAll); y en el momento de probar surgió el primer error, error que rompe la parte que ya funcionaba (mensaje en la consola de Chrome):
Control-Allow-Origin' header contains multiple values 'https://foo.com, https://foo.com', but only one is allowed. Origin 'https://foo.com' is therefore not allowed access. ¡Y tiene todo el sentido! pues en dos puntos del pipeline estamos agregando estas cabeceras.

Una solución puede ser quitar la configuración del CORS en el WebAPIConfig, es decir, la línea config.EnableCors(); y dejar que el OWIN se configure global con con Katana. ¡Pero no me gusta! no me gusta por el AllowAll (least privilage), aunque parece claro que se puede cambiar (más sobre esto a continuación), y porque se supone que la configuración del CORS de Web API es para el Framework! digo, por algo existe, no?

Como el único  lugar donde necesito el CORS es en el endpoint que genera el token, pensé que era más fácil y mejor quitar el UseCors() del Startup y agregar las cabeceras directamente en el response, sabía que no podía ser el primero que hacía esto y así fue, la segunda solución la encontré en Stack Overflow y pasa por sobrescribir el método MatchEndpoint del OAuthAuthorizationServerProvider, yo terminé con una implementación como la siguiente:

        private static void SetOriginHeaders(IOwinContext context)
        {
            if (!context.Response.Headers.Keys.Contains("Access-Control-Allow-Origin"))
                context.Response.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Origin", "https://localhost:44369");
            if (!context.Response.Headers.Keys.Contains("Access-Control-Allow-Headers"))
                context.Response.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Headers", "Accept", "Content-Type", "Authorization", "Cache-Control", "Pragma", "Origin");
            if (!context.Response.Headers.Keys.Contains("Access-Control-Allow-Methods"))
                context.Response.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Methods", "GET", "POST", "PUT", "DELETE", "OPTIONS");
        }

        public override Task MatchEndpoint(OAuthMatchEndpointContext context)
        {
            if (context.IsTokenEndpoint &&
                (context.Request.Method.Equals("OPTIONS", StringComparison.InvariantCultureIgnoreCase)
                || context.Request.Method.Equals("POST", StringComparison.InvariantCultureIgnoreCase)))
            {
                SetOriginHeaders(context.OwinContext);
                context.MatchesTokenEndpoint();
                //context.RequestCompleted();
                return Task.CompletedTask;
            }

            return base.MatchEndpoint(context);
        }

        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {		
            //Se valida el usuario...

            SetOriginHeaders(context.OwinContext);
        }

Con el código anterior funciona sin problemas, pero nuevamente pensé: ¡Esto debe poderse hacer desde el middleware!

Configurar el Owin.Cors

Después de dar muchas vueltas llegué a esta solución, que ahora me parece muy sencilla y obvia. Se puede crear una instancia de CorsOptions y usar un PoliciResolver, que no es más que una función que permite tener acceso a la información del request (IOwinRequest) y retornar un objeto que encapsula los Headers HTTP en cómodas propiedades. El código del Startup se así (el orden de los middlewares SI altera el resultado):

    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCors(new CorsOptions
            {
                PolicyProvider = new CorsPolicyProvider
                {
                    PolicyResolver = PolicyResolver
                }
            });
            ConfigureAuth(app);
        }

        private static Task<CorsPolicy> PolicyResolver(IOwinRequest request)
        {
            if (request.Path.Value == "/api/token")
            {
                //Estos valores pueden ser recuperados de un archivo de configuracion
                var corsPolicy = new CorsPolicy
                {
                    Headers = { "Accept", "Content-Type", "Authorization", "Cache-Control", "Pragma", "Origin" },
                    Methods = { "POST", "OPTIONS" },
                    Origins = { "https://localhost:44369" }
                };
                return Task.FromResult(corsPolicy);
            }
            return Task.FromResult<CorsPolicy>(null);
        }
    }

Conclusiones

  • Existe un middleware de Katana que habilita CORS en todo el pipeline de OWIN, Microsoft.Owin.Cors
  • Owin.Cors y WebApi.Cors pueden existir en el mismo proyecto
  • El OAuthTokenProvider no hace parte de WebApi, por eso se necesita el Owin.Cors

Referencias y enlaces de interés

Espero les sea de utilidad.

Hasta el próximo post.

Anuncios
[ASP.NET Web API] Autenticación basada en tokens y líos con el CORS

[ASP.NET] Simplificando los controladores

Hace unos días Juanma publicó un tweet con un articulo que me resultó interesante. En este se describe como “mejorar” el código de las aplicaciones web escritas en lenguajes orientados a objetos y sobre frameworks MVC usando “técnicas” un poco más cercanas a un paradigma funcional, y describe, además, lo difícil de adaptar el mundo stateless de la programación web (server side) a lo que propone un diseño orientado al dominio.

Me pareció interesante, además, porque en las últimas semanas he estado replanteándo como hago yo este tipo de desarrollos… en un nuevo proyecto. Siempre que puedo trato de cambiar en algo el como escribo y organizo mi código, casi siempre influenciado por lecturas (libros, blogs, twitter), conferencias, y demás, y me han llevado por escribir aplicaciones como lo planteaba el libro negro de la Arquitectura Orientada al Dominio con Tecnologías Microsoft, si, con todo y los cien ensamblados. He escrito aplicaciones con todo el código en los controladores o, en el mejor de los casos, llamando a clases que “encapsulan” estos procedimientos, pero igual, todo muy acoplado. He escrito aplicaciones con modelos de dominio anémicos y un montón de servicios que inyecto en los controladores, con y sin repositorios, etc. Pero ahora quise probar algo que vi en el blog de Bogard, quien propone usar el patrón mediador para escribir aplicaciones que usen un modelo CQS. Incluso creó una librería para resolver los Handlers de las consultas y comandos, con una que otra cosa de más, llamada MediatR, que se integra bien con y sin contenedores de dependencias.

En resumen, lo que se busca con CQS es separar las consultas de las escrituras, para simplificarlo podríamos verlo como los GET y los POST en nuestras aplicaciones, y con la aplicación del patrón mediador es tener una única dependencia en los controladores (el mediador) y que sea este ultimo quien resuelva que hadler hace que.

Para ilustrar mejor esta definición veamos un ejemplo:

    public interface ICommand<out TResult> { }

    public interface ICommandHandler<in TCommand, TResult> where TCommand : ICommand<TResult>
    {
        Task<TResult> HandleAsync(TCommand command);
    }

    public class AddItemCommand : ICommand<AddedItemViewModel>
    {
        public AddItemCommand(Guid itemId, Guid storeId)
        {
            ItemId = itemId;
            StoreId = storeId;
        }

        public Guid ItemId { get; private set; }
        public Guid StoreId { get; private set; }
    }

    public class AddItemHandler : ICommandHandler<AddItemCommand, AddedItemViewModel>
    {
        private readonly IApplicationDbContext _context;

        public AddItemHandler(IApplicationDbContext context)
        {
            _context = context;
        }

        public async Task<AddedItemViewModel> HandleAsync(AddItemCommand command)
        {
            var itemId = command.ItemId;
            var storeId = command.StoreId;
            var store = await _context.Stores.FirstAsync(s => s.Id == strtoreId);

            //Todas las reglas del dominio al dominio.
            var item = store.ShipItem(itemId);
            //...
            
            _context.SaveChanges();
            var resp = new AddedItemViewModel
            {
                Location = item.Location,
                //...
            };
            return resp;
        }
    }

Podemos detenernos aquí y recibir en el constructor del controlador cuantos handlers deseemos y usarlos en los métodos de acción que los requieran, o, si queremos ir más allá, podemos crear un objeto que resuelva y llame al handler adecuado a partir del comando, para esto crearemos un mediador o usamos MediatR. De hecho podemos detenernos en el Command y “encapsular” allí, acoplado o no, toda la funcionalidad de dicho comando y ser felices, todo depende de nuestra aplicación, sus requerimientos, y la facilidad para testear el código que deseemos.

Con esto habré transcrito aquí lo que entendí de la serie de artículos de Bogard, así que iré un poco más allá y voy a discutir algo que vi hace un tiempo en un video del buen Greg Young.

Greg Young afirma que la magia, en el código, es mala. Expone el caso de los dynamic proxy y de cómo nos explicarían eso a los desarrolladores junior, o cómo entendemos la magia de los frameworks que usan en un proyecto cuando recibimos los fuentes. Habla de los contenedores de dependencias y su magia, nos habla de buscar una interfaz común y cambiar nuestro problema con el fin de evitar la magia. Muestra una implementación de comandos y consultas, en lago similar a la que ya vimos… en fin, es un buen video y estoy seguro que algo aprenderás como lo hice yo.

Revisando la implementación anterior

Viendo el código de nuestro command handler vemos que la interfaz común nos indica que habrá un parámetro de entrada y uno de salida con un única acción: procesar el comando. Todo lo que necesitemos para llevar a cabo esta acción lo pasaremos como parámetro al constructor, y el único estado que contendrá esta clase serán dichas dependencias. Si no hay más estado que dichas dependencias y la interfaz común solo expone una acción con una entrada y una salida… ¿no luce esto como una función?

Ya Mark Seemann había escrito sobre el tema, y en español, Juanma también nos compartió sus opiniones.

En este caso me inclino a pensar un poco más funcional, es decir, darle todo lo necesario a la función para que haga su trabajo y no tener un estado que no aporta mucho en el objeto. Así las cosas podríamos olvidarnos de las interfaces y usar solo funciones:

    public class AddItemCommandHandler
    {
        public static Func<AddItemCommand, IApplicationDbContext, IAzure, Task<AddedItemViewModel>> Handle = HandleBody;

        private static Task<AddedItemViewModel> HandleBody(AddItemCommand command, IApplicationDbContext context, IAzure azure)
        {
            throw new NotImplementedException();
        }
    }
    public class RemoveItemCommandHandler
    {
        public static Func<AddItemCommand, IApplicationDbContext, Task<RemovedItemViewModel>> Handle = HandleBody;

        private static Task<RemovedItemViewModel> HandleBody(AddItemCommand command, IApplicationDbContext context)
        {
            throw new NotImplementedException();
        }
    }

El problema de ahora pasar como parámetro todas las dependencias a nuestros métodos es que hemos roto la interfaz común que habíamos logrado. Así que, ¿cómo lo conseguimos?

Aplicación parcial de funciones

La aplicación parcial de funciones es algo muy común en la programación funcional, podemos verla como la función resultante de llamar a una función sin todos sus argumentos. La manera más fácil de entenderlo es mediante un ejemplo:

    Func<int, int, int> Multi = (a, b) => a * b;
    Func<int, int> DosPor = a => Multi(a, 2);
    DosPor(3); // 6 😛

Haciendo uso de la aplicación parcial de funciones podemos pasar los parámetros extra (repositorios, contexto, loggers, helpers) para trabajar con una función que reciba un solo parámetro, el command, y recuperar así nuestra interfaz común.

Ok, ¿y cómo se resuelven los Handlers?

Ya no tenemos interfaces para inyectar y resolver desde el mediador. Pero podemos usar un contenedor de Comandos (un diccionario) para usarlos desde el controlador. ¿No es este un acoplamiento con dicho contenedor que hará más difícil testear mis controladores? te preguntarás, sí, si deseas hacerle test unitarios al controlador lo “mejor” sería sacarle una interfaz a esta dependencia (pero no me gusta hacerle unit testing a los controladores…)

¿Cómo queda este contenedor de comandos?

    public class ApplicationCommands
    {
        private static readonly Dictionary<Type, Func<ICommand, Task<IResult>>> Handlers = new Dictionary<Type, Func<ICommand, Task<IResult>>>();

        public static void Register<T>(Func<T, Task<IResult>> handler) where T : ICommand
        {
            if (!Handlers.ContainsKey(typeof(T))) Handlers.Add(typeof(T), command => handler((T)command));
        }

        public static async Task<IResult> HandleAsync(ICommand command)
        {
            return await Handlers[command.GetType()](command);
        }
    }

La interfaz ICommand la tenemos desde la primera implementación, pero ahora no será genérica y nos servirá de marker interface. Y la interfaz IResult tendrá dos métodos que uso para eso de mostrar mensajes de error y ayuda. La definición de las interfaces es:

    public interface IResult
    {
        void AddHttpInfo(HttpViewModelInfo info);
        IList<HttpViewModelInfo> GetHttpInfo();
    }

    public interface ICommand { }

Ya podremos cargar nuestro contenedor de comandos haciendo algo como:

            ApplicationCommands.Register<AddItemCommand>(
                async command => await AddItemHandler.Handle(command, new ApplicationDbContext(), new AzureManager()));

¿Y cómo se maneja el ciclo de vida de los objetos?

Al manejar un diccionario estático con los comandos no se puede registrar una instancia con ciclo de vida por request, lo que estaría por request es el comando, pero el dispose de, por ejemplo, el DbContext queda fuera de nuestro control. Por lo que no sé si convendría más usar un contenedor por request, es decir, reconstruirlo para cada controlador o actualizar la entrada en el diccionario (agradezco sugerencias en los comentarios) :S

Para verlo más claro vamos a cargar los applications commands para el Web Api:

    public class WebApiCompRoot : IHttpControllerActivator
    {
        public IHttpController Create(
            HttpRequestMessage request,
            HttpControllerDescriptor controllerDescriptor,
            Type controllerType)
        {
            if (controllerType == typeof(ShippingController))
            {
                var context = new ApplicationDbContext();
                var azureContext = new AzureContext();
                ApplicationCommands.Register<AddItemCommand>(async command => await AddItemHandler.Handle(command, context, azureContext));
                request.RegisterForDispose(context); //Ciclo de vida por request
                return new ShippingController();
            }
            return (IHttpController) Activator.CreateInstance(controllerType);
        }
    }

Si ejecutamos así el primer request funcionará perfecto. Pero para los siguientes no se creará un nuevo context y recibiremos la excepción indicando que ya se ha hecho Dispose. Podemos entonces reescribir la entrada en el diccionario en el ApplicationCommands o crear un contenedor por request y pasarlo a cada controlador.

Notas

En esta entrada solo mostré el uso de comando y no de consultas, pero la idea es la misma.

“¿No deben los comandos ser de tipo void (Action)?” eso dicen, pero noté que siempre quiero informar algo y si no es así, siempre puedes crear un IResult Unit, como el de F#

Ese código se ve horrible, ¿por qué no usas mejor un lenguaje funcional? Si, ya me lo han dicho y espero estar hablando sobre el tema pronto.

Espero les sea de utilidad, y si tienen feedback, bienvenido!

Hasta el próximo post.

[ASP.NET] Simplificando los controladores

OWIN, Katana y open source projects

De seguro que al sol de hoy ya has oído hablar sobre la especificación OWIN — Open Web Server Interface for .NET y sobre la implementación de esta especificación por parte de Microsoft en el proyecto Katana, ya se ha escrito bastante sobre el tema y para los hispanohablantes ya el buen Eduard Tomas hizo una reseña de como ha venido evolucionando ASP.NET y su visión de una futura evolución no monolítica del Framework.

En pro de la flexibilidad y la portabilidad

En la actualidad en .net tenemos varios Frameworks para desarrollo web, unos de Microsoft (WebForms, MVC y Web API) y unas opciones open source como FubuMVC, OpenRasta, NancyFX, entre otros. Con estos Frameworks desarrollamos nuestras aplicaciones, y para que puedan “correr” empleamos hosts y servidores Web, como el poderoso IIS, el IIS Express o algún tipo de Self Hosting empleando un HttpListener/TCP Listener/Web Socket. Y aquí es donde surge la principal meta de la especificación OWIN, desacoplar servidor y aplicación.

OWIN describe como los componentes de un Http pipeline deben comunicarse, para esto emplea dos componentes principales, el primero es el entorno, este es un diccionario de la forma IDictionary que llenará el servidor compatible con OWIN con los datos de entorno, con las claves que se detallan en la especificación. Y la responsabilidad de actualizar este diccionario con nuevos valores y de escribir el response body será entonces del Framework o la aplicación.

El segundo componente es el Application Delegate, esta será la abstracción principal entre todos los componentes de una aplicación, tomando el diccionario de entorno y definiendo una tarea a realizar, su firma es de la forma Func, Task>. Como se puede notar, el que la tarea a realizar sea una Task ya nos hace ver una prometedora asincronia :D.

Con estas simples abstracciones podemos escribir componentes que cumplan la especificación y “encadenarlos”  con otros componentes, reemplazar nuestro web server por uno mas ligero o robusto, emplear el host que mejor se ajuste, tener componentes mas granulares para la autenticación p. ej. y así tener lo que necesito y como lo necesito, sin ninguna dependencia extra, dándonos no solo las ventajas de poder reemplazar los componentes mas fácilmente, sino una posible mejora en el performance, pues como digo, solo usas los componentes que necesitas. Además, como estos componentes no dependen el uno del otro podríamos fácilmente encontrar un host para Mono y movernos hacia allá sin tener que reemplazar/cambiar nada/ningún componente.

A diferencia de un todo, esta modularidad nos brinda la ventaja de poder evolucionar constantemente cualquiera de nuestros componente sin tener que realizar, me atrevería a decir que, ningún trabajo en los demás.

Katana

La especificación de OWIN es dirigida por la comunidad de desarrolladores de .net, un esfuerzo conjunto de la comunidad de usuarios para presentar una nueva forma de hacer las cosas. La implementación de esta especificación por parte de Microsoft lleva el nombre de KATANA, una serie de componentes de OWIN, el proyecto es open source,  e incluye componentes de infraestructura como servidores y hosts, componentes para autenticación, Frameworks como SignalR y Web API.

El como implementar Katana ya es un tema muy documentado, así que no profundizare en este aspecto.

Open source projects

Cuando leía esta fascinante iniciativa lo primero que se me vino a la mente fue… escribiré mi propio servidor con juegos de azar y mujerzuelas, es muy sencillo 😛

        static void Main(string[] args)
        {
            const string msg = "Hola, yo soy tu server";
            const int port = 1450;
            var server = new TcpListener(IPAddress.Any, port);
            server.Start();
            Console.WriteLine("Servidor en linea...");
            while (true)
            {
                var socket = server.AcceptSocket();
                byte[] responseMessage = Encoding.ASCII.GetBytes(msg.ToCharArray(), 0, msg.Length);
                socket.Send(responseMessage);
                socket.Disconnect(false);
            }
        }

image

Pero ok, mejor olviden mi propia implementación y los juegos de azar, mejor olvídenlo todo y veamos verdaderas implementaciones hechas por la comunidad.

NOWIN

El primer proyecto de código abierto que clone fue NOWIN, según el autor, su implementación es de dos a tres veces mas rápida que HttpListener (paff sencillo) y Node JS (esto son palaras mayores :P). Implementar una aplicación con Nowin es bastante sencillo (En el código fuente  esta el mismo ejemplo):

    class Program
    {
        static void Main(string[] args)
        {
            var builder = ServerBuilder.New().SetPort(1450).SetOwinApp(Sample.App);
            using (builder.Start())
            {
                Console.WriteLine("Listening on port 1450. Enter to exit.");
                Console.ReadLine();
            }
        }
    }
    public class Sample
    {
        public static Task App(IDictionary arg)
        {
            var req = new Owin.Types.OwinRequest(arg);
            var resp = new Owin.Types.OwinResponse(req);
            if (req.Path == "/")
            {
                resp.StatusCode = 200;
                resp.AddHeader("Content-Type", "text/plain");
                resp.Write("Hello World!");
                return Task.Delay(0);
            }
            var p = Path.Combine(@"c:\Aplicacion", req.Path.Substring(1));
            if (File.Exists(p))
            {
                resp.StatusCode = 200;
                resp.AddHeader("Content-Type", "text/html");
                return resp.WriteAsync(File.ReadAllBytes(p));
            }
            resp.StatusCode = 500;
            return Task.Delay(0);
        }
    }

Lo que necesité:

image

Como luce:

image

Empleando Katana – Microsoft Hosting

En el ejemplo anterior con nowin no había una clara distinción del host y el server, pues cumplía el mismo objetivo. Veamos ahora una implementación con un componente de Katana, Microsoft.Owin.Hostin, es decir, no estamos haciendo uso de todos los componentes de katana, solo de lo que necesito! porque yo ya tengo mi server!… no es genial?! empleemos además un Web Api como framework, simplemente buscamos el Web Api OWIN en nuget y lo instalamos. Los paquetes en este ejemplo:

image

El código:

    class Program
    {
        static void Main()
        {

            var options = new StartOptions();
            options.Port = 1450;
            options.ServerFactory = "NowinWebServer";
            using (WebApp.Start(options))
            {
                Console.Write("Server en linea, puerto : {0}", options.Port);
                Console.ReadKey();
            }
        }
    }
    public class HolaMundoController : ApiController
    {
        public string Get()
        {
            return "Hola!!";
        }
    }
    public class Startup
    {
        public void Configuration(IAppBuilder builder)
        {
            var config = new HttpConfiguration();
            config.Routes.MapHttpRoute("Default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
            builder.UseWebApi(config);
        }
    }

El resultado:

image

Y la mejor parte de todas es que no hay espacio a resultados mágicos inesperados! te puedes descargar los fuentes de Katana y ver que pasa tras la cortina.

Como Nowin, he visto una implementación de  Mark Rendle llamada Flux un server para .net y mono que no usa HttpListener o Fleck una implementación de Web Socket server. Todas disponibles para jugar su uso.

Hay además implementaciones de Frameworks como el buen NancyFX y SignalR, tenemos componentes independientes de autenticación en el mismo proyecto Katana, que si al ver su código no te gustan, bien puedes mejorarlas y contribuir al proyecto o buscarte el que mejor se acomode a tus necesidades entre varias posibles opciones de la comunidad.

Opinión

Como yo lo veo con esto se marca un nuevo rumbo para el desarrollo Web (bueno me uno a Eduard y digo que no solo Web!) en .net, no solo por las ventajas que iniciativas como OWIN en si mismas proponen, sino por algo que ha ido evolucionando mucho en nuestra comunidad (.net) este tipo de cosas son muy normales en node js por ejemplo, donde hay varias opciones que puedes buscar en internet para resolver afrontar problemas, si pones npm “x cosa” en el buscador habrá al menos un loco en el mundo que ha subido un paquete que puedes descargarte y emplear para resolver tu problema. Para muchos desarrolladores de una plataforma tan robusta como lo es .NET esto también se ve como  un arma de doble filo, pues puede que ahora nos llenemos de millones de paquetes basura compatibles con OWIN que saber cual escoger se haga una tarea muy complicada (de hecho esto si pasa en node) o simplemente existan muchos paquetes con un mínimo de documentación… en fin, estos son skills que hacen que una comunidad sea fuerte, contribuir en proyectos open source no siempre es solo escribir código nuevo, se puede ayudar con implementaciones existentes, dando feedback o documentando.

Para quienes escribimos software corporativo y que aun no implementamos en producción nada fuera de un robusto IIS, pues repito, esto no supone el fin de IIS / System Web, para NADA! podemos tomar un IIS como nuestro hosting con KATANA, seleccionar los middlewares que necesitamos y los Frameworks a emplear con el mismo poder de siempre. De hecho en proyectos con VS2013 Preview ya vemos implementaciones con Katana 😀

El tema del licenciamiento es algo que me llama mucho la atención, si estas iniciativas buscan una mejora constante y hace énfasis en la portabilidad no emplees en tus aportes cosas como la que había hecho Microsoft con Katana! que había indicado (como en muchos otros paquetes de Nuget) una Windows-only Restriction, por fortuna anunció que en la versión 2, la que estará con VS2013 ya no tendrá esta restricción.

Entre colegas he visto muy parcializadas las opiniones frente a este tema, algunos alegan que nada es perfecto y querer hacer .net mas parecido a otros no es bueno… en fin, Microsoft parece no estar rompiendo nada hacía atrás y con iniciativas como esta, que repito, es de la misma comunidad de usuarios, se empiezan a dar mayores opciones, mas herramientas que podemos escoger para resolver nuestros problemas.

Si tienes alguna opinión sobre el tema no dudes en dejar tu comentario.

Bien, por ahora dejo el tema hasta aquí, ha sido un post teórico-practico-opinión, como para organizar un poco las ideas que esto trae y como lo veo yo, mas adelante espero escribir mas centrado en Katana, sus middlewares y la interacción con productos de la comunidad. 😀

Hasta el próximo post

OWIN, Katana y open source projects

[Web API] AtomPub y Web API Soporte para Multimedia

Esta semana agregué a este sitio soporte para el Atom Publishing Protocol, ayudado por supuesto por esta excelente guía de Ben Foster que en una serie de 3 artículos explica como integrar el AtomPub a un API en ASP.NET Web API, al final de los tres artículos queda haciendo falta cubrir un contenido, que de hecho lo piden en uno de los comentarios y que yo también necesito para publicar las imágenes de mi sitio desde el Windows Live Writer, pero vamos, somos desarrolladores y no conocemos los imposibles :P, así en este articulo voy a describir como lo solucioné.

¿Que dice la documentación?

Si revisamos la documentación oficial del protocolo encontramos que tenemos en el Service Document hay un elemento llamado app:accept y ya nos da una idea que vamos a necesitar, por ejemplo agregar “image/png”. Si continuamos leyendo esta documentación encontramos la sección de Media Resources and Media Link Entries donde nos brinda la documentación de como deben ir las peticiones y como se debe responder desde el servicio. Por si fuera poco y como bonus me encontré con el blog de Joe Cheng, quien explica en este articulo explica como deben estar las colecciones para que el WLW sea capaz de encontrar una colección donde ubicar dichos elementos (las imágenes). Teniendo ya bien clara toda la documentación solo nos hace falta implementarlo 🙂

La implementación

Lo primero que hice es permitir describir una colección para mis imágenes en el Service Document, esto es en el GET de uno de los controladores de mi API, el código queda de la forma:

    public class ServicesController : ApiController
    {
        public HttpResponseMessage Get()
        {
            var serviceDocument = new ServiceDocument();
            var workSpace = new Workspace
                                {
                                    Title = new TextSyndicationContent("Nicoloco Site"),
                                    BaseUri = new Uri(Request.RequestUri.GetLeftPart(UriPartial.Authority))
                                };
            var posts = new ResourceCollectionInfo("Nicoloco Blog",
                                                   new Uri(Url.Link("DefaultApi", new { controller = "blog" })));

            posts.Accepts.Add("application/atom+xml;type=entry");

            var images = new ResourceCollectionInfo("Images Blog",
                                                    new Uri(Url.Link("DefaultApi", new { controller = "images" })));
            images.Accepts.Add("image/png");
            images.Accepts.Add("image/jpeg");
            images.Accepts.Add("image/gif");

            workSpace.Collections.Add(posts);
            workSpace.Collections.Add(images);

            serviceDocument.Workspaces.Add(workSpace);

            var response = new HttpResponseMessage(HttpStatusCode.OK);
            var formatter = new AtomPub10ServiceDocumentFormatter(serviceDocument);
            var stream = new MemoryStream();
            using (var writer = XmlWriter.Create(stream))
            {
                formatter.WriteTo(writer);
            }
            stream.Position = 0;
            var content = new StreamContent(stream);
            response.Content = content;
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/atomsvc+xml");
            return response;
        }
    }

Lo que hice fue basarme en el código del articulo de Ben y agregar una nueva colección como lo indica la documentación que veíamos antes, ahora se puede descubrir esta colección para ubicar las imágenes

Una vez se puede descubrir esta colección en el documento del servicio debemos definir una entidad que nos ayude con la información de estos recursos y que podamos pedir como parámetro en nuestros controladores, mi entidad quedo definida de la forma:

    public class PostImage
    {
        public string Title { get; set; }
        public string FileName { get; set; }
        public string ContentType { get; set; }
        public byte[] BytesImage { get; set; }
        public DateTime PublishDate { get; set; }
        public string Url { get; set; }
    }

Esta definición va ligada a la documentación del protocolo, donde indican que cuando se pida dicho recurso es necesario conocer un titulo, ContentType tipo del recurso etc.

Como los request que vamos a recibir vendrán con una cabecera ContentType: image/* es necesario agregar un MediaTypeFormatter que nos facilita el tema de la negociación de contenido en Web API, el código queda de la forma:

public class ImageFormatter : MediaTypeFormatter
    {
        private const string Png = "image/png";
        private const string Jpeg = "image/jpeg";
        private const string Gif = "image/gif";
        SupportedMediaTypes.Add(new MediaTypeHeaderValue(Atom));

        public ImageFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue(Png));
            SupportedMediaTypes.Add(new MediaTypeHeaderValue(Jpeg));
            SupportedMediaTypes.Add(new MediaTypeHeaderValue(Gif));
            SupportedMediaTypes.Add(new MediaTypeHeaderValue(Atom));
        }
        public override bool CanReadType(Type type)
        {
            return typeof(PostImage) == type;
        }
        public override bool CanWriteType(Type type)
        {
            return typeof(PostImage) == type;
        }
        public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, System.Net.Http.HttpContent content, IFormatterLogger formatterLogger)
        {
            return Task.Factory.StartNew(() =>
                                             {
                                                 if (type == typeof(PostImage))
                                                 {
                                                     var postImage = (PostImage)Activator.CreateInstance(type);

                                                     //string name = content.Headers.GetValues("slug").FirstOrDefault();
                                                     MediaTypeHeaderValue contentType = content.Headers.ContentType;
                                                     string fileExtension = contentType.MediaType.Replace("image/", string.Empty);
                                                     postImage.ContentType = contentType.MediaType;
                                                     postImage.Title = DateTime.Now.ToString("yyyyMMddHHmmssFF");
                                                     postImage.FileName = string.Format("{0}.{1}", postImage.Title,
                                                                                        fileExtension);
                                                     var memoryStream = new MemoryStream();
                                                     readStream.CopyTo(memoryStream);
                                                     postImage.BytesImage = memoryStream.ToArray();
                                                     return (object)postImage;
                                                 }
                                                 return null;
                                             });

        }

        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
        {
            return Task.Factory.StartNew(() =>
                                             {
                                                 var image = (PostImage)value;
                                                 var item = new SyndicationItem
                                                                {
                                                                    Title = new TextSyndicationContent(image.Title),
                                                                    BaseUri = new Uri(image.Url),
                                                                    LastUpdatedTime = image.PublishDate,
                                                                    Content = new UrlSyndicationContent(new Uri(image.Url), image.ContentType)
                                                                };
                                                 item.Authors.Add(new SyndicationPerson { Name = "Nicolocodev" });
                                                 using (XmlWriter writer = XmlWriter.Create(writeStream))
                                                 {
                                                     var atomformatter = new Atom10ItemFormatter(item);
                                                     atomformatter.WriteTo(writer);
                                                 }
                                             });
        }
    }

Con lo anterior logramos entender la petición y transformarla a algo que entendamos y además somos capaces de brindar el recurso como el cliente lo desea cuando nos indique :).

Con esto solo nos falta agregar el tema de la persistencia del lado del controlador que se encargará de controlar estas peticiones, en mi caso, como dije en el primer articulo de este blog, haré uso de WindowsAzure Storage, así que para el almacenamiento de imágenes usaré el Blob Storage, la implementación de mi código queda de la forma:

    public class ImagesController : ApiController
    {
        private readonly CloudBlobContainer _container;
        private const string ImagesDirectory = "images";
        public ImagesController()
        {
            CloudBlobClient blobClient = WindowsAzureConfig.StorageAccount.CreateCloudBlobClient();
            _container = blobClient.GetContainerReference("blog");
            _container.CreateIfNotExists();
            _container.SetPermissions(new BlobContainerPermissions
                                         {
                                             PublicAccess = BlobContainerPublicAccessType.Blob
                                         });
            _container.GetDirectoryReference(ImagesDirectory);
        }

        public HttpResponseMessage GetImage(string id)
        {
            CloudBlockBlob blockBlob = _container.GetDirectoryReference(ImagesDirectory).GetBlockBlobReference(id);
            blockBlob.FetchAttributes();
            var postImage = new PostImage
                                {
                                    Title = id,
                                    ContentType = blockBlob.Properties.ContentType,
                                    FileName = id,
                                    Url = blockBlob.Uri.AbsoluteUri,
                                    PublishDate = DateTime.Now
                                };
            return Request.CreateResponse(HttpStatusCode.OK, postImage);
        }

        public HttpResponseMessage PostImageImage(PostImage postImage)
        {
            CloudBlockBlob blockBlob = _container.GetDirectoryReference(ImagesDirectory).GetBlockBlobReference(postImage.Title);
            blockBlob.Properties.ContentType = postImage.ContentType;

            var stream = new MemoryStream(postImage.BytesImage);
            blockBlob.UploadFromStream(stream);

            postImage.Url = blockBlob.Uri.AbsoluteUri;
            var response = Request.CreateResponse(HttpStatusCode.Created, postImage);
            response.Headers.Location = new Uri(Url.Link("DefaultApi", new { controller = "images", id = postImage.Title }));
            return response;
        }
    }

Espero les sea de utilidad.

Hasta el próximo post.

[Web API] AtomPub y Web API Soporte para Multimedia

[Web API] Versionando nuestros servicios – Evolución de la representación por adición

Siempre que trabajamos con servicios HTTP (sean REST o no) un factor que nos preocupa es el del versionamiento del servicio, la constante evolución del mismo y como los distintos clientes interactuaran con este sin romper lo que se ha construido.

Esta evolución puede darse por distintos aspectos, uno de los más frecuentes es la evolución de nuestros recursos (que vienen a ser identificados por una URI). Estos recursos son conceptuales y la única manera de materializarlos es por medio de representaciones (html, json, xml…) y cada uno de los formatos que soportemos brindaran a cada petición de cada cliente una forma de obtener el mismo recurso, esto es lo que conocemos como negociación de contenido.

Si intentamos llevar esta conceptualización a un entorno con ASP.NET Web Api por ejemplo, tendríamos “entidades” que no son más que nuestros recursos, así podemos tener una clase Persona definida de la siguiente manera:

    public class Persona
    {
        public string Nombre { get; set; }

        public string Apellido { get; set; }
    }

Y un controlador que se encargue de entender las peticiones a la URI que identifica el recurso, así:

    public class PersonaController : ApiController
    {
        private static List<Persona> _personas = CreatePersonas();

        private static List<Persona> CreatePersonas()
        {
            return _personas ?? (_personas = new List<Persona>
                                                 {
                                                     new Persona
                                                         {
                                                             Nombre = "Nicolas",
                                                             Apellido = "Herrera"
                                                         }
                                                 });
        }

        // GET api/values
        public IEnumerable<Persona> Get()
        {
            return _personas;
        }

        // GET api/values/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        public void Delete(int id)
        {
        }
    }

Y un cliente que se encarga de consumir esta información implementando la negociación de contenido que viene predeterminada en Web Api

        private static void Main(string[] args)
        {
            var httpClient = new HttpClient();
            httpClient.BaseAddress = new Uri("http://localhost:64186/api/persona");
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
            string json = httpClient.GetStringAsync(string.Empty).Result;
            var personas = JsonConvert.DeserializeObject<List<PersonaCliente>>(json);

            Console.WriteLine("Personas");
            foreach (PersonaCliente personaCliente in personas)
            {
                Console.WriteLine("Nombre y apellido: {0} {1}", personaCliente.Nombre,
                                  personaCliente.Apellido);
            }
            Console.ReadKey();
        }
    }

    public class PersonaCliente
    {
        public string Nombre { get; set; }

        public string Apellido { get; set; }
    }

Si nuestra entidad evolucionara adicionando una nueva propiedad sería lógico que su representación lo hiciera también y esta es la característica de versionamiento más pequeña que podemos encontrar, pues es muy común que necesitemos más información de una persona, información como por ejemplo la edad. Así:

    public class Persona
    {
        public string Nombre { get; set; }

        public string Apellido { get; set; }

        public int  Edad { get; set; }
    }

El primer approach y uno de los más usados es el versionamiento por la URI, y personalmente no es una solución que me agrade mucho, pues el concepto sigue siendo el mismo y no debería tener una nueva URI, pues esto significaría que es un nuevo concepto.

Cuando se le agregan elementos a la representación del recurso no debería afectar en nada a un cliente en específico porque en ese momento el ignora la existencia de ese elemento, en muchas ocasiones se rompe dicho contrato es porque se remueven elementos de la representación, elementos que desconocemos como los trabajaba cada uno de los clientes.

Teniendo esto presente a mi cliente de consola le dará igual que le agregué a la representación mientras el siga trabajando con dicha versión del API no rompo nada. Esta nueva propiedad será ignorada.

Ahora la pregunta es, como se apega mi cliente a una nueva versión si no estamos realizando peticiones a URIs distintas? La respuesta viene dada por la negociación de contenido y la cabecera accept por supuesto. Pero esto ya da para un segundo post que quiero escribir en mas detalle y no como un punto adicional de este.

Hasta el próximo post.

[Web API] Versionando nuestros servicios – Evolución de la representación por adición

[ASP.NET Web API] Métodos no HTTP en Api Controller

Como sabemos el framework reconocerá los métodos GetXXX, PostXXX etc. de nuestro Api Controller como métodos HTTP, pero puede surgir la necesidad de manejar métodos de acción que no trabajen con los métodos http, algo así como un RPC o mejor aún como los métodos de acción que hemos trabajado con MVC. Pues bien, la solución al interrogante de si es posible, es SI, y el ¿Cómo? Pues sencillo, simplemente agregamos una nueva ruta a la tabla de rutas muy similar a las que trabajamos con MVC:

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
            config.Routes.MapHttpRoute(
                name: "RpcApi",
                routeTemplate: "api/{controller}/{action}/{Id}",
                defaults: new { id = RouteParameter.Optional }
            );

Y del lado de nuestro API Controller un método que no sea entendido como un método Http, tal como:

        public string NoHttpMethod(string id)
        {
            return "Otro valor " + id.ToString(CultureInfo.InvariantCulture);
        }

Al ejecutar y hacer una solicitud a nuestra api obtendremos un http 405:



Esto es porque por defecto si no especificamos los verbos permitidos, el framework lo interpreta como un HTTP Post, por tanto GET no es un método entendido para este recurso. La solución está en decorar nuestro método con [AcceptVerbs (string)]

        [AcceptVerbs("GET")]
        public string NoHttpMethod(string id)
        {
            return "Otro valor " + id.ToString(CultureInfo.InvariantCulture);
        }

NOTA: [AcceptVerbs vs HttpGet]

Con esto agregamos soporte a esos métodos personalizados que podemos llegar a necesitar cuando trabajamos con Web Api.

Espero les sea de utilidad.

Hasta el próximos post.

[ASP.NET Web API] Métodos no HTTP en Api Controller

[ASP.NET] Actualización 2012

Así es, se anunció una serie de actualizaciones para ASP.NET – Visual Studio y ya es posible descargarlas y trabajarlas.

Descarga

La descarga la podemos realizar directamente en la WEB de ASP.NET en este enlace

¿Que se incluye?

En esta actualización lo primero que podemos notar es una serie de nuevas plantillas sobre nuestro Visual Studio 2012.

Entre la serie de mejoras podemos ubicar:

  • Facebook Template
  • Web Api Tracing, especial para el debug en nuestras apis
  • Soporte para OData wn Web Api
  • Windows Azure Authentication
  • Simple Page Aplication

Una última, que merece una felicitación para sus creadores Damian Eduards y David Fowler… si estoy hablando de SignalR 😀

Ya para terminar recomiendo este artículo del buen Jon Galloway.

Espero estén tan emocionados como yo 😛

Hasta el próximo post.

[ASP.NET] Actualización 2012