Manipuladores de mensagens HttpClient no ASP.NET Web API

por Mike Wasson

Um manipulador de mensagens é uma classe que recebe uma solicitação HTTP e retorna uma resposta http.

Normalmente, uma série de manipuladores de mensagens é encadeada. O primeiro manipulador recebe uma solicitação HTTP, executa algum processamento e fornece a solicitação para o próximo manipulador. Em algum momento, a resposta é criada e retorna o backup da cadeia. Esse padrão é chamado de manipulador de delegação .

No lado do cliente, a classe HttpClient usa um manipulador de mensagens para processar solicitações. O manipulador padrão é HttpClientHandler, que envia a solicitação pela rede e obtém a resposta do servidor. Você pode inserir manipuladores de mensagens personalizados no pipeline do cliente:

Note

ASP.NET Web API também usa manipuladores de mensagens no lado do servidor. Para obter mais informações, consulte manipuladores de mensagens http.

Manipuladores de mensagens personalizadas

Para gravar um manipulador de mensagens personalizado, derive de System .net. http. DelegatingHandler e substitua o método SendAsync . Veja a assinatura do método:

Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, CancellationToken cancellationToken);

O método usa um HttpRequestMessage como entrada e retorna de forma assíncrona um HttpResponseMessage. Uma implementação típica faz o seguinte:

  1. Processar a mensagem de solicitação.
  2. Chame base.SendAsync para enviar a solicitação para o manipulador interno.
  3. O manipulador interno retorna uma mensagem de resposta. (Essa etapa é assíncrona.)
  4. Processar a resposta e retorná-la ao chamador.

O exemplo a seguir mostra um manipulador de mensagens que adiciona um cabeçalho personalizado à solicitação de saída:

class MessageHandler1 : DelegatingHandler
{
    private int _count = 0;

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        System.Threading.Interlocked.Increment(ref _count);
        request.Headers.Add("X-Custom-Header", _count.ToString());
        return base.SendAsync(request, cancellationToken);
    }
}

A chamada a base.SendAsync é assíncrona. Se o manipulador executar qualquer trabalho após essa chamada, use a palavra-chave Await para retomar a execução após a conclusão do método. O exemplo a seguir mostra um manipulador que registra códigos de erro. O registro em log não é muito interessante, mas o exemplo mostra como obter a resposta dentro do manipulador.

class LoggingHandler : DelegatingHandler
{
    StreamWriter _writer;

    public LoggingHandler(Stream stream)
    {
        _writer = new StreamWriter(stream);
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);

        if (!response.IsSuccessStatusCode)
        {
            _writer.WriteLine("{0}\t{1}\t{2}", request.RequestUri, 
                (int)response.StatusCode, response.Headers.Date);
        }
        return response;
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _writer.Dispose();
        }
        base.Dispose(disposing);
    }
}

Adicionando manipuladores de mensagens ao pipeline do cliente

Para adicionar manipuladores personalizados a HttpClient, use o método HttpClientFactory. Create :

HttpClient client = HttpClientFactory.Create(new Handler1(), new Handler2(), new Handler3());

Os manipuladores de mensagens são chamados na ordem em que são passados para o método Create . Como os manipuladores são aninhados, a mensagem de resposta viaja na outra direção. Ou seja, o último manipulador é o primeiro a obter a mensagem de resposta.