HttpClient और WebClient के बीच निर्णय लेना


218

हमारा वेब ऐप .Net फ्रेमवर्क 4.0 में चल रहा है। यूआई अजाक्स कॉल के माध्यम से नियंत्रक विधियों को कॉल करता है।

हमें अपने विक्रेता से REST सेवा का उपभोग करना होगा। मैं .net 4.0 में REST सेवा को कॉल करने के सर्वोत्तम तरीके का मूल्यांकन कर रहा हूं। REST सेवा के लिए मूल प्रमाणीकरण योजना की आवश्यकता होती है और यह XML और JSON दोनों में डेटा लौटा सकती है। विशाल डेटा अपलोड / डाउनलोड करने के लिए कोई आवश्यकता नहीं है और मुझे भविष्य में कुछ भी दिखाई नहीं देता है। मैंने REST की खपत के लिए कुछ खुले स्रोत कोड परियोजनाओं पर एक नज़र डाली और परियोजना में अतिरिक्त निर्भरता को सही ठहराने के लिए उनमें कोई मूल्य नहीं पाया। मूल्यांकन करने के लिए शुरू किया WebClientऔर HttpClient। मैंने NuGet से .net 4.0 के लिए HttpClient डाउनलोड किया।

मैंने और इस साइट के बीच के अंतरों की खोज की WebClientऔर उल्लेख किया कि एकल HttpClient समवर्ती कॉल को संभाल सकता है और यह DNS, कुकी कॉन्फिग और ऑथेंटिकेशन को हल कर सकता है। मुझे उन व्यावहारिक मूल्यों को देखना बाकी है जिन्हें हम मतभेदों के कारण प्राप्त कर सकते हैं।HttpClient

मैंने यह पता लगाने के लिए एक त्वरित प्रदर्शन परीक्षण किया कि कैसे WebClient(सिंक कॉल), HttpClient(सिंक और एसिंक्स) प्रदर्शन करते हैं। और यहाँ परिणाम हैं:

HttpClientसभी अनुरोधों के लिए एक ही उदाहरण का उपयोग करना (न्यूनतम - अधिकतम)

WebClient सिंक: 8 एमएस - 167 एमएस
HttpClient सिंक: 3 एमएस - 7228 एमएस
HttpClient async: 985 - 10405 एमएस

HttpClientप्रत्येक अनुरोध के लिए एक नया प्रयोग करना (न्यूनतम - अधिकतम)

WebClient सिंक: ४ एमएस - २ ९
H एमएस HttpClient सिंक: ३ एमएस - p ९ ५३ एमएस
एचटीटीपी क्लाइंट async: १०२ 4 - १०34३४ एमएस

कोड

public class AHNData
{
    public int i;
    public string str;
}

public class Program
{
    public static HttpClient httpClient = new HttpClient();
    private static readonly string _url = "http://localhost:9000/api/values/";

    public static void Main(string[] args)
    {
       #region "Trace"
       Trace.Listeners.Clear();

       TextWriterTraceListener twtl = new TextWriterTraceListener(
           "C:\\Temp\\REST_Test.txt");
       twtl.Name = "TextLogger";
       twtl.TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime;

       ConsoleTraceListener ctl = new ConsoleTraceListener(false);
       ctl.TraceOutputOptions = TraceOptions.DateTime;

       Trace.Listeners.Add(twtl);
       Trace.Listeners.Add(ctl);
       Trace.AutoFlush = true;
       #endregion

       int batchSize = 1000;

       ParallelOptions parallelOptions = new ParallelOptions();
       parallelOptions.MaxDegreeOfParallelism = batchSize;

       ServicePointManager.DefaultConnectionLimit = 1000000;

       Parallel.For(0, batchSize, parallelOptions,
           j =>
           {
               Stopwatch sw1 = Stopwatch.StartNew();
               GetDataFromHttpClientAsync<List<AHNData>>(sw1);
           });
       Parallel.For(0, batchSize, parallelOptions,
            j =>
            {
                Stopwatch sw1 = Stopwatch.StartNew();
                GetDataFromHttpClientSync<List<AHNData>>(sw1);
            });
       Parallel.For(0, batchSize, parallelOptions,
            j =>
            {
                using (WebClient client = new WebClient())
                {
                   Stopwatch sw = Stopwatch.StartNew();
                   byte[] arr = client.DownloadData(_url);
                   sw.Stop();

                   Trace.WriteLine("WebClient Sync " + sw.ElapsedMilliseconds);
                }
           });

           Console.Read();
        }

