我们的 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
我搜索了和之间的区别WebClient,这个站点提到单个 HttpClient 可以处理并发调用,它可以重用解析的 DNS、cookie 配置和身份验证。我还没有看到我们可能因差异而获得的实际价值。HttpClient
我进行了快速性能测试以了解WebClient(同步调用)、HttpClient(同步和异步)的执行情况。结果如下:
HttpClient对所有请求使用相同的实例(最小 - 最大)
WebClient 同步:8 毫秒 - 167 毫秒 HttpClient 同步:3 毫秒 - 7228 毫秒 HttpClient 异步:985 - 10405 毫秒
HttpClient为每个请求使用一个新的(最小 - 最大)
WebClient 同步:4 毫秒 - 297 毫秒 HttpClient 同步:3 毫秒 - 7953 毫秒 HttpClient 异步:1027 - 10834 毫秒
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); } } }
HttpClient 是较新的 API,它具有以下优点:
如果您正在编写一个对其他 Web 服务进行 REST 调用的 Web 服务,您应该希望对所有 REST 调用使用异步编程模型,这样您就不会遇到线程不足的问题。您可能还想使用支持 async/await 的最新 C# 编译器。
注意:它不是更高性能的 AFAIK。如果您创建一个公平的测试,它可能有点类似的性能。