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 ...
随机推荐
- Uefi ABL读取XBL设置的标志位
PBL(启动固化程序)-> XBL(扩展引导加载程序,负责初始化芯片驱动和核心应用功能.XBL通常会加载一些平台相关的驱动程序,并提供通用接口)-> ABL(应用引导加载程序,负责引导操作 ...
- PostgreSQL 15 新特性解读 | 墨天轮优质文章合集
5月19日,PostgreSQL 全球开发组宣布 PostgreSQL 15 的第一个 beta 版本,这一新版本在开发者体验.性能表现等方面都有提升.为了帮助大家更快速了解到PostgreSQL 1 ...
- iOS使用SourceTree回滚回滚小结
代码回滚,适用于的场景: 1.提交错代码,想放弃刚刚提交的部分:2.代码发生冲突,处理比较麻烦,为了代码安全,直接回滚到之前干净的代码.我个人理解,可以分为本地回滚和远程回滚: 一.本地回滚,回滚自己 ...
- kotlin协程——>异常处理
异常处理 本节内容涵盖了异常处理与在异常上取消.我们已经知道取消协程会在挂起点抛出 CancellationException 并且它会被协程的机制所忽略.在这⾥我们会看看在取消过程中抛出异常或同 ⼀ ...
- 云原生爱好者周刊:使用 AWS 开源的 FireCracker 来创建和管理 K8s 集群
开源项目推荐 KubeFire 这个项目比较有创意,它使用 AWS 开源的轻量级虚拟化项目 FireCracker 来创建和管理 Kubernetes 集群,摒弃了传统的 qcow2 和 vhd 等虚 ...
- 麻将计分器微信小程序的开发
如何开发微信小程序 前言 因为最近沉迷和朋友们一起下班去打麻将,他们推荐了一个计分的小程序,就不需要每局都转账或者用扑克牌记录了,但是这个小程序不仅打开有广告,各个页面都植入了广告,用起来十分不适. ...
- c++11大括号初始化
C++11可以将{}初始化器用于任何类型(可以用等号,也可以不用) 数组.集合初始化 在C++11中,集合(列表)的初始化已经成为C++的一个基本功能,被称为"初始化列表": // ...
- MYSQL 批量删除以特定前缀开头的表
前言 这是工作中确实会用到,比如分库分表后有t_order_01.t_order_02.t_order_03...t_order_08 这样的表. 测试过程中造了大量数据进行测试,其中可能含有部分脏数 ...
- mysql清理异常字符
目前主要是清理 Mysql有时候会有一些异常字符导致数据导出失败. 发现异常字符的文字 通过如下脚本,数据库异常字符和正常字符的差异.得到异常字符的编号 SELECT hex(name),name,h ...
- 在react中使用阿里图标库
参考教程:https://blog.csdn.net/qq_41977441/article/details/110352463 阿里图标库:https://www.iconfont.cn/ 成果展示 ...