asp.net core为IHttpClientFactory添加动态命名配置

目录
  • 官方有什么推荐么?
  • IHttpClientFactory.CreateClient是如何将HttpClient创建出来的?
  • 扩展点一的实现
  • 扩展点二的实现
    • 使用
  • 总结一下

比如如何使用IHttpClientFactory动态添加cer证书

有三种方法推荐方法

  • 方法一: 推荐的做法是这样子
services.AddHttpClient("a业务").ConfigurePrimaryHttpMessageHandler(...a业务证书)
services.AddHttpClient("b业务").ConfigurePrimaryHttpMessageHandler(...b业务证书)
ServiceProvider.GetService<IHttpClientFactory>().CreateClient("a业务")....
  • 方法二:

如果你要完全自定义则可以用 new System.Net.Http.HttpClient(handler)

  • 方法三:

在或者用骚操作, 替换配置的方式也可以 逻辑就是实现一个自己的HttpClientFactoryOptions, 然后动态生成它.
get_cert_handler_by_name 是你自己的方法,可以根据任何是否使用区别业务名称a,b,c new 一个handler.
但是要注意, 这样子所有从ServiceProvider获取HttpClient都会走到这个自定义配置类上面, 要做好兼容性.

class MyClass : IPostConfigureOptions<HttpClientFactoryOptions>
        {
            public void PostConfigure(string name, HttpClientFactoryOptions options)
                => options.HttpMessageHandlerBuilderActions.Add(p => p.PrimaryHandler = get_cert_handler_by_name(name));
        }
//注册这个服务
services.AddSingleton<Microsoft.Extensions.Options.IPostConfigureOptions<Microsoft.Extensions.Http.HttpClientFactoryOptions>, MyClass>();

上述是一些前情概要, 那么接下来我们就来实现这个需求.

秒想到一个方法, 我们可以直接new HttpClient(), 在每一次要使用的时候都直接来一个, 简单粗暴.
秒想到第二个方法, 又或者用一个Dictionary<string,HttpClient>根据名字缓存client对象.
但是前者性能是个问题,而且涉及到端口的占用释放问题, 在调用量稍大的情况下得凉凉, 后者则是有已知的问题HttpClient对象没法感知dns的变更.

其他一些更不靠谱的方法还有: 使用代码配置方式(services.AddHttpClient("callback provider side").ConfigurePrimaryHttpMessageHandler())配置所有证书, 还有把所有证书都安装的本机上并设置为信任证书.

那么能除了上面这些不靠谱的方式(或者说有致命缺陷的方式), 还有靠谱的么, 那当然是有的, 例如运行时的动态配置实现方案.

所以, 接下来, 我来推荐 2 种方式式,就是我们的IHttpMessageHandlerBuilderFilterIPostConfigureOptions.

官方有什么推荐么?

针对如何为HttpClient对象添加证书, 官方文档的实现是:使用证书和来自 IHttpClientFactory 的命名 HttpClient 实现 HttpClient 和 使用证书和 HttpClientHandler 实现 HttpClient, 但是在这里显然没法解决我们的运行时配置的需求, 但是它给出了一条线索, 那就是命名配置. 它可以为我们的每一个不同的provider提供自定义配置. 只要我们能为每一个不同的provider能提供运行时配置即可, 接下来就是源码阅读时间了:

下文中的所有代码都来自netcore 3.1, 并且仅copy关键代码, 完整代码可以前往github查看.

IHttpClientFactory.CreateClient是如何将HttpClient创建出来的?

  • 每次CreateClient出来的都是一个新的HttpClient实例
  • CreateHandler中的_activeHandlers将为我们缓存我们的handler, 默认是2分钟(定义在HttpClientFactoryOptions.HandlerLifetime)
    • 这里有一个知识点就是如果我的请求刚好在过期时间前一点点获取到这个缓存的对象,就是有可能我当前的请求还在进行中, 但是2分钟过去后这个handler就要被回收的. 那官方是如何替我们解决这个可能的bug的呢, 请查看文章Cleaning up expired handlers, 我就不赘述了, 关键点在于用了一个WeakReference
  • CreateHandlerEntry方法则是真正的创建以及配置我们的handlers的地方.
    • IConfiguration获得一个HttpClientFactoryOptions对象
    • 应用 IHttpMessageHandlerBuilderFilter
    • 应用 HttpMessageHandlerBuilderActions
