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 ...
随机推荐
- argmax经过sigmoid和不经过sigmoid区别
起因 今天和同组讨论了一下网络输出时,在torch.argmax之前经过torch.sigmoid和不经过sigmoid的区别. 主要起因是实验结果图像不同 图1 不经过sigmoid 图2 经过si ...
- 5.flask 源码解析:请求
目录 一.flask 源码解析:请求 1.1 简介 1.2 请求 Flask 源码分析完整教程目录:https://www.cnblogs.com/nickchen121/p/14763457.htm ...
- Whizard:跨越 Thanos 从开源项目到生产就绪的鸿沟
此文是根据 KubeSphere 在 KubeCon China 2024 上的演讲分享整理而成. 议题简介 作为最受欢迎和强大的 Prometheus 长期存储项目之一,Thanos 被社区广泛采用 ...
- 云原生周刊:2024 年 K8s 基准报告 | 2024.4.8
开源项目推荐 Argo CD Image Updater Argo CD Image Updater 是一个自动更新 Argo CD 管理的 Kubernetes 工作负载容器镜像的工具.简而言之,它 ...
- 在 KubeSphere 中使用 APISIX Ingress 网关接入自定义监控
KubeSphere 3.2.0 发布了!为项目网关增配了整套监控及管理页面,同时引入了集群网关来提供集群层面全局的 Ingress 网关能力.当然,我们还是可以部署使用第三方 Ingress Con ...
- 快速部署sqlserver AlwaysOn集群
点击查看代码 丐版sqlserver集群 之前试过docker的,k8s的,然后发现,还是最朴素的是最简单的,希望有大佬能够汉化,他妈的,那些英文看得人要发癫啊. 前置准备,参照丐版pxc集群: ht ...
- Nuxt.js 应用中的 builder:generateApp 事件钩子详解
title: Nuxt.js 应用中的 builder:generateApp 事件钩子详解 date: 2024/10/23 updated: 2024/10/23 author: cmdragon ...
- C语言(从入门到入土)
1.C语言整体上需要记住的 总体上必须清楚的: 1)程序结构是三种: 顺序结构 , 循环结构 (三个循环结构), 选择结构 (if 和 switch) 2)读程序都要从main()入口, 然后从最上面 ...
- fiddler限速配置&mock配置
一.限速配置 1.开启性能选项 2.找到对应的参数入口 3.修改对应的从参数 解释下 这2个参数是如何做到限速的 4.request-trickle-delay(上传数据限制) 默认值是300,他的意 ...
- jsp页面访问数据库根据数据情况,定时弹出提醒
需求:根据数据库情况,在页面定时弹出相应的消息 实现: 1. 展示DIV设置 <script language="javascript" type="text/ja ...