gpt4 book ai didi

.net - HttpClient DelegatingHandler 意外的生命周期

转载 作者:行者123 更新时间:2023-12-01 22:29:07 24 4
gpt4 key购买 nike

在 ASP.NET Core 2.1 应用程序中,我使用 HttpClient 发出 REST 请求。我正在使用 DelegatingHandler 来定义一些常见行为。注册我在这里:

private static void AddRestServiceDataClient<TTypedHttpClient, TTypedHttpClientImpl>(this IServiceCollection services)
where TTypedHttpClient : class
where TTypedHttpClientImpl : RestServiceDataClient, TTypedHttpClient
{
var httpClientBuilder = services
.AddHttpClient<TTypedHttpClient, TTypedHttpClientImpl>()
.AddHttpMessageHandler<CachingHttpDelegatingHandler>()
.AddHttpMessageHandler<ExceptionHttpDelegatingHandler>()
.AddHttpMessageHandler<LoggingHttpDelegatingHandler>();
}

...

// EDIT: You should always register DelegatingHandlers as TRANSIENT (read answer for more).
services.AddScoped<ExceptionHttpDelegatingHandler>();
services.AddScoped<CachingHttpDelegatingHandler>();
services.AddScoped<LoggingHttpDelegatingHandler>();

我将DelegatingHandler注册为Scoped,但在两个不同的范围(请求)中我得到相同的DelegatingHandler。我的意思是 DelegationgHandler 的构造函数仅被调用一次,并且在更多请求中使用相同的实例(如单例)。其他一切都符合预期 - 其他服务、TypedHttpClients 和 HttpClient 的生命周期都正常。

我通过构造函数中的断点测试了所有内容,并且在每个实例中测试了 Guid,以便我可以区分实例。

当我将 DelegatingHandler 注册为 Transient 时,没有什么区别。

TL;DR DelegatingHandler 像单例一样解析,即使它们注册为作用域。这导致我的服务生活方式发生困惑。

最佳答案

经过一番调查,我发现尽管 DelegatingHandler 是通过依赖注入(inject)解决的,但 DelegatingHandler 的生命周期有点出乎意料,需要更深入的了解 .NET Core 2.1 中的 HttpClientFactory

HttpClientFactory 每次都会创建新的 HttpClient,但在多个 HttpClient 之间共享 HttpMessageHandler。有关此的更多信息,您可以在 Steve Gordon's article 中找到.

因为 DelegatingHandler 的实际实例保存在 HttpMessageHandler 内部(在 InnerHandler 属性中递归),并且 HttpMessageHandler 是共享,那么 DelegatingHandler 将以相同的方式共享,并且与共享的 HttpMessageHandler 具有相同的生命周期。

服务提供者在这里仅用于在HttpClientFactory“决定”时创建新的DelegatingHandler - 因此每个DelegatingHandler必须注册为 transient !否则你会得到不确定的行为。 HttpClientFactory 将尝试重用已使用的 DelegatingHandler

解决方法

如果需要在DelegatingHandler中解析依赖关系,可以在构造函数中解析IHttpContextAccessor,然后在httpContextAccessor中通过ServiceProvider解析依赖关系。 HttpContext.RequestServices.

这种方法并不完全是“架构上干净的”,但它是我发现的唯一解决方法。

示例:

internal class MyDelegatingHandler : DelegatingHandler
{
private readonly IHttpContextAccessor httpContextAccessor;

protected MyDelegatingHandler(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var serviceProvider = this.httpContextAccessor.HttpContext.RequestServices;
var myService = serviceProvider.GetRequiredService<IMyService>();
...
}
}

关于.net - HttpClient DelegatingHandler 意外的生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53223411/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com