HttpClientFactory in ASP.NET Core 2.1 Part 2:定义命名和类型化的客户端
HttpClientFactory in ASP.NET Core 2.1 Part 2:定义命名和类型化的客户端
原文地址:https://www.stevejgordon.co.uk/httpclientfactory-named-typed-clients-aspnetcore
上文介绍了 HttpClientFactory。我介绍了在创建功能的内幕,介绍了它帮助解决的问题,然后使用一个很基本的示例展示了如何在 WebAPI 应用中使用。本文我希望深入介绍使用它的两种方式:
- 命名客户端
- 类型化客户端
命名客户端
上文中,我介绍了如何使用 HttpClientFactory 来获取一的基础的 HttpClient 实例。当我们只是简单进行一次请求的时候也是可以的。但是,我们经常需要从代码的多个位置,多次访问同样的服务。
HttpClientFactory 通过命名客户端的方式使得更容易做到这一点。你可以创建一个包含一些特定配置的用来应用到创建 HttpClient 时的注册。你还可以注册多个命名客户端,它们使用不同的配置。
为了更具体一点。下面看一个示例,在 Startup 文件的 ConfigureServices() 方法中,我将使用 AddHttpClient() 扩展方法的另外重载方式,它接受两个附加的参数,一个名字和一个参数为 HttpClient 的 Action 委托,我的 ConfigureServices() 方法如下所示。
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("GitHubClient", client =>
{
client.BaseAddress = new Uri("https://api.github.com/");
client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactoryTesting");
});
services.AddMvc();
}
第一个参数是注册客户端的名称。Action<HttpClient> 委托支持我们在它构建的时候,配置 HttpClient 对象,它很顺手,因为可以预定义基本的访问地址,和一些已知的请求头,例如,当我们请求命名客户端的使用,每次新的实例将被创建,并如我们希望进行配置。
为使用它,在调用 CreateClient() 的时候,我们可以通过名称来请求客户端。
[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly IHttpClientFactory _httpClientFactory;
public ValuesController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public async Task<ActionResult> Get()
{
var client = _httpClientFactory.CreateClient("GitHubClient");
var result = await client.GetStringAsync("/");
return Ok(result);
}
}
在示例中,我们可以得到一个已经配置了基础访问地址的实例,所以在 GetStringAsync() 方法中,可以仅仅提供相对于基础地址的 URI 。
命名的方式在应用到客户端的配置之上给予一些控制,我不是对魔术字符串有很大兴趣,所以,对于命名客户端,我使用静态类包含字符串常量的方式。如下所示:
public static class NamedHttpClients
{
public const string GitHubClient = "GitHubClient";
}
在注册或者请求 HttpClient 的时候,我们可以使用静态类的值,而不是魔术字符串。
services.AddHttpClient(NamedHttpClients.GitHubClient, client =>
{
client.BaseAddress = new Uri("https://api.github.com/");
client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactoryTesting");
});
这样已经很好了,但是,我们可以进一步使用定制的类型化客户端。
类型化客户端
类型化的客户端允许我们使用定制的类,它可以构造函数注入到期待 HttpClient 的类中。它可以通过依赖注入系统,使用在 IHttpClientBuilder 上的扩展方法来封装,或者使用范型的 AddClientHttp() 来接受定制的类型。一旦我们拥有了自己定制的类型,我们既可以直接暴露出 HttpClient,或者在特定的方法中封装 Http 调用,更好地定义对外部服务的调用。该方式还意味着,我们不再需要魔术字符串,看起来更有意义。
我们看一个基本的示例,从我们定义定制的类型化 HttpClient 开始。
public class MyGitHubClient
{
public MyGitHubClient(HttpClient client)
{
Client = client;
}
public HttpClient Client { get; }
}
该类型需要接受一个 HttpClient 作为构造函数的参数。现在,我们设置一个公共属性来持有该 HttpClient 实例。
然后,需要在 ConfigureServices() 中如下进行服务注册:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<MyGitHubClient>(client =>
{
client.BaseAddress = new Uri("https://api.github.com/");
client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactoryTesting");
});
services.AddMvc();
}
通过将自定义类型 MyGitHubClient 类型作为范型参数传递给 AddHttpClient(),这将注册以瞬态作用域注册到容器中。由于我们的定制类型接受一个 HttpClient,它将使用适当的 HttpClient 注入到它中,在工厂中被创建。现在,我们可以更新控制器来接收我们类型化的客户端而不是 IHttpClientFactory 工厂。
[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly MyGitHubClient _gitHubClient;
public ValuesController(MyGitHubClient gitGitHubClient)
{
_gitHubClient = gitGitHubClient;
}
[HttpGet]
public async Task<ActionResult> Get()
{
var result = await _gitHubClient.Client.GetStringAsync("/");
return Ok(result);
}
}
由于我们定制的类型化客户端也通过属性暴露了 HttpClient,所以也可以直接使用它发出 Http 请求。
封装 HttpClient
在最终的示例中,我们专注于完全封装 HttpClient。该方式主要用于在我们希望在定义的方法中处理对端点的请求。此时,我们还希望能够封装对响应的验证,反序列化。所以希望在单个位置中的每个方法进行处理。
在此种情况下,我们保存在构造函数中注入的 HttpClient 到私有的只读字段中,与直接接收 HttpClient 相反,我们提供了 GetRootDataLength() 方法来执行 Http 调用,并返回响应的长度。通过简单的示例来使你了解思路。
public interface IMyGitHubClient
{
Task<int> GetRootDataLength();
}
public class MyGitHubClient : IMyGitHubClient
{
private readonly HttpClient _client;
public MyGitHubClient(HttpClient client)
{
_client = client;
}
public async Task<int> GetRootDataLength()
{
var data = await _client.GetStringAsync("/");
return data.Length;
}
}
我还更新了类型化客户端,使其从接口实现。我们可以更新控制器来接收并消费该接口。
[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly IMyGitHubClient _gitHubClient;
public ValuesController(IMyGitHubClient gitHubClient)
{
_gitHubClient = gitHubClient;
}
[HttpGet]
public async Task<ActionResult> Get()
{
var result = await _gitHubClient.GetRootDataLength();
return Ok(result);
}
}
现在我们可以根据接口的定义来调用 GetRootDataLength() 方法,不再需要直接操作 HttpClient,真正的闪光点在测试,在我们希望测试控制器的时候,我们可以模拟我们的 IMyGithubClient,测试 HttpClient 在以前是一个痛点,需要多行代码,通常我需要一套模拟。
在 ConfigureServices() 方法中注册到容器中。
services.AddHttpClient<IMyGitHubClient, MyGitHubClient>(client =>
{
client.BaseAddress = new Uri("https://api.github.com/");
client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactoryTesting");
});
AddHttpClient() 有一个可以接受两个范型参数的签名,并以适当的方式组织到容器中。
生成的客户端
IHttpClientFactory
可结合第三方库(例如 Refit)使用。 Refit 是.NET 的 REST 库。 它将 REST API 转换为实时接口。 RestService
动态生成该接口的实现,使用 HttpClient
进行外部 HTTP 调用。
定义了接口和答复来代表外部 API 及其响应:
C#复制
public interface IHelloClient
{
[Get("/helloworld")]
Task<Reply> GetMessageAsync();
}
public class Reply
{
public string Message { get; set; }
}
可以添加类型化客户端,使用 Refit 生成实现:
C#复制
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("hello", c =>
{
c.BaseAddress = new Uri("http://localhost:5000");
})
.AddTypedClient(c => Refit.RestService.For<IHelloClient>(c));
services.AddControllers();
}
可以在必要时使用定义的接口,以及由 DI 和 Refit 提供的实现:
C#复制
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IHelloClient _client;
public ValuesController(IHelloClient client)
{
_client = client;
}
[HttpGet("/")]
public async Task<ActionResult<Reply>> Index()
{
return await _client.GetMessageAsync();
}
}
总结
本文介绍了一些更高级的我们使用 HttpClientFactory 的方式,支持我们创建不同种类的命名配置的 HttpClient 实例。我们可以使用类型化的 HttpClient,通过扩展可以支持实现自定义的类,它接受一个 HttpClient 实例作为构造函数参数,还可以使用生成的 HttpClient 。
Part 1 – HttpClientFactory in ASP.NET Core 2.1 Part 1 介绍
Part 2 – HttpClientFactory in ASP.NET Core 2.1 Part 2:定义命名和类型化的客户端
Part 3 – HttpClientFactory in ASP.NET Core 2.1 Part 3: 对处理器使用对外请求中间件
Part 4 – HttpClientFacotry Part 4: 集成 Polly 处理瞬时失效
Part 5 – HttpClientFactory in ASP.NET Core 2.1 Part 5: 日志
HttpClientFactory in ASP.NET Core 2.1 Part 2:定义命名和类型化的客户端的更多相关文章
- ASP.NET Core的身份认证框架IdentityServer4(7)- 使用客户端证书控制API访问
前言 今天(2017-9-8,写于9.8,今天才发布)一口气连续把最后几篇IdentityServer4相关理论全部翻译完了,终于可以进入写代码的过程了,比较累.目前官方的文档和Demo以及一些相关组 ...
- [Asp.Net Core] Blazor Server Side 扩展用途 - 配合CEF来制作客户端浏览器软件
前言 大家用过微信PC端吧? 这是用浏览器做的. 用过Visual Studio Code吧? 也是用浏览器做的. 听说, 暴雪客户端也包含浏览器核心?? 在客户端启动一个浏览器, 并不是什么难事了. ...
- ASP.NET Core 中文文档 第二章 指南(2)用 Visual Studio 和 ASP.NET Core MVC 创建首个 Web API
原文:Building Your First Web API with ASP.NET Core MVC and Visual Studio 作者:Mike Wasson 和 Rick Anderso ...
- 【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)
HTTP is not just for serving up web pages. It's also a powerful platform for building APIs that expo ...
- asp.net core利用DI实现自定义用户系统,脱离ControllerBase.User
前言 很多时候其实我们并不需要asp.net core自带的那么复杂的用户系统,基于角色,各种概念,还得用EF Core,而且在web应用中都是把信息存储到cookie中进行通讯(我不喜欢放cooki ...
- Open ID Connect(OIDC)在 ASP.NET Core中的应用
我们在<ASP.NET Core项目实战的课程>第一章里面给identity server4做了一个全面的介绍和示例的练习 ,这篇文章是根据大家对OIDC遇到的一些常见问题整理得出. 本文 ...
- ASP.NET Core 2.2 十九. Action参数的映射与模型绑定
前文说道了Action的激活,这里有个关键的操作就是Action参数的映射与模型绑定,这里即涉及到简单的string.int等类型,也包含Json等复杂类型,本文详细分享一下这一过程.(ASP.NET ...
- [转]【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)
本文转自:https://www.cnblogs.com/inday/p/6288707.html HTTP is not just for serving up web pages. It’s al ...
- 【转】asp.net Core 系列【一】——创建Web应用
ASP.NET Core 中的 Razor 页面介绍 Razor 页面是 ASP.NET Core MVC 的一个新功能,它可以使基于页面的编码方式更简单高效. 若要查找使用模型视图控制器方法的教程, ...
- ASP.NET Core 2.2 十九. 你扔过来个json,我怎么接
原文:ASP.NET Core 2.2 十九. 你扔过来个json,我怎么接 前文说道了Action的激活,这里有个关键的操作就是Action参数的映射与模型绑定,这里即涉及到简单的string.in ...
随机推荐
- SuperMap iServer数据动态更新刷新地图与数据服务
更新:2022年6月27日 SuperMap iServer 11i 底层修改逻辑,增加智能指针.11i版本不需要以下操作即可实现 一.使用背景 有这么一个需求,后端也就通过SuperMap iDes ...
- balance_dirty_pages_ratelimited分析
balance_dirty_pages_ratelimited分析 nr_dirtied_pause:当前task的脏页门限: dirty_exceeded:全局的脏页数超过门限或者该bdi的脏页数超 ...
- .NET 白板书写预测-曲线拟合
白板软件书写速度是其最核心的功能,注册StylusPlugin从触摸线程拿触摸点数据并在另一UI线程绘制渲染是比较稳妥的方案,具体的可以查看小伙伴德熙的2019-1-28-WPF-高性能笔 - lin ...
- KubeSphere 3.1.1 发布,可以接入集群已有的 Prometheus
KubeSphere 作为一款面向应用的开源容器平台,经过 3 年的发展和 10 个版本的迭代,收获了两百多位开源贡献者,超过十万次下载,并有数千名社区用户用 KubeSphere 作为企业容器平台. ...
- 报名开启|QKE 容器引擎托管版暨容器生态发布会!
当下,"云原生"技术红利正吞噬旧秩序,重塑新世界. 但您的企业是否依然困惑:缺少运维人员或运维团队,想要专注于业务的开发,又不得不兼顾集群的日常运维:在生产环境中,为了保证业务的高 ...
- 分享一个大模型在请求api接口上的巧用
前言 自从Chatgpt横空出世以来,各种智能工具层出不穷,聊天.绘画.视频等各种工具帮助很多人高效的工作.作为一个开发者,目前常用应用包括代码自动填充,聊天助手等. 这些是工具层面的使用,有没有将大 ...
- Machine Learning Week_7 Support Vector Machines
目录 1 Large Margin Classification 1.1 Optimization Objective 1.1 Logistic Regresson 1.2 Cost 1.3 Supp ...
- 全面解释人工智能LLM模型的真实工作原理(二)
前一篇:<全面解释人工智能LLM模型的真实工作原理(一)> 序言:在上一篇文章中,我们从原理上构建了一个识别"叶子"和"花朵"的神经网络,并详细讲解 ...
- mongodb插入数据不能在vue显示
问题描述:当我们在命令行插入数据时,在MongoVUE却显示不了数据,并且查询有插入数据的数据库,如下图所示 网上资料说,这是引擎的问题,mongoDB3.2版本之后默认开启的存储引擎是wiredRi ...
- WPS Excel中配置下拉多选(VBA)
网上找到两种方案,一种利用数据选择其他单元格,也就是在其他单元格建数据.需求是模板,不合适 这里我用的VBA,踩了挺多坑,详细说下 首先更新WPS为最新版,确保可用VBA和JSA 确定使用VBA还是J ...