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 ...
随机推荐
- WiFi基础(五):802.11帧结构与WiFi控制帧、管理帧、数据帧
liwen01 2024.09.22 前言 前面介绍了 WiFi 的工作原理和 WiFi 的接入过程,这里将通过分析 WiFi 具体数据包结构,让你对 WiFi 工作原理和接入过程有一个更进一步的了解 ...
- bpftool使用方法简介
1.安装bpftool工具 看起来,在不同的linux发行版里,bpftool在不同的软件包里,ubuntu 22上,bpftool是linux-tools-generic的一部分,而树莓派里bpft ...
- 深度解析Spring AI:请求与响应机制的核心逻辑
我们在前面的两个章节中基本上对Spring Boot 3版本的新变化进行了全面的回顾,以确保在接下来研究Spring AI时能够避免任何潜在的问题.今天,我们终于可以直接进入主题:Spring AI是 ...
- 三维医学图像深度学习,数据增强方法(monai):RandHistogramShiftD, Flipd, Rotate90d
#coding:utf-8 import torch from monai.transforms import Compose, RandHistogramShiftD, Flipd, Rotate9 ...
- harbor磁盘爆满,执行垃圾回收清理镜像
1.在使用Jenkins发版操作时发现,推送私有仓库harbor报错: received unexpected HTTP status: 500 Internal Server Error 2.想要登 ...
- KubeSphere 社区双周报|2024.09.27-10.10
KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书.新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列 ...
- 手写MSMQ微软消息队列收发工具类
一.MSMQ介绍 MSMQ(Microsoft Message Queuing)是微软开发的消息队列技术,支持事务,支持异步发送和接收消息. 两个重要的概念:队列和消息.队列是存放消息的容器和传输消息 ...
- 2022/1/25-2022牛客寒假算法基础集训营1B-炸鸡块君与FIFA22(线段树)
题目描述 热爱足球(仅限游戏)的炸鸡块君最近购买了FIFA22,并且沉迷于FIFA22的Rivals排位上分. 在该排位系统中,每局游戏可能有胜利(用W表示).失败(用L表示).平局(用D表示)三种结 ...
- AOT使用经验总结
一.引言 站长接触 AOT 已有 3 个月之久,此前在<好消息:NET 9 X86 AOT的突破 - 支持老旧Win7与XP环境>一文中就有所提及.在这段时间里,站长使用 Avalonia ...
- swiper 垂直滚动
<template> <div style="height: 100%;width: 100%;"> <swiper :direction=" ...