Не удается прочитать содержимое HttpResponseMessage, если код состояния не выполнен - PullRequest
4 голосов
/ 10 января 2020

У меня есть служба, которая использует API REST SMS с использованием HttpClient:

HttpClient http = this._httpClientFactory.CreateClient();
// Skipped: setup HttpRequestMessage
using (HttpResponseMessage response = await http.SendAsync(request))
{
    try
    {
        _ = response.EnsureSuccessStatusCode();
    }
    catch (HttpRequestException)
    {
        string responseString = await response.Content.ReadAsStringAsync(); // Fails with ObjectDisposedException
        this._logger.LogInformation(
            "Received invalid HTTP response status '{0}' from SMS API. Response content was {1}.",
            (int)response.StatusCode,
            responseString
        );
        throw;
    }
}

API возвращает ошибку, но я хотел бы иметь возможность ее регистрировать. Поэтому мне нужно зарегистрировать как код ошибки (который я могу прочитать из response.StatusCode), так и связанный контент (который может содержать дополнительные полезные сведения об ошибках).

Этот код не выполняется в инструкции await response.Content.ReadAsStringAsync() с это исключение:

System.ObjectDisposedException: невозможно получить доступ к удаленному объекту.
Имя объекта: 'System. Net .Http.HttpConnection + HttpConnectionResponseContent'.
Модуль "System. Net .Http.HttpContent ", в CheckDisposed
Модуль" Система. Net .Http.HttpContent ", в ReadAsStringAsyn c

Некоторые источники предполагают, что вы не должны читать содержание ответа, когда код состояния не находится в диапазоне успеха (200-299), но что, если ответ действительно содержит полезные сведения об ошибке?

. NET используемая версия:. NET Core 2.1.12 AWS лямбда linux время выполнения.

1 Ответ

4 голосов
/ 10 января 2020

ОК, очевидно, это известная проблема в. NET API, которая была устранена в. NET Core 3.0. response.EnsureSuccessStatusCode() фактически удаляет содержимое ответа. Он был реализован таким образом, чтобы якобы помогать пользователям:

// Утилизация контента должна помочь пользователям: если пользователи вызывают EnsureSuccessStatusCode (), возникает исключение
//, если код состояния ответа ! = 2xx. Т.е. поведение аналогично неудачному запросу (например,
// сбой соединения). Пользователи не ожидают избавиться от содержимого в этом случае: если исключение
// выброшено, объект отвечает за очистку своего состояния.

Это нежелательное поведение, которое было снято с 3.0. А пока я просто переключился на использование IsSuccessStatusCode перед журналом:

HttpClient http = this._httpClientFactory.CreateClient();
// Skipped: setup HttpRequestMessage
using (HttpResponseMessage response = await http.SendAsync(request))
{
    if (!response.IsSuccessStatusCode)
    {
        string responseString = await response.Content.ReadAsStringAsync(); // Fails with ObjectDisposedException
        this._logger.LogInformation(
            "Received invalid HTTP response status '{0}' from SMS API. Response content was {1}.",
            (int)response.StatusCode,
            responseString
        );
        _ = response.EnsureSuccessStatusCode();
    }
}

Чуть более избыточно, но оно должно работать.

...