.NET Core 3.0之深入源码理解HttpClientFactory(二)

简介: .NET Core 3.0之深入源码理解HttpClientFactory(二)写在前面上一篇文章讨论了通过在ConfigureServices中调用services.AddHttpClient()方法,并基于此进一步探讨了DefaultHttpClientFactory是如何创建HttpClie...

.NET Core 3.0之深入源码理解HttpClientFactory(二)
写在前面
上一篇文章讨论了通过在ConfigureServices中调用services.AddHttpClient()方法,并基于此进一步探讨了DefaultHttpClientFactory是如何创建HttpClient实例和HttpMessageHandler实例的,并了解了DefaultHttpClientFactory内部维护者一个定时器和两个HttpMessageHandler对象集合,以定期清理无效的 HttpMessageHandler对象,详细的内容可以点击链接跳转,接下来我会接着前一篇文章继续展开相关讨论。

详细介绍
HttpMessageHandlerBuilder
该类是一个抽象类,起到生成器的作用,可用于用于配置HttpMessageHandler实例。HttpMessageHandlerBuilder会在ServiceCollection中被注册为Transient服务。调用方要为每个要创建的HttpMessageHandler实例检索一个新实例。实现者应该确保每个实例都只使用一次。

HttpMessageHandlerBuilder里面有三个比较重要的属性:

1: ///
2: /// 主HttpMessageHandler实例
3: ///
4: public abstract HttpMessageHandler PrimaryHandler { get; set; }
5:
6: ///
7: /// 这个是一个附加实例,用于配置HttpClient管道
8: ///
9: public abstract IList AdditionalHandlers { get; }
10:
11: ///
12: /// 可用于从依赖项注入容器解析服务的IServiceProvider
13: ///
14: public virtual IServiceProvider Services { get; }
这三个属性意味着每个HttpMessageHandlerBuilder都需要维护自身的HttpMessageHandler实例和管道。

其内部还有一个抽象方法:

1: public abstract HttpMessageHandler Build();
当然,内部最核心的方法就是管道的创建过程了,需要传入主派生类自身的HttpMessageHandler和管道列表对象。它会将primaryHandler实例付给管道列表的第一个Item的InnerHandler,其他对象会依此后移,这也为我们自定义HttpMessageHandler(各种中间件)提供了无限可能。

相关实现如下:

1: var next = primaryHandler;
2: for (var i = additionalHandlersList.Count - 1; i >= 0; i--)
3: {
4: var handler = additionalHandlersList[i];
5: if (handler == null)
6: {
7: var message = Resources.FormatHttpMessageHandlerBuilder_AdditionalHandlerIsNull(nameof(additionalHandlers));
8: throw new InvalidOperationException(message);
9: }
10:
11: if (handler.InnerHandler != null)
12: {
13: var message = Resources.FormatHttpMessageHandlerBuilder_AdditionHandlerIsInvalid(
14: nameof(DelegatingHandler.InnerHandler),
15: nameof(DelegatingHandler),
16: nameof(HttpMessageHandlerBuilder),
17: Environment.NewLine,
18: handler);
19: throw new InvalidOperationException(message);
20: }
21:
22: handler.InnerHandler = next;
23: next = handler;
24: }
接下来我们看一下HttpMessageHandlerBuilder一个派生类DefaultHttpMessageHandlerBuilder,其构造函数会传入IServiceProvider实例,我们的自定义操作也可以参照这个类。

关于Build方法的实现如下,比较简单主要是调用了CreateHandlerPipeline方法:

1: public override HttpMessageHandler Build()
2: {
3: if (PrimaryHandler == null)
4: {
5: var message = Resources.FormatHttpMessageHandlerBuilder_PrimaryHandlerIsNull(nameof(PrimaryHandler));
6: throw new InvalidOperationException(message);
7: }
8:
9: return CreateHandlerPipeline(PrimaryHandler, AdditionalHandlers);
10: }
ITypedHttpClientFactory
这是一个抽象工厂,该组件可以使用给定逻辑名称的自定义配置创建类型化HttpClient实例,与命名方式创建HttpClient具有相同的的功能。类型化客户端可能用于单个后端终结点,并封装此终结点的所有处理逻辑。 另一个优势是它们使用 DI 被注入到应用中需要的位置,下一篇文章会再次讨论相关功能。

我们首先看一下调用方式:

