我们的web应用程序运行在。net Framework 4.0中。UI通过Ajax调用调用控制器方法。
我们需要使用来自供应商的REST服务。我正在评估在。net 4.0中调用REST服务的最佳方式。REST服务需要一个基本的身份验证方案,它可以返回XML和JSON两种格式的数据。
对上传/下载大数据没有任何要求,我认为未来也不会有任何要求。我查看了一些用于REST消费的开源代码项目,并没有发现它们有任何价值来证明项目中的额外依赖。我开始评估WebClient和HttpClient。我从NuGet下载了。net 4.0的HttpClient。
我搜索了WebClient和HttpClient之间的区别,这个网站提到单个HttpClient可以处理并发调用,它可以重用解析的DNS、cookie配置和身份验证。我还没有看到我们可能从这些差异中获得的实际价值。
我做了一个快速的性能测试,以了解WebClient(同步调用),HttpClient(同步和异步)的执行情况。结果如下:
我对所有请求使用相同的HttpClient实例(最小值-最大值)。
WebClient同步:8ms - 167 ms HttpClient同步:3ms - 7228 ms HttpClient async: 985 - 10405 ms
为每个请求(最小-最大)使用一个新的HttpClient:
WebClient同步:4ms - 297ms HttpClient同步: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);
}
}
}
我的问题
The REST calls return in 3-4 seconds which is acceptable. Calls to REST service are initiated in the controller methods which gets invoked from Ajax calls. To begin with, the calls runs in a different thread and doesn't block the UI. So, can I just stick with synchronous calls? The above code was run in my localbox. In a production setup, DNS and proxy lookup will be involved. Is there an advantage of using HttpClient over WebClient? Is HttpClient concurrency better than WebClient? From the test results, I see WebClient synchronous calls perform better. Will HttpClient be a better design choice if we upgrade to .NET 4.5? Performance is the key design factor.