初始化
HttpClient位于System.Net.Http命名空间下,用于发送 HTTP 请求和接收来自通过 URI 确认的资源的 HTTP 响应。HttpClient设计意旨可共享实例,且在使用得当的情况下其实例是线程安全的。对于服务器端应用程序而言,如若为每个HTTP请求均创建一个新的HttpClient实例,则在系统压力较高的情况下可能造成socket端口被耗尽,并导致SocketException。所以,比较推荐的使用方式是利用static关键字创建一个可共享的实例。对于.Net Core2.1及以上版本的应用程序,还可以使用HttpClientFactory来创建共享的HttpClient实例。
public class DemoController: ApiController
{
private static readonly HttpClient client = new HttpClient();
... ...
}
在某些应用中,我们希望随请求一起发送一个默认凭据,以供资源服务进行身份验证。此时,可以通过设置HttpClientHandler.UseDefaultCredentials属性来实现。如果使用默认凭据,则为将该属性设置为 true;否则为 false。其默认值为 false。
var client = new HttpClient(
new HttpClientHandler {
UseDefaultCredentials = true,
}
);
发送HTTP请求
在利用HttpClient发送HTTP请求时,需要将请求的信息封装到一个HttpRequestMessage实例中,之后利用SendAsync方法进行发送。
public async Task GetAsync(string uri) {
using (var request = new HttpRequestMessage(HttpMethod.Get, uri))
{
using (var response = await client.SendAsync(request)
{
if (response.IsSuccessStatusCode) {
var dataString = response.Content.ReadAsString();
... ...
}
else {
Console.WriteLine($"{response.StatusCode}: {response.ReasePhrase}");
}
}
}
}
public async Task PostAsync(string uri, MyClass data) {
using (var request = new HttpRequestMessage(HttpMethod.Post, uri))
{
var json = JsonConvert.SerializeObject(data); // Newtonsoft.Json package is needed
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
using (var response = await client.SendAsync(request)
{
// do something
}
}
}
单元测试
为每一个public函数都提供相应的单元测试函数是一个良好的开发习惯,在为HttpClient相关的应用程序开发单元测试项目时,我们可以考虑通过internal的构造函数来根据需求设置相应的Mock的HttpClient实例,而发送真正的HTTP请求。而Mock的HttpClient可以通过自定义的HttpClientHandler来实现。
为了使单元测试project(假设名为Demo.Tests)可以访问业务逻辑project(假设名为Demo.Business)中的internal函数,我们需要在业务逻辑project的Properties下的AssemblyInfo.cs中为其开放访问权限。
[assembly: AssemblyTitle("Demo.Business")]
... ...
[assembly: InternalsVisibleTo("Demo.Tests")]
本文介绍了在.Net中如何初始化和利用HttpClient发送HTTP请求,强调了HttpClient实例的共享和线程安全,以及如何设置默认凭据。同时,讨论了在单元测试中如何模拟HttpClient的行为,以确保代码的健壮性。

被折叠的 条评论
为什么被折叠?