        public static T GetDataFromWebClient<T>()
        {
            using (var webClient = new WebClient())
            {
                webClient.BaseAddress = _url;
                return JsonConvert.DeserializeObject<T>(
                    webClient.DownloadString(_url));
            }
        }

        public static void GetDataFromHttpClientSync<T>(Stopwatch sw)
        {
            HttpClient httpClient = new HttpClient();
            var response = httpClient.GetAsync(_url).Result;
            var obj = JsonConvert.DeserializeObject<T>(
                response.Content.ReadAsStringAsync().Result);
            sw.Stop();

            Trace.WriteLine("HttpClient Sync " + sw.ElapsedMilliseconds);
        }

        public static void GetDataFromHttpClientAsync<T>(Stopwatch sw)
        {
           HttpClient httpClient = new HttpClient();
           var response = httpClient.GetAsync(_url).ContinueWith(
              (a) => {
                 JsonConvert.DeserializeObject<T>(
                    a.Result.Content.ReadAsStringAsync().Result);
                 sw.Stop();
                 Trace.WriteLine("HttpClient Async " + sw.ElapsedMilliseconds);
              }, TaskContinuationOptions.None);
        }
    }
}

मेरे सवाल

  1. REST कॉल 3-4s में लौटाता है जो स्वीकार्य है। नियंत्रक सेवा के लिए कॉल को नियंत्रक विधियों में शुरू किया जाता है जो कि अजाक्स कॉल से आह्वान किया जाता है। शुरू करने के लिए, कॉल एक अलग थ्रेड में चलती हैं और UI को ब्लॉक नहीं करती हैं। तो, क्या मैं सिर्फ सिंक कॉल के साथ रह सकता हूं?
  2. उपरोक्त कोड मेरे स्थानीय बॉक्स में चलाया गया था। ठेस स्थापना में, DNS और प्रॉक्सी लुकअप शामिल होंगे। क्या HttpClientओवर का उपयोग करने का कोई फायदा है WebClient?
  3. क्या HttpClientसंगामिति से बेहतर है WebClient? परीक्षण के परिणामों से, मुझे लगता है कि WebClientसिंक कॉल बेहतर प्रदर्शन करती हैं।
  4. HttpClientअगर हम .net 4.5 में अपग्रेड करते हैं तो क्या एक बेहतर डिज़ाइन विकल्प होगा? प्रदर्शन प्रमुख डिज़ाइन कारक है।

5
आपका परीक्षण अनुचित है GetDataFromHttpClientAsyncक्योंकि यह पहले चलता है, अन्य आह्वान का संभावित रूप से काहेड डेटा (स्थानीय मशीन या आपके और गंतव्य के बीच किसी भी पारदर्शी प्रॉक्सी पर होना) का लाभ मिलता है और तेज होगा। इसके अलावा, सही परिस्थितियों var response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;में थ्रेडपूल थ्रेड्स को समाप्त करने के कारण गतिरोध हो सकता है। आपको कभी भी ऐसी गतिविधि पर रोक नहीं लगानी चाहिए जो थ्रेडपूल थ्रेड्स में थ्रेड पूल पर निर्भर करती है, आपको awaitइसके बजाय इसे थ्रेड को पूल में वापस करना चाहिए ।
स्कॉट चेम्बरलेन

1
वेब एपीआई क्लाइंट के साथ HttpClient एक JSON / XML REST क्लाइंट के लिए शानदार है।
कोरी नेल्सन

