Использование EnsureSuccessStatusCode и обработка исключений HttpRequestException

Каков шаблон использования HttpResponseMessage.EnsureSuccessStatusCode()? Он располагает Контентом сообщения и выбрасывает HttpRequestException, но я не вижу, как программно обрабатывать его иначе, чем общий Exception. Например, он не включает HttpStatusCode, что было бы удобно.

Есть ли способ получить больше информации? Может ли кто-нибудь показать соответствующий шаблон использования как EnsureSuccessStatusCode(), так и HttpRequestException?

Ответ 1

Идиоматическое использование EnsureSuccessStatusCode заключается в том, чтобы кратко подтвердить успех запроса, когда вы не хотите обрабатывать случаи отказа каким-либо конкретным способом. Это особенно полезно, если вы хотите быстро прототипировать клиента.

Когда вы решите, что хотите обрабатывать случаи отказа определенным образом, не делать следующее.

var response = await client.GetAsync(...);
try
{
    response.EnsureSuccessStatusCode();
    // Handle success
}
catch (HttpRequestException)
{
    // Handle failure
}

Это создает исключение, чтобы сразу его поймать, что не имеет никакого смысла. Для этой цели существует свойство IsSuccessStatusCode для HttpResponseMessage. Вместо этого сделайте следующее.

var response = await client.GetAsync(...);
if (response.IsSuccessStatusCode)
{
    // Handle success
}
else
{
    // Handle failure
}

Ответ 2

Мне не нравится EnsureSuccessStatusCode, поскольку он не возвращает ничего серьезного. Вот почему я создал собственное расширение:

public static class HttpResponseMessageExtensions
{
    public static async Task EnsureSuccessStatusCodeAsync(this HttpResponseMessage response)
    {
        if (response.IsSuccessStatusCode)
        {
            return;
        }

        var content = await response.Content.ReadAsStringAsync();

        if (response.Content != null)
            response.Content.Dispose();

        throw new SimpleHttpResponseException(response.StatusCode, content);
    }
}

public class SimpleHttpResponseException : Exception
{
    public HttpStatusCode StatusCode { get; private set; }

    public SimpleHttpResponseException(HttpStatusCode statusCode, string content) : base(content)
    {
        StatusCode = statusCode;
    }
}

исходный код для Microsoft EnsureSuccessStatusCode можно найти здесь

Синхронная версия на основе Ссылка SO:

public static void EnsureSuccessStatusCode(this HttpResponseMessage response)
{
    if (response.IsSuccessStatusCode)
    {
        return;
    }

    var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();

    if (response.Content != null)
        response.Content.Dispose();

    throw new SimpleHttpResponseException(response.StatusCode, content);
}

Что мне не нравится в IsSuccessStatusCode, так это то, что он не "красиво" многоразовый. Например, вы можете использовать библиотеку, например polly, чтобы повторить запрос в случае сетевой проблемы. В этом случае вам нужен ваш код, чтобы повысить исключение, чтобы политическая или некоторая другая библиотека могла его обрабатывать...

Ответ 3

Я знаю, что это не лучший способ сделать это, но я использую вот так:

try
{
    ...
}
catch (HttpRequestException exception)
{
    if (exception.Message.Contains("401 (Unauthorized)"))
    {
        statusCode = HttpStatusCode.Unauthorized;
    }
    else if (exception.Message.Contains("403 (Forbidden)"))
    {
        statusCode = HttpStatusCode.Forbidden;
    }
}

Пожалуйста, дайте мне знать, если у вас есть лучшее решение.

С уважением, B.J.