//Microsoft.Extensions.Http.DefaultHttpClientFactory
public HttpClient CreateClient(string name)
{
	HttpClient httpClient = new HttpClient(this.CreateHandler(name), disposeHandler: false);
	return httpClient;
}
public HttpMessageHandler CreateHandler(string name)
{
	ActiveHandlerTrackingEntry value = this._activeHandlers.GetOrAdd(name, this._entryFactory).Value;
        //_entryFactory可以直接理解为是CreateHandlerEntry方法.它真实的类型是Lazy<>(CreateHandlerEntry,LazyThreadSafetyMode.ExecutionAndPublication)的, 也就是并发安全的调用CreateHandlerEntry.
	return value.Handler;
}
internal ActiveHandlerTrackingEntry CreateHandlerEntry(string name)
{
        HttpClientFactoryOptions options = this._optionsMonitor.Get(name);
	HttpMessageHandlerBuilder requiredService = provider.GetRequiredService<HttpMessageHandlerBuilder>();
	requiredService.Name = name;
	Action<HttpMessageHandlerBuilder> action = Configure; // 扩展点二 HttpClientFactoryOptions.HttpMessageHandlerBuilderActions
	for (int num = this._filters.Length - 1; num >= 0; num--)
	{
		action = this._filters[num].Configure(action); //扩展点一 _filters(构造函数传入的IEnumerable<IHttpMessageHandlerBuilderFilter> filters).
	}
	action(requiredService);
	LifetimeTrackingHttpMessageHandler handler = new LifetimeTrackingHttpMessageHandler(requiredService.Build());
	return new ActiveHandlerTrackingEntry(name, handler, serviceScope, options.HandlerLifetime);

	void Configure(HttpMessageHandlerBuilder b)
	{
		for (int i = 0; i < options.HttpMessageHandlerBuilderActions.Count; i++)
		{
			options.HttpMessageHandlerBuilderActions[i](b);
		}
	}
}

关键点代码就是上面代码中标记出来的扩展点一 和 扩展点二.

  • 扩展点一: 需要注入适当的IHttpMessageHandlerBuilderFilter对象,就可以改写requiredService对象, 也就可以实现我们要的运行时动态配置了.
  • 扩展点二: 需要实现自定义的IConfiguration配置, 只要this._optionsMonitor.Get(name)拿到的对象的HttpMessageHandlerBuilderActions属性包含我们相应的改写代码即可.

扩展点一的实现

为HttpClient的handler增加一个配置的filter, 针对符合的handlerBuilder增加一些自己的改写逻辑.
我们在用HttpClient对象的时候产生的日志("Sending HTTP request......","Received HTTP response headers after......")就是由这个Filter特性注入的. 官方参考代码:LoggingHttpMessageHandlerBuilderFilter

个人见解: 觉得在这个扩展点加这个业务不是特别的符合应用场景, 所以我建议在扩展点二做这个事情.

class MyHttpClientHandlerFilter : IHttpMessageHandlerBuilderFilter
{
    public Action<HttpMessageHandlerBuilder> Configure(Action<HttpMessageHandlerBuilder> next)
    {
        void Configure(HttpMessageHandlerBuilder builder)
        {
            next(builder); //一开始就调用next, 这样我们的整个HandlerBuilder的执行顺序就是依次call _filters, 最后call options.HttpMessageHandlerBuilderActions(扩展点二).

            if (builder.Name.StartsWith("CallbackProviderSide-")) //我们可以为这类业务统一加一个前缀做区别, 这样就不会影响其他的HttpClient对象了.
            {
                //builder.PrimaryHandler= your custom handler. 参考官方文档的实现.
            }
        }
        return Configure;
    }
}
//然后在DI容器中注入我们的filter.
ServiceCollection.AddSingleton<IHttpMessageHandlerBuilderFilter,MyHttpClientHandlerFilter>();

扩展点二的实现

class MyHttpClientCustomConfigure : IPostConfigureOptions<HttpClientFactoryOptions>
{
    public void PostConfigure(string name, HttpClientFactoryOptions options)
    {
        if (name.StartsWith("CallbackProviderSide-")) //我们可以为这类业务统一加一个前缀做区别, 这样就不会影响其他的HttpClient对象了.
        {
            options.HttpMessageHandlerBuilderActions.Add(p =>
            {
                //p.PrimaryHandler= your custom handler. 参考官方文档的实现.
            });
        }
    }
}

//然后在DI容器中注入我们的这个配置扩展类.
ServiceCollection.AddSingleton<Microsoft.Extensions.Options.IPostConfigureOptions<Microsoft.Extensions.Http.HttpClientFactoryOptions>, MyHttpClientCustomConfigure>();

为什么这里注入的类型是Microsoft.Extensions.Options.IPostConfigureOptions<Microsoft.Extensions.Http.HttpClientFactoryOptions>, 是因为OptionsFactory它的构造函数需要的就是这个. 至于有关Configuration系统的扩展和源代码在这里就不在这里展开了.

使用