@ सच चेम्बरलेन - आपके उत्तर के लिए धन्यवाद। जैसा कि सभी परीक्षण कॉल Parallel.Foreach में चलते हैं, इस बात की कोई गारंटी नहीं है कि कौन सा पहले चला होगा। इसके अलावा, सेवा के लिए पहली कॉल GetDataFromHttpClientAsync की थी, GetDataFromHttpClientAsync के सभी बाद के कॉल कैश से लाभान्वित होने चाहिए और तेजी से चलने चाहिए। मैंने उस परिणाम में नहीं देखा। आरजीडी प्रतीक्षा, हम अभी भी 4.0 का उपयोग कर रहे हैं। मैं आपसे सहमत हूं कि सिंक फैशन में HttpClient गतिरोध पैदा करेगा और मैं अपने डिजाइन विचार से उस विकल्प पर शासन कर रहा हूं।
user3092913

@CoryNelson क्या आप विस्तार से बता सकते हैं कि वेब एपीआई क्लाइंट के साथ HttpClient एक JSON / XML टेस्ट क्लाइंट के लिए शानदार क्यों है?
user3092913

2
यहाँ HttpClient और WebClient के बीच के अंतर पर कुछ शब्द दिए गए हैं: blogs.msdn.com/b/henrikn/archive/2012/02/11//-
JustAndrei

जवाबों:


243

मैं एफ # और वेब एपीआई दुनिया दोनों में रहता हूं।

वेब एपीआई के साथ बहुत सारी अच्छी चीजें हो रही हैं, विशेष रूप से सुरक्षा के लिए संदेश संचालकों के रूप में, आदि।

मुझे पता है कि मेरा केवल एक ही मत है, लेकिन मैं केवल HttpClientभविष्य के किसी भी काम के उपयोग की सिफारिश करूंगा । शायद System.Net.Httpउस विधानसभा का उपयोग किए बिना बाहर आने वाले कुछ अन्य टुकड़ों का लाभ उठाने का कोई तरीका है , लेकिन मैं कल्पना नहीं कर सकता कि इस समय कैसे काम करेगा।

इन दोनों की तुलना करने की बात कही

  • HttpClient WebClient की तुलना में HTTP के अधिक निकट है।
  • HttpClient का अर्थ वेब क्लाइंट का पूर्ण प्रतिस्थापन नहीं था, क्योंकि रिपोर्ट प्रगति, कस्टम URI योजना और WebClient द्वारा प्रदान की जाने वाली FTP कॉल जैसी चीजें हैं - लेकिन HttpClient नहीं करता है।
+--------------------------------------------+--------------------------------------------+
|               WebClient                    |               HttpClient                   |
+--------------------------------------------+--------------------------------------------+
| Available in older versions of .NET        | .NET 4.5 only.  Created to support the     |
|                                            | growing need of the Web API REST calls     |
+--------------------------------------------+--------------------------------------------+
| WinRT applications cannot use WebClient    | HTTPClient can be used with WinRT          |
+--------------------------------------------+--------------------------------------------+
| Provides progress reporting for downloads  | No progress reporting for downloads        |
+--------------------------------------------+--------------------------------------------+
| Does not reuse resolved DNS,               | Can reuse resolved DNS, cookie             |
| configured cookies                         | configuration and other authentication     |
+--------------------------------------------+--------------------------------------------+
| You need to new up a WebClient to          | Single HttpClient can make concurrent      |
| make concurrent requests.                  | requests                                   |
+--------------------------------------------+--------------------------------------------+
| Thin layer over WebRequest and             | Thin layer of HttpWebRequest and           |
| WebResponse                                | HttpWebResponse                            |
+--------------------------------------------+--------------------------------------------+
| Mocking and testing WebClient is difficult | Mocking and testing HttpClient is easy     |
+--------------------------------------------+--------------------------------------------+
| Supports FTP                               | No support for FTP                         |
+--------------------------------------------+--------------------------------------------+
| Both Synchronous and Asynchronous methods  | All IO bound methods in                    |
| are available for IO bound requests        | HTTPClient are asynchronous                |
+--------------------------------------------+--------------------------------------------+