1: public static IHttpClientBuilder AddHttpClient(this IServiceCollection services)
2: where TClient : class
3: {
4: if (services == null)
5: {
6: throw new ArgumentNullException(nameof(services));
7: }
8:
9: AddHttpClient(services);
10:
11: var name = TypeNameHelper.GetTypeDisplayName(typeof(TClient), fullName: false);
12: var builder = new DefaultHttpClientBuilder(services, name);
13: builder.AddTypedClient();
14: return builder;
15: }
可以看出此处的调用与普通的HttpClient没有什么太大区别,只是增加了一个泛型标记,而且该类型没有特殊的要求,只要是个类就行。其内部依然调用AddHttpClient(services),但它调用了另一个扩展方法,如下所示:

1: public static IHttpClientBuilder AddTypedClient(this IHttpClientBuilder builder)
2: where TClient : class
3: {
4: if (builder == null)
5: {
6: throw new ArgumentNullException(nameof(builder));
7: }
8:
9: builder.Services.AddTransient(s =>
10: {
11: var httpClientFactory = s.GetRequiredService();
12: var httpClient = httpClientFactory.CreateClient(builder.Name);
13:
14: var typedClientFactory = s.GetRequiredService>();
15: return typedClientFactory.CreateClient(httpClient);
16: });
17:
18: return builder;
19: }
可以看到最终的代码调用了ITypedHttpClientFactory的CreateClient方法,Microsoft.Extensions.Http包中有一个默认的ITypedHttpClientFactory派生类,DefaultTypedHttpClientFactory,该类提供了了构造函数用于接收IServiceProvider实例,以及一个内部类声明的缓存对象,该对象十分重要,它被注册为singleton类型,已达到全局使用,并可以充当相关实例激活时的对象池。它也允许它的外部类注册为transient,这样它就不会在应用根服务提供程序上被关掉了。

相关代码如下:

1: public TClient CreateClient(HttpClient httpClient)
2: {
3: if (httpClient == null)
4: {
5: throw new ArgumentNullException(nameof(httpClient));
6: }
7:
8: return (TClient)_cache.Activator(_services, new object[] { httpClient });
9: }
内部缓存对象:

1: public class Cache
2: {
3: private readonly static Func _createActivator = () => ActivatorUtilities.CreateFactory(typeof(TClient), new Type[] { typeof(HttpClient), });
4:
5: private ObjectFactory _activator;
6: private bool _initialized;
7: private object _lock;
8:
9: public ObjectFactory Activator => LazyInitializer.EnsureInitialized(
10: ref _activator,
11: ref _initialized,
12: ref _lock,
13: _createActivator);
14: }
最后我们看一下源码中提供的范例:

1: class ExampleClient
2: {
3: private readonly HttpClient _httpClient;
4: private readonly ILogger _logger;
5: // typed clients can use constructor injection to access additional services
6: public ExampleClient(HttpClient httpClient, ILogger logger)
7: {
8: _httpClient = httpClient;
9: _logger = logger;
10: }
11: // typed clients can expose the HttpClient for application code to call directly
12: public HttpClient HttpClient => _httpClient;
13: // typed clients can also define methods that abstract usage of the HttpClient
14: public async Task SendHelloRequest()
15: {
16: var response = await _httpClient.GetAsync("/helloworld");
17: response.EnsureSuccessStatusCode();
18: }
19: }
20: //This sample shows how to consume a typed client from an ASP.NET Core middleware.
21: public void Configure(IApplicationBuilder app, ExampleClient exampleClient)
22: {
23: app.Run(async (context) =>
24: {
25: var response = await _exampleClient.GetAsync("/helloworld");
26: await context.Response.WriteAsync("Remote server said: ");
27: await response.Content.CopyToAsync(context.Response.Body);
28: });
29: }
30: //This sample shows how to consume a typed client from an ASP.NET Core MVC Controller.
31: public class HomeController : ControllerBase(IApplicationBuilder app, ExampleClient exampleClient)
32: {
33: private readonly ExampleClient _exampleClient;
34: public HomeController(ExampleClient exampleClient)
35: {
36: _exampleClient = exampleClient;
37: }
38: public async Task Index()
39: {
40: var response = await _exampleClient.GetAsync("/helloworld");
41: var text = await response.Content.ReadAsStringAsync();
42: return Content("Remote server said: " + text, "text/plain");
43: };
44: }
以上为本篇文章的主要内容,希望大家多提意见,如果喜欢记得点个推荐哦

作者: 艾心

出处: https://www.cnblogs.com/edison0621/

