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 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 performance 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 (min - max)
WebClient sync: 8 ms - 167 ms
HttpClient sync: 3 ms - 7228 ms
HttpClient async: 985 - 10405 ms
Using a 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();
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);
}
}
}
My Questions
- 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?
- 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
overWebClient
? - Is
HttpClient
concurrency better thanWebClient
? From the test results, I seeWebClient
sync calls perform better. - Will
HttpClient
be a better design choice if we upgrade to .Net 4.5? Performance is the key design factor.
HttpClient is the newer of the APIs and it has the benefits of
If you are writing a web service which is making REST calls to other web services, you should want to be using an async programming model for all your REST calls, so that you don't hit thread starvation. You probably also want to use the newest C# compiler which has async/await support.
Note: It isn't more performant AFAIK. It's probably somewhat similarly performant if you create a fair test.
I live in both the F# and Web API worlds.
There's a lot of good stuff happening with Web API, especially in the form of message handlers for security, etc.
I know mine is only one opinion, but I would only recommend use of
HttpClient
for any future work. Perhaps there's some way to leverage some of the other pieces coming out ofSystem.Net.Http
without using that assembly directly, but I cannot imagine how that would work at this time.Speaking of comparing these two
If you’re using .NET 4.5, please do use the async goodness with HttpClient that Microsoft provides to the developers. HttpClient is very symmetrical to the server side brethren of the HTTP those are HttpRequest and HttpResponse.
Update: 5 Reasons to use new HttpClient API:
Reference
C# 5.0 Joseph Albahari
(Channel9 — Video Build 2013)
Five Great Reasons to Use the New HttpClient API to Connect to Web Services
WebClient vs HttpClient vs HttpWebRequest
Firstly, I am not an authority on WebClient vs. HttpClient, specifically. Secondly, from your comments above, it seems to suggest that WebClient is Sync ONLY whereas HttpClient is both.
I see that as a huge difference when thinking for future, i.e. long running processes, responsive GUI, etc. (add to the benefit you suggest by framework 4.5 - which in my actual experience is hugely faster on IIS)