यदि आप .NET 4.5 का उपयोग कर रहे हैं, तो कृपया डेवलपर्स के लिए Microsoft द्वारा प्रदान किए जाने वाले HttpClient के साथ async अच्छाई का उपयोग करें। HttpClient HTTP के सर्वर साइड भाइयों के लिए बहुत सममित है जो कि HttpRequest और HttpResponse हैं।

अपडेट: नए HttpClient एपीआई का उपयोग करने के लिए 5 कारण:

  • मजबूत टाइपर्स हेडर।
  • साझा कैश, कुकीज़ और साख
  • कुकीज़ और साझा कुकीज़ तक पहुंच
  • कैशिंग और साझा कैश पर नियंत्रण।
  • ASP.NET पाइपलाइन में अपने कोड मॉड्यूल को इंजेक्ट करें। क्लीनर और मॉड्यूलर कोड।

संदर्भ

सी # 5.0 जोसेफ अलबहारी

(Channel9 - वीडियो बिल्ड 2013)

वेब सेवाओं से जुड़ने के लिए नए HttpClient एपीआई का उपयोग करने के लिए पांच महान कारण

WebClient बनाम HttpClient बनाम HttpWebRequest


4
यह उल्लेख किया जाना चाहिए कि HttpClient .NET 4.0 के लिए भी उपलब्ध है
टोड मेनियर

2
यह स्पष्ट नहीं करता है कि WebClient HttpClient की तुलना में तेज़ी से परिमाण क्यों लगता है। इसके अलावा WebClientअब async तरीकों लगता है।
क्रश करें

8
@crush यह है क्योंकि ओपी हर एक अनुरोध के लिए HttpClient का एक नया उदाहरण बना रहा है। इसके बजाय आपको अपने आवेदन के जीवनकाल के लिए HttpClient के एकल उदाहरण का उपयोग करना चाहिए। देखें stackoverflow.com/a/22561368/57369
गेब्रियल

6
यह ध्यान देने योग्य WebClientहै, .Net Coreलेकिन इसमें उपलब्ध नहीं HttpClientहै।
प्रणव सिंह

3
चूंकि .Net कोर 2.0 वेबक्लाइंट (हजारों अन्य एपीआई के बीच) वापस और उपलब्ध हैं।
कोडरबैंग

56

HttpClient एपीआई का नया है और इसके फायदे हैं

  • एक अच्छा async प्रोग्रामिंग मॉडल है
  • हेनरिक एफ नील्सन द्वारा काम किया जा रहा है, जो मूल रूप से HTTP के अन्वेषकों में से एक है, और उन्होंने एपीआई को डिज़ाइन किया है इसलिए आपके लिए HTTP मानक का पालन करना आसान है, जैसे कि मानकों का अनुपालन करने वाले हेडर बनाना।
  • .Net फ्रेमवर्क 4.5 में है, इसलिए इसमें भविष्य के लिए समर्थन की गारंटी स्तर है
  • लाइब्रेरी का xcopyable / पोर्टेबल-फ्रेमवर्क संस्करण भी है यदि आप इसे अन्य प्लेटफार्मों पर उपयोग करना चाहते हैं - .net 4.0, Windows XP आदि।

यदि आप एक वेब सेवा लिख ​​रहे हैं जो अन्य वेब सेवाओं के लिए REST कॉल कर रही है, तो आपको अपने सभी REST कॉल के लिए एक async प्रोग्रामिंग मॉडल का उपयोग करना चाहिए, ताकि आप थ्रेड भुखमरी को न मारें। आप शायद नवीनतम C # कंपाइलर का भी उपयोग करना चाहते हैं जिसमें async / प्रतीक्षा समर्थन है।

नोट: यह अधिक प्रदर्शनकारी AFAIK नहीं है। यदि आप निष्पक्ष परीक्षा देते हैं तो यह संभवत: कुछ इसी तरह का प्रदर्शन करने वाला है।


