我偶然发现了一个特殊的情况,我想要构建的命名
HttpClient
是使用异步函数运行的,如下所示:
services.AddHttpClient("customClient", async (serviceProvider, httpClient) => {...});
然后当我尝试从我想要使用它的服务中的
IHttpClientFactory
实例中调用它时,如下所示:
//Constructor start
this.httpClient = httpClientFactory.CreateClient("customClient");
//Constructor end
我最终得到了一个半途而废的
HttpClient
,其中设置了BaseAddress
但缺少DefaultRequestHeaders.Authorization
,尽管两者都在相同的AddHttpClient
异步函数中设置(但Authorization
标头仅在等待后设置) 1 次通话)。
所以我想知道,就像问题标题中那样:当
CreateClient(name)
被同步调用同时 HttpClient
设置是异步时会发生什么?
难道没有一种机制等待这种定义吗?从我的尝试来看,似乎并非如此。
所以我想知道,就像问题标题中那样:当同步调用 CreateClient(name) 同时 HttpClient 设置是异步时会发生什么?
设置不允许异步。如果您查看所有重载,它们都不会采用异步委托。
如果你仔细想想,这是有道理的。一般来说,依赖注入会拒绝异步初始化,因为如果它们允许它,那么每个依赖解析都必须被
await
编辑。
难道没有一种机制等待这种定义吗?从我的尝试来看,似乎并非如此。
不。常见的模式有:
我碰巧发现自己处于你的立场,并得出以下结论:身份验证设置永远不会发生在
services.AddHttpClient()
部分,而是在同一DI的下一行:.ConfigurePrimaryMessageHandler()
您将配置 NTLM/OAuth/等。在这里,如果您在同一位置设置令牌身份验证,读者会非常清楚会发生什么并且易于维护:
services.AddHttpClient("customClient", ...)
.ConfigurePrimaryMessageHandler((provider) =>
new TokenProviderMessageHandler(provider.GetRequiredService<ITokenAccessor>());
serviceProvider 仍然过载,您仍然依赖
IHttpClientFactory
,如果您将流程推迟到实际调用(异步),您甚至可以 await
:
/// <summary>Middleware for HttpClient calls</summary>
class TokenProviderMessageHandler : DelegatingHandler
{
string token;
readonly Task<string> tokenTask;
TokenProviderMessageHandler(ITokenAccessor accessor)
// inner handler is necessary, has the same scope (default PooledConnectionIdleTimeout = 2 minutes)
: base(new HttpClientHandler())
{
tokenTask = accessor.GetToken();
}
public async Task SendAsync(HttpRequestMessage request, CancellationToken cancellation)
{
token ??= await tokenTask;
// additional renew token logic could be here, depends on your iddletime between calls
request.Headers.Add(..., $"Bearer {token}");
return base.SendAsync(request, cancellation);
}
}