none
Webclient vs HttpClient RRS feed

  • Question

  • Our web app is running in .Net Framework 4.0. The UI calls controller methods through ajax calls.

    We need to consume REST service from our vendor. I am evaluating the best way to call REST service in .Net 4.0. The REST service requires Basic Authentication Scheme and it can return data in both XML and JSON. There is no requirement for uploading/downloading huge data and I don't see anything in future. I took a look at few open source code projects for REST consumption and didn't find any value in those to justify additional dependency in the project. Started to evaluate WebClient and HttpClient . I downloaded HttpClient for .Net 4.0 from NuGet.

    I searched for differences between WebClient and HttpClient and this site(http://blogs.k10world.com/technology/webclient-httpclient-consume-http-requests/) mentioned that single HttpClient can handle concurrent calls and it can reuse resolved DNS , cookie config and authentication. I am yet to see practical values that we may gain due to the differences.

    I did a quick perf. test to find how WebClient (Sync calls) , HttpClient (Sync and Async ) perform. and here are the results.

    using same HttpClient instance for all the requests

    WebClient Sync - 8 ms - 167 ms
    HttpClient Sync - 3 ms - 7228 ms
    HttpClient Async - 985 - 10405 ms
    

    Using new HttpClient for each request (min - max)

    WebClient Sync     4 ms - 297 ms
    HttpClient Sync    3 ms - 7953 ms
    HttpClient Async   1027 - 10834 ms
    

    Code

    {
    
        public class AHNData
        {
            public int i;
            public string str;
    
    
    
        }
        public class Program
        {
           public static HttpClient httpClient = new HttpClient();
            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 =>
               {
    
                   //Trace.Write(System.Threading.Thread.CurrentThread.ManagedThreadId + "-" + "Started");
                   using (WebClient client = new WebClient())
                   {
                       Stopwatch sw = Stopwatch.StartNew();
                       byte[] arr = client.DownloadData("http://localhost:9000/api/values/");
                       sw.Stop();
    
                      Trace.WriteLine("WebClient Sync " + sw.ElapsedMilliseconds.ToString());
                   }
               });
    
    
                Console.Read();
            }
    
            public static T GetDataFromWebClient<T>()
            {
                using (var webClient = new WebClient())
                {
                    webClient.BaseAddress = "http://localhost:9000/api/values/";
                    return JsonConvert.DeserializeObject <T> (webClient.DownloadString("http://localhost:9000/api/values/"));
                }
            }
    
    
            public static void GetDataFromHttpClientSync<T>(Stopwatch sw)
            {
    
                  HttpClient httpClient = new HttpClient();
    
                    var response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;
    
    
                    var obj= JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result);
                    sw.Stop();
    
                   Trace.WriteLine("HttpClient Sync " +  sw.ElapsedMilliseconds.ToString());
    
    
            }
    
    
            public static void GetDataFromHttpClientAsync<T>(Stopwatch sw)
            {
    
                    HttpClient httpClient = new HttpClient();
    
                    var response = httpClient.GetAsync("http://localhost:9000/api/values/").ContinueWith((a)=>{
    
                        JsonConvert.DeserializeObject<T>(a.Result.Content.ReadAsStringAsync().Result);
    
                        sw.Stop();
    
                       Trace.WriteLine("HttpClient Async "+  sw.ElapsedMilliseconds.ToString());
    
                    }, TaskContinuationOptions.None);
    
            }
    
        }
    }
    
    
    
    • My Questions

      1. The REST calls return in 3-4s which is acceptable. Calls to REST service are initiated in controller methods which gets invoked from ajax calls. To begin with , the calls run in a different thread and doesn't block UI. So, can I just stick with sync calls ?
      2. The above code was run in my localbox. In prod setup, DNS and proxy lookup will be involved. Is there any advantage of using Httpclient over WebClient?
      3. Is HttpClient concurrency better than WebClient ? From the test results, I see WebClient sync calls perform better.
      4. Will HttpClient be a better design choice if we upgrade to .Net 4.5? Performance is the key design factor.

    Note: I asked the same question in SO and one of the members said that GetDataFromHttpClientAsync is called first and might not benefit from caching. I reversed the order to

     1.WebClientSync

    2.HttpClientsync

    3. HttpClientAsync.

    The results were

     WebClient Sync 3ms - 79 ms

    HttpClientSync 3 ms - 7927ms

    HttpClientASync 380 ms - 1694 ms

    Still HttpClientAsync is a slow performer. Any thoughts?

    Monday, December 16, 2013 4:51 PM

All replies

  • The webclient is a browser and the httpclient isn't a brwser.  The HTTP client runs quicker becasue you don't have to put the results into a window.  From my experience, the webbrowser handlers also handles more of the protocols than the httpclient.  In many cases the webpbrowser will automatically handler the cookies while the httpclient you have to add the code for proxy server and cookies. 


    jdweng

    Monday, December 16, 2013 5:00 PM
  • From the test results above, I see HttpClient is slower . Can you please explain why you say 'HTTP client runs quicker becasue you don't have to put the results into a window' ?

    Thanks for your reply.

    Monday, December 16, 2013 5:09 PM
  • Are you using the document complete event to determine which method is quicker?  A webpage isn't completed until the document is completely downloaded which may occur after you get a 200 done status and the java code finishes executing.

    The webclient has to parse the data and update the browser window.  this may occur in the background mode.  When you use an IE (a browser) you will see that a webpage takes a while before the done appears in the lower left corner of the screen.  You may see some of the webpage in the browser before the done occurs.

    The httpclient will complete before the browser because it doesn't have to parse the data to the window.


    jdweng

    Monday, December 16, 2013 5:24 PM
  • The test code doesn't scrape a webpage. It calls a MVC method in http://localhost:9000/api/values/ .
    Monday, December 16, 2013 5:28 PM
  • The webclient could be running faster because it is using cookies while the httpclient isn't using cookies.  A webclient automtically handles cookies while the httpclient you have to add the code for the cookies.  When there aren't any cookies, the transfer will take longer. 

    jdweng

    Monday, December 16, 2013 5:33 PM
  • I am not very convinced that cookies are causing delay in this sample test. The test was conducted against localhost and http://localhost:9000/api/values/ returns a simple object. i confirmed through Fiddler that  no cookies are sent to client. 

    api/values/ is a simple MVC controller method that returns a simple object for the very purpose of testing.

    ArrayOfData xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/DM.Controllers">

    <Data>
    <d>15</d>
    <i>5</i>
    <str>hoo hoo</str>
    </Data>
    <Data>
    <d>16</d>
    <i>6</i>
    <str>yo yo</str>
    </Data>
    </ArrayOfData>



    Monday, December 16, 2013 7:59 PM
  • Joel what are you talking about?
    IE? Java? Browser windows updating?

    WebClient is NOT a browser. It is a .Net class. 
    Wednesday, December 18, 2013 1:19 AM