यदि यह प्रॉक्सी को स्विच करने का एक तरीका है, तो यह पागल होगा
ed22

3

सबसे पहले, मैं WebClient बनाम HttpClient पर विशेष रूप से एक प्राधिकरण नहीं हूं। दूसरे, ऊपर की आपकी टिप्पणियों से, यह लगता है कि WebClient केवल सिंक है जबकि HttpClient दोनों है।

मैंने यह जानने के लिए एक त्वरित प्रदर्शन परीक्षण किया कि WebClient (सिंक कॉल), HttpClient (सिंक और एसिंक्स) कैसे प्रदर्शन करते हैं। और यहाँ परिणाम हैं।

मैं देखता हूं कि भविष्य के लिए सोचते समय एक बड़ा अंतर के रूप में, यानी लंबे समय तक चलने वाली प्रक्रियाएं, उत्तरदायी जीयूआई, इत्यादि (जो लाभ आप 4.5 फ्रेमवर्क द्वारा सुझाते हैं - जो कि मेरे वास्तविक अनुभव में IIS पर बहुत तेजी से है)


4
WebClientलगता है कि नवीनतम .NET संस्करणों में async क्षमताएं हैं। मैं जानना चाहता हूं कि इतने बड़े पैमाने पर HttpClient से बेहतर प्रदर्शन क्यों होता है।
क्रश करें

1
के अनुसार stackoverflow.com/a/4988325/1662973 , यह एक ही, तथ्य यह है कि एक दूसरे के एक अमूर्त है के अलावा अन्य हो रहा है। हो सकता है, यह इस बात पर निर्भर करता है कि वस्तुओं का उपयोग कैसे किया जाता है / लोड किया जाता है। न्यूनतम समय इस कथन का समर्थन करता है कि वेबक्लीट वास्तव में HttpClient का एक अमूर्त हिस्सा है, इसलिए एक मिलिसेकंड ओवरहेड के बराबर है। फ्रेमवर्क "डरपोक" हो सकता है कि यह वास्तव में पूलिंग या वेबक्लेर का निपटान कैसे हो सकता है।
एंथनी हॉर्न

3

HttpClientFactory

यह उन विभिन्न तरीकों का मूल्यांकन करने के लिए महत्वपूर्ण है जिन्हें आप एक HttpClient बना सकते हैं, और इसका एक हिस्सा HttpClientFactory समझ रहा है।

https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

यह एक सीधा जवाब नहीं है जो मुझे पता है - लेकिन आप new HttpClient(...)हर जगह से समाप्त होने की तुलना में यहां शुरू करने से बेहतर हैं ।


2

मेरे पास HttpClient, WebClient, HttpWebResponse के बीच बेंचमार्क है, फिर रेस्ट वेब एपि को कॉल करें

और परिणाम बाकी वेब एपि बेंचमार्क कॉल करें

--------------------- स्टेज 1 ---- 10 अनुरोध

{00: 00: 17.2232544} ====> HttpClinet

{००: ००: ०४.३१०86 ९ ६} ====> WebRequest

{00: 00: 04.5436889} ====> WebClient

--------------------- स्टेज 1 ---- 10 अनुरोध - छोटे आकार

{00: 00: १७.२२,३२,५४४} ====> HttpClinet

{00: 00: ०४.३१,०८,९८६} ====> WebRequest

{00: 00: ०४.५४,३६,८८९} ====> WebClient

--------------------- स्टेज 3 ---- 10 सिंक अनुरोध - छोटा आकार

{00: 00: १५.३०,४७,५०२} ====> HttpClinet

{00: 00: ०३.५५,०५,२४९} ====> WebRequest

{00: 00: ०४.०७,६१,३५९} ====> WebClient

--------------------- स्टेज 4 ---- 100 सिंक अनुरोध - छोटा आकार

{00: 03: २३.६२,६८,०८६} ====> HttpClinet

