我们的网络应用程序在 .Net Framework 4.0 中运行.UI 通过 ajax 调用来调用控制器方法.
Our web app is running in .Net Framework 4.0. The UI calls controller methods through ajax calls.
我们需要使用供应商提供的 REST 服务.我正在评估在 .Net 4.0 中调用 REST 服务的最佳方式.REST 服务需要 Basic Authentication Scheme 并且它可以返回 XML 和 JSON 格式的数据.不需要上传/下载大量数据,将来我也看不到任何东西.我查看了一些用于 REST 消费的开源代码项目,但没有发现任何价值来证明项目中的额外依赖是合理的.开始评估 WebClient 和 HttpClient.我从 NuGet 下载了 .Net 4.0 的 HttpClient.
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.
我搜索了 WebClient 和 HttpClient 和 本站 提到单个 HttpClient 可以处理并发调用,并且可以重用解析的 DNS、cookie 配置和身份验证.我还没有看到我们可能因差异而获得的实用价值.
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.
我做了一个快速的性能测试,以了解 WebClient(同步调用)、HttpClient(同步和异步)的执行情况.结果如下:
I did a quick performance test to find how WebClient (sync calls), HttpClient (sync and async) perform. and here are the results:
对所有请求使用相同的 HttpClient 实例(最小 - 最大)
Using same HttpClient instance for all the requests (min - max)
WebClient 同步:8 毫秒 - 167 毫秒HttpClient 同步:3 毫秒 - 7228 毫秒HttpClient 异步:985 - 10405 毫秒
WebClient sync: 8 ms - 167 ms HttpClient sync: 3 ms - 7228 ms HttpClient async: 985 - 10405 ms
为每个请求使用新的 HttpClient(最小 - 最大)
Using a new HttpClient for each request (min - max)
WebClient 同步:4 毫秒 - 297 毫秒HttpClient 同步:3 毫秒 - 7953 毫秒HttpClient 异步:1027 - 10834 毫秒
WebClient sync: 4 ms - 297 ms HttpClient sync: 3 ms - 7953 ms HttpClient async: 1027 - 10834 ms
代码
public class AHNData { public int i; public string str; } public class Program { public static HttpClient httpClient = new HttpClient(); private static readonly string _url = "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); } } }我的问题
HttpClient 是较新的 API,它具有
HttpClient is the newer of the APIs and it has the benefits of
- 具有良好的异步编程模型
- 由 Henrik F Nielson 负责,他基本上是 HTTP 的发明者之一,他设计了 API,因此您可以轻松遵循 HTTP 标准,例如生成符合标准的标头
- 在 .Net 框架 4.5 中,因此在可预见的未来有一定程度的支持
- 如果您想在其他平台(.Net 4.0、Windows Phone 等)上使用它,还有该库的 xcopyable/portable-framework 版本.
如果您正在编写一个对其他 Web 服务进行 REST 调用的 Web 服务,您应该希望对所有 REST 调用使用异步编程模型,这样您就不会遇到线程饥饿.您可能还想使用支持 async/await 的最新 C# 编译器.
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.
注意:AFAIK 的性能并不高.如果您创建一个公平的测试,它的性能可能有点相似.
Note: It isn't more performant AFAIK. It's probably somewhat similarly performant if you create a fair test.
更多推荐
在 HttpClient 和 WebClient 之间做出决定
发布评论