Fala galera, beleza?

Uma das novidades mais bacanas do ASP.NET 5 é a forma como ele trabalha com Middlewares. Abaixo vamos entender um pouco o que são, de onde vem, o que comem como funcionam e como implementar Middlewares para nossas aplicações ASP.NET 5.

Como tudo isso pode ser muita informação, vamos por partes e aos poucos. Futuramente elaborarei mais artigos explicando mais aspectos referentes ao trabalho com Middlewares, bem como mostrando algumas ferramentas que expostas através de Middlewares e que podem ajudar no desenvolvimento de nossas aplicações.

Owin e Katana

A utilização de Middlewares nào é algo novo. Tecnologias como Rails (Ruby) e Express (Node) já fazem uso disso. E foi isso que o pessoal do projeto Katana fez, implementando Owin. Agora temos a estrutura de Middlewares presentes no ASP.NET 5.

O que são Middlewares?

Basicamente as novas aplicações ASP.NET não sabem fazer muita coisa. Tudo vai depender de quais Middlewares você configure e utilize em sua aplicação.

A grosso modo um Middleware é um pedaço de código que atua entre o Request e o Response para uma requisição, como a imagem abaixo ilustra:
Middleware Pipeline

Percebam que existe um pipeline de Middlewares, todos a serem configurados, que atuam no momento em que um Request chega, trabalhando todo ele até que o Response esteja pronto. Reparem que dependendo da ordem em que um Middleware é configurado a forma como a aplicação se comporta vai mudar, pois eles são executados na ordem que definirmos no código. Este é um ponto que abordaremos melhor em um segundo artigo.

Configurando Middlewares no ASP.NET 5

Uma coisa interessante que vamos notar em uma aplicação ASP.NET 5 é que ela pode não conter nada. Para utilizarmos o MVC adicionamos o Middleware do MVC em nossa aplicação. Vejamos um Startup.cs cru, que responde a todos os Requests com apenas uma mensagem:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;

namespace middlewaredemo
{
    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("<h1>Hello ASP.NET 5</h1>");
            });
        }

        public static void Main(string[] args) => Microsoft.AspNet.Hosting.WebApplication.Run<Startup>(args);
    }
}

Isso é tudo que precisamos para subir uma aplicação ASP.NET. Ao rodar dnx web podemos acessar no nosso browser:
App ASP.NET 5

Esta app porém não é muito inteligente, pois para todo Request ela sempre responde a mesma coisa. Vamos adicionar então o Middleware do MVC e criar uma rota, Controller e uma View 😉

Adicionando Middleware MVC

Para fazermos isso primeiro precisamos colocar a dependência do MVC em nosso project.json:

 "dependencies": {
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
    "Microsoft.AspNet.Mvc": "6.0.0-rc1-final"
  },

Feito isso vamos instalar essa dependência com dnu restore (se você estiver no Visual Studio isso será feito automaticamente).

Agora vamos alterar o Startup.cs adicionando o serviço do MVC ao container:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
}

E ainda neste arquivo vamos dizer ao ASP.NET para usar o Middleware do MVC:

public void Configure(IApplicationBuilder app)
{
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

Com isso basta criarmos um Controller e uma View para que nosso request seja tratado pelo MVC:
ASP.NET usando Middleware MVC

Com isso passamos a configurar um Request Handler (o MVC) para a nossa aplicação e no geral esse tipo de Request Handler, reutilizável, é chamado de Middleware 😀

Criando um Middleware

Podemos facilmente criar um Middleware e adicioná-lo ao nosso pipeline. Vamos usar o exemplo da própria documentação do ASP.NET e criar um Middleware que faça log dos nossos requests.

O primeiro passo para o nosso exemplo será configurar a dependência no project.json:

  "dependencies": {
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
    "Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
    "Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final"
  }

Feito isso vamos criar uma classe que será nosso Middleware de Logging:

public static class RequestLoggerExtensions
{
    public static IApplicationBuilder UseRequestLogger(this IApplicationBuilder builder) => builder.UseMiddleware<RequestLoggerMiddleware>();
}

public class RequestLoggerMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public RequestLoggerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
    {
        _next = next;
        _logger = loggerFactory.CreateLogger<RequestLoggerMiddleware>();
    }

    public async Task Invoke(HttpContext context)
    {
        _logger.LogInformation("Handling request: " + context.Request.Path);
        await _next.Invoke(context);
        _logger.LogInformation("Finished handling request.");
    }
}

Acima definimos uma extension para usarmos com o padrão builder no Startup.cs e abaixo temos nosso Middleware de log. Reparem que nosso Middleware recebe um RequestDelegate chamado next que representa o próximo Middleware no nosso pipeline e recebe um objeto que implementa ILoggerFactory que será injetado no nosso Middleware pelo próprio framework.

Agora podemos apenas registrar nosso Middleware no Startup.cs:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(minLevel: LogLevel.Information);
                
    app.UseRequestLogger();
    
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

Primeiro adicionamos um Console Logger aos tipos de loggers disponíveis na nossa app, e então dizemos ao ASP.NET para usar nosso Middleware aqui app.UseRequestLogger(); (esta é a extension que definimos anteriormente).

Com isso ao executarmos nossa app veremos informações de log ao long de todos os requests:
Criando um Middleware de Logging

O código completo do Startup.cs e do middleware de Logging está aqui neste gist: https://gist.github.com/vquaiato/f562dcfd0f3982cd92f1

Conclusão

Agora está muito simples colocar algo no pipeline do ASP.NET, utilizando o padrão de Middlewares. Tudo que precisamos fazer é criar código que receba um request e saiba trabalhá-lo, passando o request para frente, respondendo ou terminando com ele.

É possível trabalhar com Middlewares de autenticação utilizando ferramentas como o IdentityServer 3 por exemplo, ou ainda criar um Middleware de autenticação Oauth com redes sociais, as opções e possibilidades são muitas.

Abraços,
Quaiats.

Vinicius Quaiato