{00: 00: ४७.१४,०६,६३२} ====> WebRequest

{00: 01: ०१.२३,१९,४९९} ====> WebClient

--------------------- स्टेज 5 ---- 10 सिंक अनुरोध - अधिकतम आकार

{00: 00: ५८.१८,०४,६७७} ====> HttpClinet

{00: 00: ५८.०७,१०,४४४} ====> WebRequest

{00: 00: ३८.४१,७०,९३८} ====> WebClient

--------------------- स्टेज 6 ---- 10 सिंक अनुरोध - अधिकतम आकार

{00: 01: ०४.९९,६४,२७८} ====> HttpClinet

{00: 00: ५९.१४,२९,७६४} ====> WebRequest

{00: 00: ३२.०५,८४,८३६} ====> WebClient

_____ WebClient तेज है ()

var stopWatch = new Stopwatch();
        stopWatch.Start();
        for (var i = 0; i < 10; ++i)
        {
            CallGetHttpClient();
            CallPostHttpClient();
        }

        stopWatch.Stop();

        var httpClientValue = stopWatch.Elapsed;

        stopWatch = new Stopwatch();

        stopWatch.Start();
        for (var i = 0; i < 10; ++i)
        {
            CallGetWebRequest();
            CallPostWebRequest();
        }

        stopWatch.Stop();

        var webRequesttValue = stopWatch.Elapsed;


        stopWatch = new Stopwatch();

        stopWatch.Start();
        for (var i = 0; i < 10; ++i)
        {

            CallGetWebClient();
            CallPostWebClient();

        }

        stopWatch.Stop();

        var webClientValue = stopWatch.Elapsed;

// ------------------------- कार्य

private void CallPostHttpClient()
    {
        var httpClient = new HttpClient();
        httpClient.BaseAddress = new Uri("https://localhost:44354/api/test/");
        var responseTask = httpClient.PostAsync("PostJson", null);
        responseTask.Wait();

        var result = responseTask.Result;
        var readTask = result.Content.ReadAsStringAsync().Result;

    }
    private void CallGetHttpClient()
    {
        var httpClient = new HttpClient();
        httpClient.BaseAddress = new Uri("https://localhost:44354/api/test/");
        var responseTask = httpClient.GetAsync("getjson");
        responseTask.Wait();

        var result = responseTask.Result;
        var readTask = result.Content.ReadAsStringAsync().Result;

    }
    private string CallGetWebRequest()
    {
        var request = (HttpWebRequest)WebRequest.Create("https://localhost:44354/api/test/getjson");

        request.Method = "GET";
        request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;

        var content = string.Empty;

        using (var response = (HttpWebResponse)request.GetResponse())
        {
            using (var stream = response.GetResponseStream())
            {
                using (var sr = new StreamReader(stream))
                {
                    content = sr.ReadToEnd();
                }
            }
        }

        return content;
    }
    private string CallPostWebRequest()
    {

        var apiUrl = "https://localhost:44354/api/test/PostJson";


        HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(new Uri(apiUrl));
        httpRequest.ContentType = "application/json";
        httpRequest.Method = "POST";
        httpRequest.ContentLength = 0;

        using (var httpResponse = (HttpWebResponse)httpRequest.GetResponse())
        {
            using (Stream stream = httpResponse.GetResponseStream())
            {
                var json = new StreamReader(stream).ReadToEnd();
                return json;
            }
        }

        return "";
    }

    private string CallGetWebClient()
    {
        string apiUrl = "https://localhost:44354/api/test/getjson";


        var client = new WebClient();

        client.Headers["Content-type"] = "application/json";

        client.Encoding = Encoding.UTF8;

        var json = client.DownloadString(apiUrl);


        return json;
    }

    private string CallPostWebClient()
    {
        string apiUrl = "https://localhost:44354/api/test/PostJson";


        var client = new WebClient();

        client.Headers["Content-type"] = "application/json";

        client.Encoding = Encoding.UTF8;

        var json = client.UploadString(apiUrl, "");


        return json;
    }

