Проверка, представляет ли HttpStatusCode успех или неудачу

93

Предположим, у меня есть следующая переменная:

System.Net.HttpStatusCode status = System.Net.HttpStatusCode.OK;

Как я могу проверить, является ли это кодом состояния успеха или ошибкой?

Например, я могу сделать следующее:

int code = (int)status;
if(code >= 200 && code < 300) {
    //Success
}

Еще у меня может быть какой-то белый список:

HttpStatusCode[] successStatus = new HttpStatusCode[] {
     HttpStatusCode.OK,
     HttpStatusCode.Created,
     HttpStatusCode.Accepted,
     HttpStatusCode.NonAuthoritativeInformation,
     HttpStatusCode.NoContent,
     HttpStatusCode.ResetContent,
     HttpStatusCode.PartialContent
};
if(successStatus.Contains(status)) //LINQ
{
    //Success
}

Ни одна из этих альтернатив меня не убеждает, и я надеялся на класс или метод .NET, которые могут выполнять эту работу за меня, например:

bool isSuccess = HttpUtilities.IsSuccess(status);
Матиас Цицерон
источник
вам нужно будет сделать int code = (int)Response.StatusCodeоттуда, вам нужно будет создать здесь свою собственную Enumпроверку для рабочего примера stackoverflow.com/questions/1330856/…
MethodMan
Вы случайно не пользуетесь HttpClientклассом?
dcastro
1
@dcastro Нет, извините. Я использую высокоуровневый API, который может (или не может) использовать его внутри. API предоставляет код состояния ответа, но не раскрывает, HttpResponseMessageнапример, внутренний
Матиас Цицеро,
@MatiCicero Это очень плохо: / Вы всегда можете повторно использовать реализацию HttpResponseMessage.IsSuccessStatusCode(см. Мой ответ), которая точно такая же, как ваш первый подход, и сделать ее методом расширения для HttpStatusCodeтипа.
dcastro

Ответы:

177

Если вы пользуетесь HttpClientклассом, то получите HttpResponseMessageобратно.

У этого класса есть полезное свойство, IsSuccessStatusCodeкоторое будет проверять за вас.

using (var client = new HttpClient())
{
    var response = await client.PostAsync(uri, content);
    if (response.IsSuccessStatusCode)
    {
        //...
    }
}

Если вам интересно, это свойство реализовано как:

public bool IsSuccessStatusCode
{
    get { return ((int)statusCode >= 200) && ((int)statusCode <= 299); }
}

Таким образом, вы можете просто повторно использовать этот алгоритм, если не используете его HttpClientнапрямую.

Вы также можете использовать EnsureSuccessStatusCodeдля создания исключения, если ответ не был успешным.

Dcastro
источник
1
К вашему сведению: для меня это был ответ.
Тофер Рождение
Ваш ответ весьма полезен, но теперь он работает так: if (response.IsCompletedSuccessfully) {//}
Салман
12

У класса HttpResponseMessage есть свойство IsSuccessStatusCode, если посмотреть на исходный код, это похоже на это, так как usr уже предположил, что 200–299, вероятно, лучшее, что вы можете сделать.

public bool IsSuccessStatusCode
{
    get { return ((int)statusCode >= 200) && ((int)statusCode <= 299); }
}
TomDoesCode
источник
11

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

Вы можете достичь точно такого же результата, создав экземпляр HttpResponseMessage с вашим кодом состояния и проверив его успех. Он вызывает исключение аргумента, если значение меньше нуля или больше 999.

if (new HttpResponseMessage((HttpStatusCode)statusCode).IsSuccessStatusCode)
{
    // ...
}

Это не совсем кратко, но вы можете сделать его расширением.

user232548
источник
Это отлично сработало для меня, поскольку у меня был только HttpStatusCode, а не ответное сообщение. Отличная работа!
Тодд Вэнс
5
«Принятый ответ немного беспокоит меня, так как он содержит магические числа (хотя они стандартные)» - они не «волшебные», если они стандартизированы, хорошо поняты и никогда не изменятся. Нет абсолютно ничего плохого в том, чтобы использовать коды напрямую. Если у вас все IsSuccessStatusCodeхорошо, используйте его (как сказано в принятом ответе). В противном случае не добавляйте свой собственный мусор, используя абстракцию, если вы не выполняете эту проверку повсюду
Эд С.
1
Имейте в виду, что создание экземпляра HttpResponseMessageдля использования одного из его свойств занимает больше времени, чем проверка двух логических условий с помощью int.
Миро Дж.
10

Добавление в ответ @TomDoesCode Если вы используете HttpWebResponse, вы можете добавить этот метод расширения:

public static bool IsSuccessStatusCode(this HttpWebResponse httpWebResponse)
{
    return ((int)httpWebResponse.StatusCode >= 200) && ((int)httpWebResponse.StatusCode <= 299);
}
ozba
источник
8

Я неравнодушен к открываемости методов расширения.

public static class HttpStatusCodeExtensions
{
    public static bool IsSuccessStatusCode(this HttpStatusCode statusCode)
    {
        var asInt = (int)statusCode;
        return asInt >= 200 && asInt <= 299;
    }
}

Пока ваше пространство имен находится в области видимости, использование будет statusCode.IsSuccessStatusCode().

Боджинго
источник
Методы расширения - это круто, но я запутался - разве это не то же самое, что свойство IsSuccessStatusCode HTTPResponseMessage, которое используется с HTTPClient или IHTTPClientFactory? @DCastro даже показывает нам, что это реализовано именно так в .NET. Когда и зачем мне использовать такой метод расширения для кодов состояния HTTP в диапазоне 2xx?
sfors требует восстановить Монику на работе
4
@sfors, да, но что, если у вас есть только HttpStatusCodeв области видимости? Существует множество библиотек, которые не используются и не отображаются, HttpResponseMessageно предоставляют код состояния.
bojingo
3

Это зависит от того, какой HTTP-ресурс вы вызываете. Обычно 2xxдиапазон определяется как диапазон кодов состояния успеха. Это явно соглашение, которого будет придерживаться не каждый HTTP-сервер.

Например, отправка формы на веб-сайте часто возвращает 302 редирект.

Если вы хотите разработать общий метод, эта code >= 200 && code < 300идея, вероятно, будет вашим лучшим вариантом.

Если вы вызываете свой собственный сервер, вам, вероятно, следует убедиться, что вы стандартизированы 200.

usr
источник
2

Это расширение предыдущего ответа, которое позволяет избежать создания и последующей сборки мусора нового объекта для каждого вызова.

public static class StatusCodeExtensions
{
    private static readonly ConcurrentDictionary<HttpStatusCode, bool> IsSuccessStatusCode = new ConcurrentDictionary<HttpStatusCode, bool>();
    public static bool IsSuccess(this HttpStatusCode statusCode) => IsSuccessStatusCode.GetOrAdd(statusCode, c => new HttpResponseMessage(c).IsSuccessStatusCode);
}
Роб Линдон
источник