【问题标题】:How to create named client after startup?启动后如何创建命名客户端?
【发布时间】:2020-05-27 08:10:02
【问题描述】:

对于我的应用程序,我需要为 HttpRequests 创建一个命名客户端。我可以在 Startup 中创建一个命名客户端。为了访问它,我注入一个“IHttpClientFactory”并从中创建一个客户端。但是客户端需要有一个访问令牌作为授权标头,我无法在 Startup.xml 中创建令牌。因此,我需要一种在 Startup 类之外创建命名客户端的方法。我已经尝试将“IServiceCollection”注入控制器。但这不起作用。

或者有没有办法在启动时创建命名客户端后对其进行编辑?

【问题讨论】:

  • 您在哪里使用命名客户端?该服务不能添加令牌吗?
  • IServiceCollection 是预构建服务注册工具。你想注入IServiceProvider,虽然我不明白为什么这是必要的。以这种方式解决依赖关系是一种反模式。

标签: c# asp.net-core httpclient


【解决方案1】:

与@Ruben-J 发布的解决方案类似的解决方案是创建一个自定义 HttpMessageHandler,它在请求时为通过 HttpClient 发出的请求分配一个授权标头。

您可以创建一个自定义的 HttpMessageHandler,它可以像这样在 Startup 中分配给一个命名的 HttpClient:

public class YourHttpMessageHandler : DelegatingHandler
{
    private readonly IYourTokenProviderService _yourTokenProviderService;

    public YourHttpMessageHandler(IYourTokenProviderService yourTokenProviderService) 
        : base()
    {
        _yourTokenProviderService = yourTokenProviderService;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = SendAsyncWithAuthToken(request, cancellationToken);

        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            await _yourTokenProviderService.RefreshTokenAsync();

            response = SendAsyncWithAuthToken(request, cancellationToken);
        }

        return response;
    }

    private async Task<HttpResponseMessage> SendWithAuthTokenAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _yourTokenProviderService.Token);

        return await base.SendAsync(request, cancellationToken);
    }
}

然后您在 Startup 中配置您的服务并命名为​​ HttpClient:

public virtual void ConfigureServices(IServiceCollection services) 
{
    ...
    services.AddTransient<IYourTokenProviderService, YourTokenProviderService>();
    services.AddTransient<YourHttpMessageHandler>();

    services.AddHttpClient<IYourNamedHttpClient, YourNamedHttpClient>()
        .AddHttpMessageHandler<YourHttpMessageHandler>();
    ...
}

值得注意的是,Polly 的AddPolicyHandler 的当前实现也添加了自己的 DelegatingHandler。 有关更多背景信息,请参阅 Microsoft documentation on adding DelegatingHandler'sHere is also great series of articles from Steve Gordon.

【讨论】:

    【解决方案2】:

    您可以使用 Polly 向您的客户端添加策略处理程序。然后,如果请求返回 401 Unauthorized,您可以添加逻辑。因此,例如让您的服务使用客户端刷新不记名令牌并将其设置为当前请求。这只是一个快速的解决方案,也许还有更优雅的解决方案。但是,如果您的令牌过期,这也会派上用场。因为那么它会自动刷新。

    services.AddHttpClient("YourClient")
                .AddPolicyHandler((provider, request) =>
                {
                    return Policy.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized)
                        .RetryAsync(1, async (response, retryCount, context) =>
                        {
                            var service = provider.GetRequiredService<IYourService>();
                            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer",  await service.RefreshToken());
                        });
                });
    

    【讨论】:

    • 谢谢你,这很有帮助。假设当 HttpStatusCode 为“OK”时。我可以在响应中添加一个新的 HttpClient 吗?就像不是做 RetryAsync 我只会创建一个新的 HttpClient 并从响应中获取访问令牌。
    • 我会使用您已经在服务中注入的同一个 httpclient。并让它调用另一个 url 来获取新的令牌。无需创建另一个 httpclient。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多