EnsureSuccessStatusCode kullanımı ve attığı HttpRequestException'ın işlenmesi


107

Kullanım şekli nedir HttpResponseMessage.EnsureSuccessStatusCode()? Mesajın İçeriğini elden çıkarır ve gönderir HttpRequestException, ancak onu programatik olarak genelden farklı bir şekilde nasıl ele alacağımı göremiyorum Exception. Örneğin, HttpStatusCodekullanışlı olabilecek olanı içermez .

Bundan daha fazla bilgi almanın bir yolu var mı? Herhangi biri hem hem de EnsureSuccessStatusCode()HttpRequestException için ilgili kullanım modelini gösterebilir mi?

Yanıtlar:


158

'Nin deyimsel kullanımı, EnsureSuccessStatusCodebaşarısızlık durumlarını belirli bir şekilde ele almak istemediğinizde, bir isteğin başarısını kısaca doğrulamaktır. Bu, özellikle bir istemcinin hızlı bir şekilde prototipini oluşturmak istediğinizde kullanışlıdır.

Karar ne zaman, belirli bir şekilde başarısızlık davalarını istiyorum yok aşağıdakileri yapın.

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

Bu, hemen yakalamak için bir istisna atar ki bu hiç mantıklı değil. IsSuccessStatusCodeMalı HttpResponseMessagebu amaç için vardır. Bunun yerine aşağıdakileri yapın.

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

1
Gerçek tamsayı durum kodunu almanın bir yolu var mı ? bunu denediğimde 404 durum kodu yerine "Bulunamadı" gibi bir dize alıyorum.
NickG

12
@NickG (int)response.StatusCode(Bkz msdn.microsoft.com/en-us/library/... )
Timothy Shields

1
EnsureSuccessStatusCode () tarafından atılan varsayılan HttpRequestException neden ifadesine sahip olacaktır. Ancak başarılı olmazsa, yanıtta bu mülke yine de erişebilirsiniz.
Stefan Zvonar

@TimothyShields Hızlı prototip oluşturmaya izin verdiğiniz için renginizi takdir ediyorum. Neden ve bloklarına response.Contentgeçmeden önce değeri ilk önce okumuyorsunuz ? Bu şekilde, mülkü yalnızca bir kez okursunuz. Bunu bu şekilde yapmanın tek dezavantajı, Content özelliği uzun bir dizeyse, temelde istemciyi yavaşlatmanızdır, ancak hız konusunda endişeleriniz varsa, neden sadece kullanmayasınız ? // Handle success// Handle failureresponse.Contentresponse.EnsureSuccessStatusCode();
John Zabroski

Kendi EnsureSuccessStatusCode sürümümü aşağıya yazdım. stackoverflow.com/a/63476616/1040437Content Durumu kontrol etmeden önce sorumluluğu arayana devreder .
John Zabroski

97

EnsureSuccessStatusCode'u anlamlı bir şey döndürmediği için sevmiyorum. Bu yüzden kendi uzantımı oluşturdum:

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'un EnsureSuccessStatusCode için kaynak kodu burada bulunabilir

SO bağlantısına dayalı eşzamanlı sürüm :

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 ile ilgili hoşlanmadığım şey "güzelce" yeniden kullanılabilir olmamasıdır. Örneğin , ağ sorunu olması durumunda bir isteği tekrarlamak için polly gibi kitaplığı kullanabilirsiniz . Bu durumda, polly veya başka bir kütüphanenin işleyebilmesi için istisna oluşturmak için kodunuza ihtiyacınız vardır ...


1
kabul ediyorum, varsayılan kod geri dönüşten anlamlı bir mesaj alma özelliğinin eksik olduğunu.
LT

2
Sürümünüz, uygulamasının orijinal uygulamasından farklı çalışıyor EnsureSuccessStatusCode. Her zaman elden çıkarırsınız response.Content(çünkü sonunda her zaman return;ifadeden sonra çağrılır ) ve daha fazla okumak için içeriği yok eder. Orijinal uygulama, içeriği yalnızca durum kodu başarılı sonucu göstermediğinde atar.
Lukas.Navratil