相关文章
|
22天前
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:<https://github.com/khellang/Scrutor>
39 5
|
3月前
|
存储 开发框架 JSON
ASP.NET Core OData 9 正式发布
【10月更文挑战第8天】Microsoft 在 2024 年 8 月 30 日宣布推出 ASP.NET Core OData 9,此版本与 .NET 8 的 OData 库保持一致,改进了数据编码以符合 OData 规范,并放弃了对旧版 .NET Framework 的支持,仅支持 .NET 8 及更高版本。新版本引入了更快的 JSON 编写器 `System.Text.UTF8JsonWriter`,优化了内存使用和序列化速度。
100 0
|
2月前
|
开发框架 .NET C#
在 ASP.NET Core 中创建 gRPC 客户端和服务器
本文介绍了如何使用 gRPC 框架搭建一个简单的“Hello World”示例。首先创建了一个名为 GrpcDemo 的解决方案,其中包含一个 gRPC 服务端项目 GrpcServer 和一个客户端项目 GrpcClient。服务端通过定义 `greeter.proto` 文件中的服务和消息类型,实现了一个简单的问候服务 `GreeterService`。客户端则通过 gRPC 客户端库连接到服务端并调用其 `SayHello` 方法,展示了 gRPC 在 C# 中的基本使用方法。
46 5
在 ASP.NET Core 中创建 gRPC 客户端和服务器
|
30天前
|
开发框架 缓存 .NET
GraphQL 与 ASP.NET Core 集成:从入门到精通
本文详细介绍了如何在ASP.NET Core中集成GraphQL,包括安装必要的NuGet包、创建GraphQL Schema、配置GraphQL服务等步骤。同时,文章还探讨了常见问题及其解决方法,如处理复杂查询、错误处理、性能优化和实现认证授权等,旨在帮助开发者构建灵活且高效的API。
27 3
|
7天前
|
开发框架 算法 中间件
ASP.NET Core 中的速率限制中间件
在ASP.NET Core中,速率限制中间件用于控制客户端请求速率,防止服务器过载并提高安全性。通过`AddRateLimiter`注册服务,并配置不同策略如固定窗口、滑动窗口、令牌桶和并发限制。这些策略可在全局、控制器或动作级别应用,支持自定义响应处理。使用中间件`UseRateLimiter`启用限流功能,并可通过属性禁用特定控制器或动作的限流。这有助于有效保护API免受滥用和过载。 欢迎关注我的公众号:Net分享 (239字符)
25 0
|
4月前
|
开发框架 监控 前端开发
在 ASP.NET Core Web API 中使用操作筛选器统一处理通用操作
【9月更文挑战第27天】操作筛选器是ASP.NET Core MVC和Web API中的一种过滤器,可在操作方法执行前后运行代码,适用于日志记录、性能监控和验证等场景。通过实现`IActionFilter`接口的`OnActionExecuting`和`OnActionExecuted`方法,可以统一处理日志、验证及异常。创建并注册自定义筛选器类,能提升代码的可维护性和复用性。
|
4月前
|
开发框架 .NET 中间件
ASP.NET Core Web 开发浅谈
本文介绍ASP.NET Core,一个轻量级、开源的跨平台框架,专为构建高性能Web应用设计。通过简单步骤,你将学会创建首个Web应用。文章还深入探讨了路由配置、依赖注入及安全性配置等常见问题,并提供了实用示例代码以助于理解与避免错误,帮助开发者更好地掌握ASP.NET Core的核心概念。
117 3
|
3月前
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架
|
4月前
|
开发框架 NoSQL .NET
利用分布式锁在ASP.NET Core中实现防抖
【9月更文挑战第5天】在 ASP.NET Core 中,可通过分布式锁实现防抖功能,仅处理连续相同请求中的首个请求,其余请求返回 204 No Content,直至锁释放。具体步骤包括:安装分布式锁库如 `StackExchange.Redis`;创建分布式锁服务接口及其实现;构建防抖中间件;并在 `Startup.cs` 中注册相关服务和中间件。这一机制有效避免了短时间内重复操作的问题。
|
5月前
|
开发框架 监控 .NET
开发者的革新利器:ASP.NET Core实战指南,构建未来Web应用的高效之道
【8月更文挑战第28天】本文探讨了如何利用ASP.NET Core构建高效、可扩展的Web应用。ASP.NET Core是一个开源、跨平台的框架,具有依赖注入、配置管理等特性。文章详细介绍了项目结构规划、依赖注入配置、中间件使用及性能优化方法,并讨论了安全性、可扩展性以及容器化的重要性。通过这些技术要点,开发者能够快速构建出符合现代Web应用需求的应用程序。
79 0