1
ऊपर गेब्रियल की टिप्पणी देखें। संक्षेप में, यदि आप HttpClient का एक उदाहरण बनाते हैं और पुन: उपयोग करते हैं, तो HttpClient बहुत तेज़ है।
LT Dan

1

शायद आप समस्या के बारे में एक अलग तरीके से सोच सकते थे। WebClientऔर HttpClientअनिवार्य रूप से एक ही चीज़ के विभिन्न कार्यान्वयन हैं। जो मैं सुझाता हूं वह आपके आवेदन में IoC कंटेनर के साथ डिपेंडेंसी इंजेक्शन पैटर्न को लागू करने का है । आपको निम्न स्तर के HTTP हस्तांतरण की तुलना में उच्च स्तर के साथ क्लाइंट इंटरफ़ेस का निर्माण करना चाहिए। आप ठोस वर्ग है कि दोनों का उपयोग लिख सकते हैं और , और फिर config के माध्यम से कार्यान्वयन सुई आईओसी कंटेनर का उपयोग करें।WebClientHttpClient

यह आपको क्या करने की अनुमति देगा HttpClientऔर WebClientआसानी से स्विच किया जा सकेगा ताकि आप उत्पादन वातावरण में उद्देश्यपूर्ण परीक्षण कर सकें।

तो जैसे सवाल:

यदि हम .net 4.5 में अपग्रेड करते हैं तो क्या HttpClient एक बेहतर डिज़ाइन विकल्प होगा?

वास्तव में IoC कंटेनर का उपयोग करके दो क्लाइंट कार्यान्वयन के बीच स्विच करके उत्तर दिया जा सकता है। यहाँ एक उदाहरण इंटरफ़ेस है जिस पर आप निर्भर हो सकते हैं जिसमें HttpClientया के बारे में कोई विवरण शामिल नहीं है WebClient

/// <summary>
/// Dependency Injection abstraction for rest clients. 
/// </summary>
public interface IClient
{
    /// <summary>
    /// Adapter for serialization/deserialization of http body data
    /// </summary>
    ISerializationAdapter SerializationAdapter { get; }

    /// <summary>
    /// Sends a strongly typed request to the server and waits for a strongly typed response
    /// </summary>
    /// <typeparam name="TResponseBody">The expected type of the response body</typeparam>
    /// <typeparam name="TRequestBody">The type of the request body if specified</typeparam>
    /// <param name="request">The request that will be translated to a http request</param>
    /// <returns></returns>
    Task<Response<TResponseBody>> SendAsync<TResponseBody, TRequestBody>(Request<TRequestBody> request);

    /// <summary>
    /// Default headers to be sent with http requests
    /// </summary>
    IHeadersCollection DefaultRequestHeaders { get; }

    /// <summary>
    /// Default timeout for http requests
    /// </summary>
    TimeSpan Timeout { get; set; }

    /// <summary>
    /// Base Uri for the client. Any resources specified on requests will be relative to this.
    /// </summary>
    Uri BaseUri { get; set; }

    /// <summary>
    /// Name of the client
    /// </summary>
    string Name { get; }
}

public class Request<TRequestBody>
{
    #region Public Properties
    public IHeadersCollection Headers { get; }
    public Uri Resource { get; set; }
    public HttpRequestMethod HttpRequestMethod { get; set; }
    public TRequestBody Body { get; set; }
    public CancellationToken CancellationToken { get; set; }
    public string CustomHttpRequestMethod { get; set; }
    #endregion

    public Request(Uri resource,
        TRequestBody body,
        IHeadersCollection headers,
        HttpRequestMethod httpRequestMethod,
        IClient client,
        CancellationToken cancellationToken)
    {
        Body = body;
        Headers = headers;
        Resource = resource;
        HttpRequestMethod = httpRequestMethod;
        CancellationToken = cancellationToken;

        if (Headers == null) Headers = new RequestHeadersCollection();

        var defaultRequestHeaders = client?.DefaultRequestHeaders;
        if (defaultRequestHeaders == null) return;

        foreach (var kvp in defaultRequestHeaders)
        {
            Headers.Add(kvp);
        }
    }
}

