Controladores de mensajes HttpClient en ASP.NET Web API

Un controlador de mensajes es una clase que recibe una solicitud HTTP y devuelve una respuesta HTTP.

Normalmente, una serie de controladores de mensajes se encadenan. El primer controlador recibe una solicitud HTTP, realiza algún procesamiento y proporciona la solicitud al siguiente controlador. En algún momento, se crea la respuesta y se realiza una copia de seguridad de la cadena. Este patrón se denomina controlador de delegación.

Diagram of message handlers chained together, illustrating process to receive an H T T P request and return an H T T P response.

En el lado cliente, la clase HttpClient usa un controlador de mensajes para procesar las solicitudes. El controlador predeterminado es HttpClientHandler, que envía la solicitud a través de la red y obtiene la respuesta del servidor. Puede insertar controladores de mensajes personalizados en la canalización de cliente:

Diagram of process to insert custom message handlers into client pipeline. Shows h t t p Client class that uses a message handler to process requests.

Nota:

ASP.NET Web API también usa controladores de mensajes en el lado servidor. Para obtener más información, consulte controladores de mensajes HTTP.

Controladores de mensajes personalizados

Para escribir un controlador de mensajes personalizado, derive de System.Net.Http.DelegatingHandler e invalide el método SendAsync. Esta es la firma del método:

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

El método toma un HttpRequestMessage como entrada y devuelve de forma asincrónica un HttpResponseMessage. Una implementación típica hace lo siguiente:

  1. Procesar el mensaje de solicitud.
  2. Llamar a base.SendAsync para enviar la solicitud al controlador interno.
  3. El controlador interno devuelve un mensaje de respuesta. (Este paso es asincrónico).
  4. Procesar la respuesta y devolverla al autor de la llamada.

En el siguiente ejemplo se muestra un controlador de mensajes que agrega un encabezado personalizado a la solicitud saliente:

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);
    }
}

La llamada a base.SendAsync es asincrónica. Si el controlador realiza algún trabajo después de esta llamada, use la palabra clave await para reanudar la ejecución una vez completado el método. En el siguiente ejemplo se muestra un controlador que registra códigos de error. El registro en sí no es muy interesante, pero en el ejemplo se muestra cómo obtener la respuesta dentro del controlador.

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);
    }
}

Adición de controladores de mensajes a la canalización de cliente

Para agregar controladores personalizados a HttpClient, use el método HttpClientFactory.Create:

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

Se llama a los controladores de mensajes en el orden en que se pasan al método Create. Dado que los controladores están anidados, el mensaje de respuesta viaja en la otra dirección. Es decir, el último controlador es el primero para obtener el mensaje de respuesta.