ASP.NET Core 2.1 中的 HttpClientFactory (Part 2) 定义命名化和类型化的客户端
原文:https://www.stevejgordon.co.uk/httpclientfactory-named-typed-clients-aspnetcore
发表于:2018年1月
上一篇文章《HttpClientFactory简介》我解释了创建该功能的原因。我们知道了它可以解决的问题,然后例举了一个非常基本的示例展示了如何在WebAPI应用程序中使用它。在这篇文章中,我想深入探讨另外两种可以使用它的方法:命名化客户端(named clients)和类型化客户端(typed clients)。
命名化客户端(Name Clients)
在第一篇文章中,我演示了如何使用HttpClientFactory来获取基本的HttpClient实例。当您只需要从单一位置发出快速请求时,这很好。但通常,您可能希望从代码中的多个位置向同一服务发出多个请求。
通过命名化客户端的概念,HttpClientFactory使这一点变得更容易。使用命名化客户端,您可以创建一个注册,其中包含在创建HttpClient时的一些特定配置。您可以注册多个命名化客户端,每个客户端都可以预先配置不同的设置。
为了让这个概念更具体一些,让我们看一个例子。在我的Startup.ConfigureServices方法中,使用AddHttpClient的不同重载方法,该方法接受两个附加参数。把一个名称和一个Action委托“告诉”HttpClient。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);
}
}
在这个例子中,我们创建的HttpClient实例已经有基本地址集(base address set),所以我们的GetStringAsync方法传入对应的URI即可。
这种命名化的方式使我们能够控制应用于HttpClient的配置。我不是“魔力字符串”的忠实粉丝,所以如果我使用命名客户端,我可能会有一个静态类,其中包含客户端名称的字符串常量。像这样:
public static class NamedHttpClients
{
public const string GitHubClient = "GitHubClient";
}
注册(或请求)客户端时,我们可以使用静态类值,而不是“魔力字符串”:
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");
});
这非常好,但我们可以更进一步,来看看如何使用自定义的类型化客户端。
类型化客户端(Typed Clients)
类型化客户端允许我们定义一个通过构造函数注入HttpClient的自定义类。这样我们可以使用IHttpClientBuilder的扩展方法链接DI系统,或者使用泛型AddHttpClient方法来接收自定义类型。一旦我们有了自定义类,我们就可以直接公开HttpClient,也可以将Http calls封装在特定方法中,从而更好地定义外部服务的使用。这种方法也意味着我们不再需要“魔术字符串”,并且看起来更加合理。
让我们看一个自定义类型化客户端的基本例子:
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。它在DI系统中被注册为transient scope。由于我们的自定义类接受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(Encapsulating the HttpClient)
最后一个例子是我们想要完全封装HttpClient的情况。当我们想要定义处理对端点的特定调用的方法时,最有可能使用此方法。此时,我们还可以在每个方法中封装响应和反序列化的验证,以便在单一位置处理它。
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;
}
}
这种情况下,我们通过private readonly字段存储了在构造中注入的HttpClient。与直接通过此类(class)获得HttpClient不同,我们提供了一个GetRootDataLength方法来执行Http调用并返回请求长度。一个简单的例子,但你应该已经明白了!
我们现在可以更新控制器以接受和使用接口,如下所示:
[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有点痛苦,按照我通常习惯的方式会有更多代码。
在DI容器中注册,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有一个接受两个泛型参数的签名,对应DI中的签名。
总结
在这篇文章中,我们探讨了HttpClientFactory一些更高级的方法,它允许我们使用特定的命名配置创建不同的HttpClient实例。然后我们讨论了使用类型化客户端,通过扩展实现了我们自己的类,它接受HttpClient实例。我们可以直接公开HttpClient,也可以将调用封装到此类中来访问远程端点。
下一篇文章,我们将讨论使用DelegatingHandlers来实现“传出请求中间件”( outgoing request middleware)的另一种模式。
ASP.NET Core 2.1 中的 HttpClientFactory (Part 2) 定义命名化和类型化的客户端的更多相关文章
- ASP.NET Core 2.1 中的 HttpClientFactory (Part 3) 使用Handler实现传出请求中间件
原文:https://www.stevejgordon.co.uk/httpclientfactory-aspnetcore-outgoing-request-middleware-pipeline- ...
- ASP.NET Core 2.1 中的 HttpClientFactory (Part 4) 整合Polly实现瞬时故障处理
原文:https://www.stevejgordon.co.uk/httpclientfactory-using-polly-for-transient-fault-handling发表于:2018 ...
- ASP.NET Core 2.1 中的 HttpClientFactory (Part 1) HttpClientFactory介绍
原文:https://www.stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore 发表于:2018年1月 ASP.NET ...
- .NET Core 2.1中的HttpClientFactory最佳实践
ASP.NET Core 2.1中出现一个新的HttpClientFactory功能, 它有助于解决开发人员在使用HttpClient实例从其应用程序发出外部Web请求时可能遇到的一些常见问题. 介绍 ...
- 在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务
在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务 https://procodeguide.com/programming/polly-in-aspnet-core ...
- ASP.NET Core HTTP 管道中的那些事儿
前言 马上2016年就要过去了,时间可是真快啊. 上次写完 Identity 系列之后,反响还不错,所以本来打算写一个 ASP.NET Core 中间件系列的,但是中间遇到了很多事情.首先是 NPOI ...
- ASP.NET Core 1.0 中的依赖项管理
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
- 在ASP.NET Core 1.0中如何发送邮件
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:目前.NET Core 1.0中并没有提供SMTP相关的类库,那么要如何从ASP.NE ...
- ASP.NET Core 1.0 中使用 Swagger 生成文档
github:https://github.com/domaindrivendev/Ahoy 之前文章有介绍在ASP.NET WebAPI 中使用Swagger生成文档,ASP.NET Core 1. ...
随机推荐
- 办公室上网慢原因排查 有人下载东西 设置行为管理 宽带分配设置独立下行宽带 TL-WVR1200L
办公室上网慢原因排查 有人下载东西 设置行为管理 宽带分配设置独立下行宽带
- vim脚本判断操作系统
Linux 和 Windows 通用配置 其实在配置文件中是可以通过逻辑代码判断平台做条件处理的,这样就可以实现一个配置文件两个个平台下共用了,判断逻辑如下: " ============= ...
- AdapterViewFlipper
使用AdapterViewFiller组件设置图片轮播,该组件可以自动切换view <?xml version="1.0" encoding="utf-8" ...
- js 实现复制粘贴
js 实现复制粘贴 <!DOCTYPE html> <html><head> <meta http-equiv="Content-Type" ...
- linux记录-docker配置mysql
docker部署mysql 1.拉取镜像 docker pull mysql 2.docker rm containerID 删除镜像iD 3.创建镜像 docker run --name=m ...
- 邪淫真正的可怕危害 (转自学佛网:http://www.xuefo.net/nr/article54/544414.html)
邪淫真正的可怕危害 邪淫的害处可能很快就显现,也可能是逐渐的表现出来.但往往后者的害处更大.因为当积累了多年的邪淫果报一旦显现,后悔就已经晚了. 我本人就是一个很好的例子.回想自己这40多年的日子,邪 ...
- mybatis 枚举typeHandler
枚举typeHandler 在绝大多数情况下,typeHandler因为枚举而使用,MyBatis已经定义了两个类作为枚举类型的支持,这两个类分别是: •EnumOrdinalTypeHandler. ...
- Redis应用场景梳理
缓存 作为Key-Value形态的内存数据库,Redis 最先会被想到的应用场景便是作为数据缓存.而使用 Redis 缓存数据非常简单,只需要通过string类型将序列化后的对象存起来即可,不过也有一 ...
- LODOP粒度TableRowThickNess合并行测试
之前的博文:LODOP打印table不切行TableRowThickNess. ,中是没有合并行等的表格,通过设置增大分页粒度,会找附近的表格线,然后根据表格线分页,避免了切行.如果有比较复杂的表格, ...
- LODOP中设置设置图片平铺水印,超文本透明
之前的博文:LODOP中平铺图片 文本项Repeat. 该博文中是平铺的图片,上面是文本.如果是图片add_print_image和add_print_text纯文本,这两个打印项设计的,可以直接通过 ...