public abstract class Response<TResponseBody> : Response
{
    #region Public Properties
    public virtual TResponseBody Body { get; }

    #endregion

    #region Constructors
    /// <summary>
    /// Only used for mocking or other inheritance
    /// </summary>
    protected Response() : base()
    {
    }

    protected Response(
    IHeadersCollection headersCollection,
    int statusCode,
    HttpRequestMethod httpRequestMethod,
    byte[] responseData,
    TResponseBody body,
    Uri requestUri
    ) : base(
        headersCollection,
        statusCode,
        httpRequestMethod,
        responseData,
        requestUri)
    {
        Body = body;
    }

    public static implicit operator TResponseBody(Response<TResponseBody> readResult)
    {
        return readResult.Body;
    }
    #endregion
}

public abstract class Response
{
    #region Fields
    private readonly byte[] _responseData;
    #endregion

    #region Public Properties
    public virtual int StatusCode { get; }
    public virtual IHeadersCollection Headers { get; }
    public virtual HttpRequestMethod HttpRequestMethod { get; }
    public abstract bool IsSuccess { get; }
    public virtual Uri RequestUri { get; }
    #endregion

    #region Constructor
    /// <summary>
    /// Only used for mocking or other inheritance
    /// </summary>
    protected Response()
    {
    }

    protected Response
    (
    IHeadersCollection headersCollection,
    int statusCode,
    HttpRequestMethod httpRequestMethod,
    byte[] responseData,
    Uri requestUri
    )
    {
        StatusCode = statusCode;
        Headers = headersCollection;
        HttpRequestMethod = httpRequestMethod;
        RequestUri = requestUri;
        _responseData = responseData;
    }
    #endregion

    #region Public Methods
    public virtual byte[] GetResponseData()
    {
        return _responseData;
    }
    #endregion
}

पूर्ण कोड

HttpClient कार्यान्वयन

आप इसके कार्यान्वयन में अतुल्यकालिक रूप से चलाने के Task.Runलिए उपयोग कर सकते हैं WebClient

डिपेंडेंसी इंजेक्शन, जब अच्छी तरह से किया जाता है, तो निम्न स्तर के निर्णय को आगे बढ़ाने में समस्या को कम करने में मदद मिलती है। अंतत: सही उत्तर जानने का एकमात्र तरीका है कि दोनों जीवित वातावरण में प्रयास करें और देखें कि कौन सा सबसे अच्छा काम करता है। यह काफी संभव है कि WebClientकुछ ग्राहकों के HttpClientलिए बेहतर काम कर सकता है , और दूसरों के लिए बेहतर काम कर सकता है। यही कारण है कि अमूर्तता महत्वपूर्ण है। इसका अर्थ है कि एप्लिकेशन के मूल डिज़ाइन को बदलने के बिना कोड को जल्दी से स्वैप किया जा सकता है, या कॉन्फ़िगरेशन के साथ बदला जा सकता है।


1

2020 से अलोकप्रिय राय:

जब यह ASP.NET ऐप की बात आती है, तो मैं अभी भी पसंद WebClientकरता हूँ HttpClientक्योंकि:

  1. आधुनिक कार्यान्वयन एसिंक्स / प्रतीक्षा योग्य कार्य-आधारित विधियों के साथ आता है
  2. छोटी स्मृति पदचिह्न और 2x-5x तेज है (अन्य उत्तर पहले से ही उल्लेख करते हैं) विशेष रूप से परिदृश्यों में जब आप अन्य टिप्पणीकारों की तरह " अपने आवेदन के जीवनकाल के लिए HttpClient का एक भी उदाहरण " पुन: उपयोग नहीं कर सकते हैं । और ASP.NET उन परिदृश्यों में से एक है - कोई "आवेदन का जीवनकाल" नहीं है, केवल एक अनुरोध के जीवन भर।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.