Senkron Bağlantı için neden HttpClient kullanılır?


188

Bir API ile etkileşim kurmak için bir sınıf kütüphanesi inşa ediyorum. API çağırmak ve XML yanıtı işlemek gerekiyor. HttpClientEşzamansız bağlantı için kullanmanın faydalarını görebiliyorum , ancak yaptığım şey tamamen eşzamanlı, bu yüzden kullanmaya göre önemli bir fayda göremiyorum HttpWebRequest.

Herkes herhangi bir ışık saçabilirse, ben çok takdir ediyorum. Bunun için yeni teknolojiyi kullanan biri değilim.


3
Size söylemekten nefret ediyorum, ancak Windows üzerinden ağ iletişimi dahili olarak nasıl çalıştığından (tamamlama bağlantı noktaları olarak da bilinir) HTTP üzerinden yapılan çağrı hiçbir zaman tamamen senkronize değildir.
TomTom


Yanıtlar:


374

ama yaptığım şey tamamen eşzamanlı

HttpClientEşzamanlı istekler için kullanabilirsiniz :

using (var client = new HttpClient())
{
    var response = client.GetAsync("http://google.com").Result;

    if (response.IsSuccessStatusCode)
    {
        var responseContent = response.Content; 

        // by calling .Result you are synchronously reading the result
        string responseString = responseContent.ReadAsStringAsync().Result;

        Console.WriteLine(responseString);
    }
}

Uzağa kullanmak niye Olarak HttpClientüzerine WebRequestsöz konusu, iyi, HttpClientblokta yeni çocuk ve yaşlı istemci üzerinde geliştirmeler içerebilir.


27
Eşzamansız yöntemleri eşzamanlı olarak kullanmanız UI iş parçacığınızı potansiyel olarak engellemez mi? Bunu senkronize string responseString = Task.Run(() => responseContent.ReadAsStringAsync()).Result;etmeniz gerekiyorsa , bunun gibi bir şey düşünmek isteyebilirsiniz .
dünyalı

13
@earthling, evet, Task.Rungörevi bir ThreadPool'dan çağırır, ancak bundan .Resulttüm faydaları öldürmek ve bunu aradığınız iş parçacığını .Result(genellikle ana UI iş parçacığı olur) engellemek için çağırıyorsunuz .
Darin Dimitrov

35
Bu gönderiye göre ( blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx ) .Resultböyle çağırmak threadpool'ı tüketebilir ve kilitlenmeye neden olabilir.
Pete Garafano

