ConfigureServices 中的 AddHttpContextAccessor 与每个 HttpClient

AddHttpContextAccessor in ConfigureServices vs per HttpClient

在 ConfigureServices 方法中添加一次 httpContextAccessor 与为每个配置的 HttpClient 添加 HttpContextAccessor 之间有什么区别吗?

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    // FIRST VERSION
    services.AddHttpContextAccessor();

    // SECOND VERSION
    var myService1 = services.AddHttpClient<TestHttpClient1>(c =>
    {
        c.BaseAddress = new Uri(Configuration["TestHttpClient1"]);
    });
    myService1.Services.AddHttpContextAccessor();

    var myService2 = services.AddHttpClient<TestHttpClient2>(c =>
    {
        c.BaseAddress = new Uri(Configuration["TestHttpClient2"]);
    });
    myService2.Services.AddHttpContextAccessor();
}

我的猜测是认为在第二个版本中,我们有两个单例,一个用于 class TestHttpClient1,另一个用于 TestHttpClient2,但我不明白为什么要这样做,因为我看到此代码正在生产中。

Is there any difference between adding the httpContextAccessor one time in ConfigureServices method versus adding the HttpContextAccessor per HttpClient configured.

不,没有任何区别。 myService1.ServicesmyService2.Services 都引用 相同的 IServiceCollection 作为 services 变量。第一次调用 (services.AddHttpContextAccessor()) 将注册服务,但接下来的两次调用 (myService1.Services.AddHttpContextAccessor()myService2.Services.AddHttpContextAccessor()) 将 no-op(什么都不做).

为了将所有这些都放在上下文中,这里是 AddHttpClient<TClient>(...) (source) 的源代码摘录:

var builder = new DefaultHttpClientBuilder(services, name);
// ...
return builder;

创建了一个新的DefaultHttpClientBuilder实例,它包裹了传入的IServiceCollection。因为这是一个扩展方法,所以这里的services指的是同一个services 和你的 ConfigureServices 方法一样。然后通过 IHttpClientBuilder.Services 公开,这就是您在引用时使用的内容,例如myService1.Services.

AddHttpContextAccessor 的调用使用 TryAddSingleton,只有在服务尚未注册时才会注册该服务 (source):

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

在您的示例中,它 已经在第一次调用 services.AddHttpContextAccessor() 时被注册,这意味着接下来的两次注册尝试什么都不做。