至于用它就简单了

var factory = ServiceProvider.GetService<IHttpClientFactory>();
var httpClientForBaidu = factory.CreateClient("CallbackProviderSide-baidu");
var httpClientForCnblogs = factory.CreateClient("CallbackProviderSide-Cnblogs");

总结一下

这样子, 我们的这个运行时动态配置HttpClient就算完成了, 我也轻轻松松又水了一篇文章.
另外,有关IHttpClientFactory背后的故事可以查看文章Exploring the code behind IHttpClientFactory in depth, 很完整的流程图在配上代码, 把它讲解的清清楚楚.

以上就是asp.net core为IHttpClientFactory添加动态命名配置的详细内容,更多关于asp.net core 添加动态命名配置的资料请关注我们其它相关文章!

(0)

相关推荐

  • asp.net core 使用 tensorflowjs实现 face recognition的源代码

    功能描述 上传照片文件名及是系统要识别标签或是照片的名称(人物标识) 提取照片脸部特征值(调用 facemesh模型) 保存特征值添加样本(调用 knnClassifier) 测试上传的图片是否识别正确 项目依赖的库 源代码(neozhu/smartadmin.core.urf: Domain Driven Design (DDD) ultra-lightweight rapid development architecture(support .net 5.0) (github.com)) t

  • asp.net core配合vue实现后端验证码逻辑

    目录 概述 部分原理 源码 概述 网上的前端验证码逻辑总感觉不安全,验证码建议还是使用后端配合验证. 如果产品确定可以上网的话,就可以使用腾讯,百度等第三方验证,对接方便.但是产品可能内网部署,就必须自己写了. 本文章就是基于这一点来实现的. 前端验证码显示一个图片,后端生成图片. 部分原理 1.前端调用生端获取图片时,传入一个roomID,后端生成一个4位验征码,放入redis中.然后生成一个图片返回. 2.前端显示图片,登录时将roomID和填写的验证码,一并提交,登录接口根据roomId从

  • Asp.net中UpdatePanel的用法详解

    Asp.net UpdatePanel 允许用户构建一个丰富的,以客户端为中心的应用程序,引用UpdatePanel控件,能够实现页面的部分刷新,一个包含scriptManage和 UpdatePanel控件的页面自动具有页面部分刷新的功能,不需要写任何的客户端JavaScript代码.一个web页面只能包含一个 ScriptManage控件,但可以包含一个或多个UpdatePanel控件. 使用UpdatePanel控件实现页面的局部更新,需要包含一个ScriptManage控件,并且必须将S

  • ASP.NET session.timeout设置案例详解

    session.timeout 方法一: asp.net Session的默认时间设置是20分钟,即超过20分钟后,服务器会自动放弃Session信息. 当我们在asp.net程序中打开webconfig的时候,可以看到一段如下的代码:Asp.net程序代码: sessionState节点放在<system.web>节点下,形式如下: configuration 元素(常规设置架构) system.web 元素(ASP.NET 设置架构) sessionState 元素(ASP.NET 设置架

  • ASP.NET Core如何实现简单的静态网站滚动更新

    目录 Intro FileProvider Construct Host Demo More 总结 Intro 最近我们老板想让我实现一个静态网站"滚动更新"的功能,其实就是希望网站部署的时候网站内容完整的切换,不能网站部署的过程中一部分是新的内容,另外一部分是老的内容. 这让我想到了微软的 Azure App Service,上家公司主要是用微软的云服务 Azure,站点是部署到 Azure App Service 上的,Azure App Service 有一个部署槽的概念,我们的

  • asp.net core为IHttpClientFactory添加动态命名配置

    目录 官方有什么推荐么? IHttpClientFactory.CreateClient是如何将HttpClient创建出来的? 扩展点一的实现 扩展点二的实现 使用 总结一下 比如如何使用IHttpClientFactory动态添加cer证书 有三种方法推荐方法 方法一: 推荐的做法是这样子 services.AddHttpClient("a业务").ConfigurePrimaryHttpMessageHandler(...a业务证书) services.AddHttpClient

  • 关于dotnet 替换 ASP.NET Core 的底层通讯为命名管道的 IPC 库的问题

    目录 背景 使用方法 服务端 客户端 这是一个用于本机多进程进行 IPC 通讯的库,此库的顶层 API 是采用 ASP.NET Core 的 MVC 框架,其底层通讯不是传统的走网络的方式,而是通过 dotnetCampus.Ipc 开源项目提供的基于 NamedPipeStream 命名管道的方式进行通讯.相当于替换掉 ASP.NET Core 的底层通讯方式,从走网络换成命名管道的方式.本库的优势是可以使用设计非常好的 ASP.NET Core 的 MVC 框架作为顶层调用 API 层,底层

  • ASP.NET Core使用IHttpClientFactory发出HTTP请求

    1.HttpClient类使用存在的问题 HttpClient类的使用所存在的问题,百度搜索的文章一大堆,好多都是单纯文字描述,让人感觉不太好理解,为了更好理解HttpClient使用存在的问题,下面让我们通过代码跟示例来描述. using(var client = new HttpClient()) 传统关闭连接方法如上述代码所示,但当使用using语句释放HttpClient对象的时候,套接字(socket)也不会立即释放,下面我们通过请求aspnetmonsters站点的示例来验证下: c

  • ASP.NET Core 6.0 添加 JWT 认证和授权功能

    目录 序言 相关名词 认证(Authentication) 基本步骤 1 安装 Nuget 包 2 准备配置信息 3 添加服务 4 调用中间件 5 JwtHelper 类实现 6 控制器配置 7 测试调用 授权(Authorization) 相关标签(Attribute) 授权方式 1 Policy(策略) 2 Role(角色) 3 Scheme(方案) 3 定义权限项 4 实现 Requirement 5 实现授权处理程序 Handler 6 添加授权处理程序 7 添加授权策略 8 控制器配置

  • ASP.Net Core MVC基础系列之获取配置信息

    这一节, 我们来讲解.Net Core 是怎么获取配置信息的. .Net Core配置信息来源主要有以下几种 1.appsettings.json文件 2. User Secrets 3. 环境变量 4. 命令行参数 5. 自定义XML等等 在我们上一节新建的项目中, 已经默认有appsettings.json文件了, 并且appsettings.json默认会加载到项目中来, 至于为什么会默认加载, 我们可以通过源码进行分析, VS2017反编译不好用, F12看不到完整的代码, 这里我使用I

  • 详解如何在ASP.NET Core中使用IHttpClientFactory

    利用IHttpClientFactory可以无缝创建HttpClient实例,避免手动管理它们的生命周期. 当使用ASP.Net Core开发应用程序时,可能经常需要通过HttpClient调用WebAPI的方法以检查终结点是否正常工作.要实现这一点,通常需要实例化HttpClient并使用该实例来调用你的方法.但是直接使用HttpClient也有一些缺点,主要与手动管理实例的生命周期有关. 你可以使用IHttpClientFactory创建HttpClient来避免这些问题.IHttpClie

  • 如何为asp.net core添加protobuf支持详解

    前言 在一些性能要求很高的应用中,使用protocol buffer序列化,优于Json.而且protocol buffer向后兼容的能力比较好. 由于Asp.net core 采用了全新的MiddleWare方式,因此使用protobuf序列化,只需要使用Protobuf-net修饰需要序列化的对象,并在MVC初始化的时候增加相应的Formatter就可以了. 没时间解释了,快上车. 通过NuGet获取Zaabee.AspNetCoreProtobuf Install-Package Zaab

  • 解析如何利用一个ASP.NET Core应用来发布静态文件

    虽然ASP.NET Core是一款"动态"的Web服务端框架,但是在很多情况下都需要处理针对静态文件的请求,最为常见的就是这对JavaScript脚本文件.CSS样式文件和图片文件的请求.针对不同格式的静态文件请求的处理,ASP.NET Core为我们提供了三个中间件,它们将是本系列文章论述的重点.不过在针对对它们展开介绍之前,我们照理通过一些简单的实例来体验一下如何在一个ASP.NET Core应用中发布静态文件. 目录 一.以Web的形式读取文件 二.浏览目录内容 三.显示默认页面

  • ASP.NET Core 使用Cookie验证身份的示例代码

    ASP.NET Core 1.x提供了通过Cookie 中间件将用户主体序列化为一个加密的Cookie,然后在后续请求中验证Cookie并重新创建主体,并将其分配给HttpContext.User属性.如果您要提供自己的登录界面和用户数据库,可以使用作为独立功能的Cookie中间件. ASP.NET Core 2.x的一个主要变化是不再存在Cookie中间件.取而代之的是在Startup.cs文件中的Configure方法中的调用UseAuthentication方法会添加设置HttpConte

  • ASP.NET Core中Cookie验证身份用法详解

    目录 添加配置 ASP.NETCore1.x ASP.NETCore2.x 创建身份认证Cookie ASP.NETCore1.x ASP.NETCore2.x Signingout(登出) ASP.NETCore1.x ASP.NETCore2.x 服务端变化反馈 ASP.NETCore1.x ASP.NETCore2.x Cookie设置选项 ASP.NETCore1.x ASP.NETCore2.x 持久Cookie ASP.NETCore1.x ASP.NETCore2.x 绝对到期时间

随机推荐