Обработчики сообщений HttpClient в веб-API ASP.NET

Обработчик сообщений — это класс, который получает HTTP-запрос и возвращает HTTP-ответ.

Как правило, ряд обработчиков сообщений объединяется. Первый обработчик получает HTTP-запрос, выполняет некоторую обработку и передает запрос следующему обработчику. В какой-то момент создается ответ и выполняется резервное копирование цепочки. Этот шаблон называется делегированным обработчиком.

Схема обработчиков сообщений, объединяемых в цепочку, иллюстрирующая процесс получения запроса H T T P и возврата ответа H T T P.

На стороне клиента класс HttpClient использует обработчик сообщений для обработки запросов. Обработчик по умолчанию — HttpClientHandler, который отправляет запрос по сети и получает ответ с сервера. Можно вставить пользовательские обработчики сообщений в клиентский конвейер:

Схема процесса вставки пользовательских обработчиков сообщений в клиентский конвейер. Показывает класс t p Client, использующий обработчик сообщений для обработки запросов.

Замечание

ASP.NET веб-API также использует обработчики сообщений на стороне сервера. Дополнительные сведения см. в разделе "Обработчики сообщений HTTP".

Пользовательские обработчики сообщений

Чтобы написать пользовательский обработчик сообщений, наследуйте от System.Net.Http.DelegatingHandler и переопределите метод SendAsync. Ниже приведена подпись метода:

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

Метод принимает HttpRequestMessage в качестве входных данных и асинхронно возвращает httpResponseMessage. Типичная реализация выполняет следующие действия:

  1. Обработайте сообщение запроса.
  2. Вызовите base.SendAsync, чтобы отправить запрос внутреннему обработчику.
  3. Внутренний обработчик возвращает ответное сообщение. (Этот шаг является асинхронным.)
  4. Обработайте ответ и верните его клиенту.

В следующем примере показан обработчик сообщений, который добавляет пользовательский заголовок в исходящий запрос:

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

Вызов base.SendAsync является асинхронным. Если обработчик выполняет любую работу после этого вызова, используйте ключевое слово await , чтобы возобновить выполнение после завершения метода. В следующем примере показан обработчик, который регистрирует коды ошибок. Само логирование не очень интересно, но в примере показано, как получить доступ к ответу внутри обработчика.

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

Добавление обработчиков сообщений в клиентский конвейер

Чтобы добавить пользовательские обработчики в HttpClient, используйте метод HttpClientFactory.Create :

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

Обработчики сообщений вызываются в порядке их передачи в метод Create . Поскольку обработчики вложены друг в друга, сообщение ответа перемещается в противоположном направлении. То есть последний обработчик первым получает ответное сообщение.