1

我正在开发一个 Blazor 项目,为了让我更容易理解这个问题,我们可以说我正在使用两种不同的服务来处理身份验证部分。它们与命名的 httpclient 一起注册在 configureservices 启动方法中。

services.AddHttpClient("XBOWServicesApi", c =>
{
c.BaseAddress = new Uri(XBOWServicesApi);
});

services.AddSingleton<IService1, Service1>();
services.AddSingleton<IService2, Service2>();

服务 1:包装 REST Api 中可用的所有功能。它使用通过实例化的 httpclientfactory 在构造函数中设置的 http 客户端。这需要使用 baseurl 和 Auth-header 进行设置才能工作。

public Service1(IHttpClientFactory clientFactory)
{
this.httpClient = clientFactory.CreateClient("XBOWServicesApi");
}

服务 2:使用自定义 AuthenticationStateProvider 处理登录/注销功能。它有自己的httpclient,所以我可以为http客户端设置Auth Header。构造函数的工作方式与服务 1 相同。

public Service2(IHttpClientFactory clientFactory)
{
this.httpClient = clientFactory.CreateClient("XBOWServicesApi");
}

这个建立的原因当然是我喜欢共享同一个 http 客户端,所以当它在 login/logout 方法中设置时,服务 1 在与 api 通信时将具有正确的 auth 标头。

但是,客户端工厂每次都提供一个新实例,所以这永远不会起作用。

任何想法如何处理这个?

/亨里克

4

3 回答 3

1

您可以使用named client

services.AddHttpClient("github", c =>
{
    c.BaseAddress = new Uri("https://api.github.com/");
    // Github API versioning
    c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
    // Github requires a user-agent
    c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});

之后,只需调用CreateClient具有相应name参数的方法。

var client = _clientFactory.CreateClient("github");

每次CreateClient调用:

  • 创建了一个新的 HttpClient 实例。
  • 调用配置操作。

您可以在此处的 Microsoft 文档中找到更多详细信息。

于 2020-04-20T12:12:22.017 回答
0

您可以使用 HttpMessageHandlers 在瞬态 HttpClients 之间共享作用域服务。

IHttpClient.CreateClient每次返回一个新的实例,但你可以注册一个HttpMessageHandler,如下所示:

services.AddScoped<HandlerData>();
services.AddTransient<HeaderHandler>();
services.AddHttpClient("XBOWServicesApi", c =>
{
c.BaseAddress = new Uri(XBOWServicesApi);
}).AddHttpMessageHandler<HeaderHandler>();

HeaderHandler 类:

public class HeaderHandler : DelegatingHandler
{
    private readonly IHttpContextAccessor httpContextAccessor;
    public HeaderHandler(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken )
    {
        var Data= this.httpContextAccessor.HttpContext.RequestServices.GetRequiredService<HandlerData>();
        request.Headers.Add(Data.HeaderName, Data.HeaderValue);
        return base.SendAsync(request, cancellationToken);
    }
}

处理程序数据类:

public class HandlerData
{
    public string HeaderName { get; set; }
    public string HeaderValue { get; set; }
}

服务代码:

public Service1(IHttpClientFactory clientFactory, HandlerData data)
{
    data.HeaderName = "Header1";
    data.HeaderValue = "Value";
    this.httpClient = clientFactory.CreateClient("XBOWServicesApi");
}
public Service2(IHttpClientFactory clientFactory)
{
    //This will contain the same headers as Service1 as HandlerData is Scoped Service
    this.httpClient = clientFactory.CreateClient("XBOWServicesApi");
}

或者,IHttpMessageHandlerFactory如果您需要创建与请求相同的 DI 范围内的处理程序,您也可以使用 new:

参考:https ://github.com/aspnet/HttpClientFactory/issues/166

于 2020-04-20T18:19:45.477 回答
0

当我阅读Microsoft IHttpClientFactory 文档时:

每次从 IHttpClientFactory 获取 HttpClient 对象时,都会返回一个新实例。但是每个 HttpClient 使用一个由 IHttpClientFactory 汇集和重用的 HttpMessageHandler 来减少资源消耗,只要 HttpMessageHandler 的生命周期没有过期。

这是否回答你的问题?

于 2020-04-20T12:04:37.133 回答