4
Neden önce await response.Content.ReadAsStringAsync()ve sonra kontrol if (response.Content != null)
ettiğinizi anlamıyorum

3
Polly, bu tür bir senaryoya tam olarak yardımcı olmak için artık dönüş sonuçlarını ve istisnaları ele alıyor. Polly'yi HttpRequestçağrıları koruyacak şekilde yapılandırabilir ve politikayı hem belirli istisnaları hem de belirli e-postaları işleyecek şekilde yapılandırabilirsiniz HttpResponseCode. Polly benioku sayfasındaki örneğe
dağ gezgini

2
response.ContentÜzerinde çağrılan bir metodu varken nasıl boş olabilir ?
Ian Warburton

1

Exception'ı aynı yöntemde işlemek istemediğimde EnsureSuccessStatusCode kullanıyorum.

public async Task DoSomethingAsync(User user)
{
    try
    {
        ...
        var userId = await GetUserIdAsync(user)
        ...
    }
    catch(Exception e)
    {
        throw;
    }
}

public async Task GetUserIdAsync(User user)
{
    using(var client = new HttpClient())
    {
        ...
        response = await client.PostAsync(_url, context);

        response.EnsureSuccesStatusCode();
        ...
    }
}

GetUserIdAsync üzerinde oluşturulan İstisna DoSomethingAsync üzerinde işlenecektir.


1

Aşağıda önerdiğim çözüm var. Tek kusur, ASP.NET Core çerçeve kaynak yöneticisi çerçeveye dahil olduğundan, Microsoft'un uluslararasılaştırılmış mesaj dizelerini doğrudan yeniden kullanamıyorum, bu yüzden burada sadece kelimesi kelimesine İngilizce mesajı kullanıyorum.

Artıları

  • İçeriği bir 5xx sunucu hatası için günlüğe kaydeder
    • Bazen, bir sunucu hatası aslında kılık değiştirmiş bir istemci hatasıdır, örneğin, kullanımdan kaldırılmış bir uç noktayı kullanan ve sonunda kapatılan bir istemci gibi.
  • Kullanarak entegrasyon testleri yazarken hataları ortaya çıkarmayı kolaylaştırır ConfigureTestContainer<T>

Eksileri

  • Yetersiz.
    • Yanıt içeriğini okursanız ve içerik çok uzunsa, istemciyi yavaşlatırsınız. Yumuşak gerçek zamanlı yanıt gereksinimleri olan bazı müşteriler için bu gecikme kabul edilemez olabilir.
  • Hata kaydı ve izleme için yanlış sorumluluk.
    • Eğer bu bir 5xx sunucu hatasıysa, istemci yanlış bir şey yapmadığına göre neden istemci bunu önemsiyor? Sadece arayın response.EnsureSuccessStatusCode();ve sunucu ilgilensin.
    • Neden Dahili Sunucu Hatası varken sunucu hata günlüklerini kontrol etmiyorsunuz?
  • ContentDurumu kontrol etmeden önce mülkün okunmasını gerektirir . Bunun istenmediği durumlar olabilir, bunlardan biri verimsizliktir.

Kullanım

using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, "controller/action"))
{
  using (var response = await HttpClient.SendAsync(requestMessage))
  {
    var content = await response.Content.ReadAsStringAsync();
    response.EnsureSuccessStatusCode2(content);
    var result = JsonConvert.DeserializeObject<ResponseClass>(content);
  }
}

API

    public static class HttpResponseMessageExtensions
    {
        public static void EnsureSuccessStatusCode2(this HttpResponseMessage message, string content = null)
        {
            if (message.IsSuccessStatusCode)
                return;
            var contentMessage = string.IsNullOrWhiteSpace(content) ? string.Empty : $"Content: {content}";
            throw new HttpRequestException(string.Format(
                System.Globalization.CultureInfo.InvariantCulture,
                "Response status code does not indicate success: {0} ({1}).{2}",
                (int)message.StatusCode,
                message.ReasonPhrase,
                contentMessage)
                );
        }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.