C# HttpClient与HttpWebRequest相比,具有更好的性能、安全性和更少的连接
我发现一个HttpClient可以被多个请求共享。如果是共享的,并且请求指向同一目标,则多个请求可以重用连接。WebRequest需要为每个请求重新创建连接 我还查阅了一些关于示例中使用HttpClient的其他方法的文档 以下文章总结了高速NTLM身份验证连接共享: 我尝试过的可能实现如下所示 (A) (B) (C)C# HttpClient与HttpWebRequest相比,具有更好的性能、安全性和更少的连接,c#,asp.net-web-api,httpwebrequest,httpclient,C#,Asp.net Web Api,Httpwebrequest,Httpclient,我发现一个HttpClient可以被多个请求共享。如果是共享的,并且请求指向同一目标,则多个请求可以重用连接。WebRequest需要为每个请求重新创建连接 我还查阅了一些关于示例中使用HttpClient的其他方法的文档 以下文章总结了高速NTLM身份验证连接共享: 我尝试过的可能实现如下所示 (A) (B) (C) 如果有人能帮助我了解我应该采取哪种方法来实现最高性能,我将不胜感激,最小化连接并确保安全性不受影响。如果将它们中的任何一个与async一起使用,从性能角度来看,这应该是好的,因
如果有人能帮助我了解我应该采取哪种方法来实现最高性能,我将不胜感激,最小化连接并确保安全性不受影响。如果将它们中的任何一个与async一起使用,从性能角度来看,这应该是好的,因为它不会阻塞等待响应的资源,并且您将获得良好的吞吐量 HttpClient优于HttpWebRequest,因为异步方法是现成的,您不必担心编写begin/end方法 基本上,当您使用async调用(使用任何一个类)时,它不会阻塞等待响应的资源,任何其他请求都会利用这些资源进行进一步的调用 要记住的另一件事是,您不应该在“using”块中使用HttpClient来允许对其他web请求重复使用相同的资源 有关更多信息,请参阅下面的线程
GetWebRequestHandler()
返回的实例的生存期很短(可能只是为了示例?)。如果是故意这样做的,它将否定对HttpClient
构造函数的第二个参数传递false
。false
的值告诉HttpClient不要处理底层的HttpMessageHandler
(这有助于扩展,因为它不会关闭请求的端口)。当然,这是假设HttpMessageHandler
的生命周期足够长,您可以利用不打开/关闭端口的好处(这对服务器的可伸缩性有很大影响)。因此,我有一个选项“D”的建议Httpclient
实例static
在所有api调用中重复使用。从内存分配和GC的角度来看,这比在客户端打开端口更有效。您没有为HttpClient
实例(及其所有底层对象)分配内存和创建内存的开销,因此也避免了通过GC对它们进行清理请参考我提供的关于类似问题的答案-这是我的ApicClient,它只创建了一次HttpClient。将此对象作为单例注册到依赖项注入库中。重复使用是安全的,因为它是无状态的。不要为每个请求重新创建HTTPClient。尽可能重用Httpclient
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
//You need to install package Newtonsoft.Json > https://www.nuget.org/packages/Newtonsoft.Json/
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
public class MyApiClient : IDisposable
{
private readonly TimeSpan _timeout;
private HttpClient _httpClient;
private HttpClientHandler _httpClientHandler;
private readonly string _baseUrl;
private const string ClientUserAgent = "my-api-client-v1";
private const string MediaTypeJson = "application/json";
public MyApiClient(string baseUrl, TimeSpan? timeout = null)
{
_baseUrl = NormalizeBaseUrl(baseUrl);
_timeout = timeout ?? TimeSpan.FromSeconds(90);
}
public async Task<string> PostAsync(string url, object input)
{
EnsureHttpClientCreated();
using (var requestContent = new StringContent(ConvertToJsonString(input), Encoding.UTF8, MediaTypeJson))
{
using (var response = await _httpClient.PostAsync(url, requestContent))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
}
public async Task<TResult> PostAsync<TResult>(string url, object input) where TResult : class, new()
{
var strResponse = await PostAsync(url, input);
return JsonConvert.DeserializeObject<TResult>(strResponse, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
public async Task<TResult> GetAsync<TResult>(string url) where TResult : class, new()
{
var strResponse = await GetAsync(url);
return JsonConvert.DeserializeObject<TResult>(strResponse, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
public async Task<string> GetAsync(string url)
{
EnsureHttpClientCreated();
using (var response = await _httpClient.GetAsync(url))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
public async Task<string> PutAsync(string url, object input)
{
return await PutAsync(url, new StringContent(JsonConvert.SerializeObject(input), Encoding.UTF8, MediaTypeJson));
}
public async Task<string> PutAsync(string url, HttpContent content)
{
EnsureHttpClientCreated();
using (var response = await _httpClient.PutAsync(url, content))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
public async Task<string> DeleteAsync(string url)
{
EnsureHttpClientCreated();
using (var response = await _httpClient.DeleteAsync(url))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
public void Dispose()
{
_httpClientHandler?.Dispose();
_httpClient?.Dispose();
}
private void CreateHttpClient()
{
_httpClientHandler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
};
_httpClient = new HttpClient(_httpClientHandler, false)
{
Timeout = _timeout
};
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(ClientUserAgent);
if (!string.IsNullOrWhiteSpace(_baseUrl))
{
_httpClient.BaseAddress = new Uri(_baseUrl);
}
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeJson));
}
private void EnsureHttpClientCreated()
{
if (_httpClient == null)
{
CreateHttpClient();
}
}
private static string ConvertToJsonString(object obj)
{
if (obj == null)
{
return string.Empty;
}
return JsonConvert.SerializeObject(obj, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
private static string NormalizeBaseUrl(string url)
{
return url.EndsWith("/") ? url : url + "/";
}
}
使用系统;
Net系统;
使用System.Net.Http;
使用System.Net.Http.Header;
使用系统文本;
使用System.Threading.Tasks;
//您需要安装软件包Newtonsoft.Json>https://www.nuget.org/packages/Newtonsoft.Json/
使用Newtonsoft.Json;
使用Newtonsoft.Json.Serialization;
公共类MyApicClient:IDisposable
{
专用只读时间间隔\u超时;
私有httpclientu HttpClient;
私人HttpClientHandler_HttpClientHandler;
私有只读字符串\u baseUrl;
private const string ClientUserAgent=“my-api-client-v1”;
私有常量字符串MediaTypeJson=“application/json”;
公共MyApicClient(字符串baseUrl,TimeSpan?timeout=null)
{
_baseUrl=NormalizeBaseUrl(baseUrl);
_超时=超时??从秒开始的时间跨度(90);
}
公共异步任务PostAsync(字符串url,对象输入)
{
确保已创建TTPClientCreated();
使用(var requestContent=newstringcontent(ConvertToJsonString(输入),Encoding.UTF8,MediaTypeJson))
{
使用(var response=wait_httpClient.PostAsync(url,requestContent))
{
response.EnsureSuccessStatusCode();
return wait response.Content.ReadAsStringAsync();
}
}
}
公共异步任务PostAsync(字符串url,对象输入),其中TResult:class,new()
{
var strResponse=等待后同步(url,输入);
返回JsonConvert.DeserializeObject(strResponse,新JsonSerializerSettings
{
ContractResolver=新的CamelCasePropertyNamesContractResolver()
});
}
公共异步任务GetAsync(字符串url),其中TResult:class,new()
{
var strResponse=await GetAsync(url);
返回JsonConvert.DeserializeObject(strResponse,新JsonSerializerSettings
{
ContractResolver=新的CamelCasePropertyNamesContractResolver()
});
}
公共异步任务GetAsync(字符串url)
{
确保已创建TTPClientCreated();
使用(var response=await_httpClient.GetAsync(url))
{
response.EnsureSuccessStatusCode();
return wait response.Content.ReadAsStringAsync();
}
}
公共异步任务PutAsync(字符串url,对象输入)
{
return wait-PutAsync(url,新的StringContent(JsonConvert.SerializeObject(输入),Encoding.UTF8,MediaTypeJson));
}
公共异步任务PutAsync(字符串url,HttpContent)
{
确保已创建TTPClientCreated();
使用(var response=wait_httpClient.PutAsync(url,内容))
{
response.EnsureSuccessStatusCode();
return wait response.Content.ReadAsStringAsync();
}
}
公共异步任务DeleteAsync(字符串url)
{
确保客户
using (HttpClient client = new HttpClient)
{
}
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("some uri string")
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
//You need to install package Newtonsoft.Json > https://www.nuget.org/packages/Newtonsoft.Json/
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
public class MyApiClient : IDisposable
{
private readonly TimeSpan _timeout;
private HttpClient _httpClient;
private HttpClientHandler _httpClientHandler;
private readonly string _baseUrl;
private const string ClientUserAgent = "my-api-client-v1";
private const string MediaTypeJson = "application/json";
public MyApiClient(string baseUrl, TimeSpan? timeout = null)
{
_baseUrl = NormalizeBaseUrl(baseUrl);
_timeout = timeout ?? TimeSpan.FromSeconds(90);
}
public async Task<string> PostAsync(string url, object input)
{
EnsureHttpClientCreated();
using (var requestContent = new StringContent(ConvertToJsonString(input), Encoding.UTF8, MediaTypeJson))
{
using (var response = await _httpClient.PostAsync(url, requestContent))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
}
public async Task<TResult> PostAsync<TResult>(string url, object input) where TResult : class, new()
{
var strResponse = await PostAsync(url, input);
return JsonConvert.DeserializeObject<TResult>(strResponse, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
public async Task<TResult> GetAsync<TResult>(string url) where TResult : class, new()
{
var strResponse = await GetAsync(url);
return JsonConvert.DeserializeObject<TResult>(strResponse, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
public async Task<string> GetAsync(string url)
{
EnsureHttpClientCreated();
using (var response = await _httpClient.GetAsync(url))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
public async Task<string> PutAsync(string url, object input)
{
return await PutAsync(url, new StringContent(JsonConvert.SerializeObject(input), Encoding.UTF8, MediaTypeJson));
}
public async Task<string> PutAsync(string url, HttpContent content)
{
EnsureHttpClientCreated();
using (var response = await _httpClient.PutAsync(url, content))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
public async Task<string> DeleteAsync(string url)
{
EnsureHttpClientCreated();
using (var response = await _httpClient.DeleteAsync(url))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
public void Dispose()
{
_httpClientHandler?.Dispose();
_httpClient?.Dispose();
}
private void CreateHttpClient()
{
_httpClientHandler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
};
_httpClient = new HttpClient(_httpClientHandler, false)
{
Timeout = _timeout
};
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(ClientUserAgent);
if (!string.IsNullOrWhiteSpace(_baseUrl))
{
_httpClient.BaseAddress = new Uri(_baseUrl);
}
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeJson));
}
private void EnsureHttpClientCreated()
{
if (_httpClient == null)
{
CreateHttpClient();
}
}
private static string ConvertToJsonString(object obj)
{
if (obj == null)
{
return string.Empty;
}
return JsonConvert.SerializeObject(obj, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
private static string NormalizeBaseUrl(string url)
{
return url.EndsWith("/") ? url : url + "/";
}
}
using ( var client = new MyApiClient("http://localhost:8080"))
{
var response = client.GetAsync("api/users/findByUsername?username=alper").Result;
var userResponse = client.GetAsync<MyUser>("api/users/findByUsername?username=alper").Result;
}