16
Bu kod, ana kullanıcı arabirimi iş parçacığında bir görev tarafından yürütülürse her zaman kilitlenecektirnew TaskFactory(TaskScheduler.FromCurrentSynchronizationContext()
Wim Coenen

24
Peki, HttpClient'i UI iş parçacığından eşzamanlı olarak nasıl kullanabilirim? Diyelim diyorum bilerek (veya bir konsol uygulaması yazıyorum) Ben HTTP yanıtı elde edene vb bekleyin (), Sonuç (), kilitlenmeleri neden olabilir eğer ... Yani, bunun için kesin çözüm nedir UI iş parçacığı engellemek istiyor olmadan çıkmazdan ve risk olmadan WebClient gibi diğer sınıfları kullanarak?
Dexter

26

Donny V. cevabını ve Josh'un

"Async sürümünü kullanmamamın tek nedeni, daha önce yerleşik async desteği olmayan .NET'in eski bir sürümünü desteklemeye çalışmamdı."

(ve itibara sahip olsaydım oyla.)

Son kez hatırlamıyorum, HttpWebRequest durum kodu> = 400 için istisnalar attığı için minnettarım. Bu sorunların üstesinden gelmek için hemen istisnaları yakalamanız ve bazı istisnai olmayan yanıt mekanizmalarına eşlemeniz gerekir. kodunuzda ... kendi içinde sıkıcı, sıkıcı ve hata eğilimli. İster bir veritabanı ile iletişim kuruyor, isterse ısmarlama bir web proxy'si uyguluyor olsun, Http sürücüsünün sadece uygulama kodunuza ne döndürüldüğünü söylemesi ve nasıl davranacağınıza karar vermek için size bırakması 'neredeyse' her zaman istenir.

Bu nedenle HttpClient tercih edilir.


1
HttpClientKendisinin etrafında bir sarıcı olduğuna şaşırdım HttpWebRequest(bu aslında dahili olarak bu WebExceptionnesneleri yakalar ve sizin için bir dönüştürme yapar HttpResponseMessage). Tamamen sıfırdan yeni bir müşteri oluşturmanın daha kolay olacağını düşünürdüm.
Dai

4
Tüm kod tabanınızı yalnızca performans açısından bile kritik olmayan çok düşük seviyeli bir http çağrısı için yeniden yazmak istememek gibi birçok iyi neden vardır (ancak bir milyon yere async tanıtacaktır).
FrankyBoy

.Net çekirdek 2'de, bir ifadeyi DynamicExpressionParser ile dinamik olarak değerlendirmek istiyorsanız, zaman uyumsuz kullanmak mümkün olmayabilir; özellik dizinleyicileri zaman uyumsuz kullanamaz; benim durumumda dinamik olarak "GetDefaultWelcomeMessage [\" InitialMessage \ "]" gibi bir dize değerlendirmek gerekir burada bu yöntem bir HttpCall yapar ve dizin sözdizimi "Util.GetDefaultWelcomeMessage (\" InitialMessage \ ")"
eugen tercih edilir

7

Bir sınıf kütüphanesi oluşturuyorsanız, belki de kütüphanenizin kullanıcıları kütüphanenizi eşzamansız olarak kullanmak isterler. Bence bu en büyük sebep.

Ayrıca kitaplığınızın nasıl kullanılacağını da bilmiyorsunuz. Belki de kullanıcılar çok sayıda isteği işleyecek ve bunu eşzamansız olarak yapmak, daha hızlı ve daha verimli çalışmasına yardımcı olacaktır.

Bunu basitçe yapabiliyorsanız, onlar için bakabileceğiniz zaman akışı asenkron hale getirmeye çalışan kütüphanenizin kullanıcılarına yükü yüklememeye çalışın.

Async sürümünü kullanmamamın tek nedeni, daha önce yerleşik async desteği olmayan .NET'in eski bir sürümünü desteklemeye çalışmamdı.


Görüyorum, bu yüzden sınıf kitaplığını asenkron hale getirin ve sistem kullanıcılarının zaman uyumsuz kullanıp kullanmamaya karar vermesine veya beklemede kullanmasına ve senkronize olarak kullanmasına izin verilsin mi?
Ketçap

erm, bekle, kontrolü arayana geri döndürerek belirli çağrıları eşzamansız hale getirmeye yardımcı olur.
Josh Smeaton

6

Benim durumumda kabul edilen cevap işe yaramadı. API zaman uyumsuz eylemleri vardı bir MVC uygulamasından çağırıyordu.

Ben iş bu şekilde başardı:

private static readonly TaskFactory _myTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
public static T RunSync<T>(Func<Task<T>> func)
    {           
        CultureInfo cultureUi = CultureInfo.CurrentUICulture;
        CultureInfo culture = CultureInfo.CurrentCulture;
        return _myTaskFactory.StartNew<Task<T>>(delegate
        {
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = cultureUi;
            return func();
        }).Unwrap<T>().GetAwaiter().GetResult();
    }

Sonra şöyle dedim:

Helper.RunSync(new Func<Task<ReturnTypeGoesHere>>(async () => await AsyncCallGoesHere(myparameter)));

1
Thx @Darkonekt ... Bu benim için mükemmel çalışıyor. Yalnızca HttpClient.SendAsync (...). Sonuç hiçbir zaman AspNet Handler (.ASHX) içinde çalışmaz.
Rafael Kazuo Sato Simiao

3
public static class AsyncHelper  
{
    private static readonly TaskFactory _taskFactory = new
        TaskFactory(CancellationToken.None,
                    TaskCreationOptions.None,
                    TaskContinuationOptions.None,
                    TaskScheduler.Default);

    public static TResult RunSync<TResult>(Func<Task<TResult>> func)
        => _taskFactory
            .StartNew(func)
            .Unwrap()
            .GetAwaiter()
            .GetResult();

    public static void RunSync(Func<Task> func)
        => _taskFactory
            .StartNew(func)
            .Unwrap()
            .GetAwaiter()
            .GetResult();
}

Sonra

AsyncHelper.RunSync(() => DoAsyncStuff());

Bu sınıfı kullanırsanız, zaman uyumsuz yönteminizi parametre olarak geçirirseniz, zaman uyumsuzluk yöntemlerini eşitleme yöntemlerinden güvenli bir şekilde çağırabilirsiniz.

burada açıklanmıştır: https://cpratt.co/async-tips-tricks/


-1

Tüm cevaplar HttpClientsoruya gerçek cevap vermek yerine senkronize kullanmaya odaklanıyor gibi görünüyor .

HttpClientbasit bir istek / yanıt işleyicisi daha fazladır, bu yüzden farklı ağların bazı özellikleri ile başa çıkabilir. Yani benim durumumda müzakere gerektiren NTLM proxy ile çalışmak, kimlik doğrulaması için istemci ve proxy sunucusu arasında belirteçler ve kimlik bilgileri ile birden fazla istek / yanıt göndermek. HttpClient(using HttpClientHandler), bir yöntem çağrısı ile kaynakları proxy'nin ötesinde döndüren yerleşik bir mekanizmaya sahip gibi görünüyor.


Cevabınız HttpClient'in eşzamansız olarak nasıl kullanılacağını açıklamıyor.
user275801

@ user275801 Bu aptalca bir yorum. Kimse bunu sormadı. Varsayılan olarak eşzamansızdır.
Bizniztime
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.