asp.net IHttpClientFactory与services.AddHttpClient之间的关系

7xllpg7q  于 2023-10-21  发布在  .NET
关注(0)|答案(3)|浏览(99)

我在一家公司的BFF项目上工作。这就是为什么我们抛出这么多http调用。该项目使用.Net5编码。我看到在进行Http调用时使用了HttpClient,我想如果我使用IHttpClientFactory创建HttpClient会更好,以便在最佳实践中使套接字的使用更有效。
在启动文件中为HttpClients创建了这样一个DI

services.AddHttpClient<TClient, TImplementation>(c =>
                         {
                             c.BaseAddress = new Uri(settings.Url);
                             c.Timeout = settings.Timeout;
                         })
                         .ConfigurePrimaryHttpMessageHandler(sp => new DefaultHttpClientHandler())
                         .AddHttpMessageHandler<OutgoingRequestHandler>()
                         .AddHttpMessageHandler(serviceProvider =>
                             new TraceLogHandler(serviceProvider.GetRequiredService<ILogger<TraceLogHandler>>(), settings.Logging));

当我将鼠标悬停在AddHttpClient方法上时,我看到了以下解释:
将IHttpClientFactory和相关服务添加到IServiceCollection,并配置TClient类型和命名的HttpClient之间的绑定。客户端名称将被设置为TClient类型名称。

MyHttpClientBase.cs

   public class HttpClientBase<T>
    {
        private readonly HttpClient _httpClient;
        private readonly ILogger<T> _logger;

        public HttpClientBase(HttpClient httpClient, ILogger<T> logger)
        {
            _httpClient = httpClient;
            _logger = logger;
        }
   ...}
 

   myApiClient
   public class ApiClient : HttpClientBase<IApiClient>, IApiClient
    {
        public ApiClient(HttpClient httpClient, ILogger<IApiClient> logger)
            : base(httpClient, logger)
        {
        }
        ...
    }

我不明白在这种用法中,使用Socket管理我的IHttpClientFactory。还是与IHttpClientFactory集成使用?

1qczuiv0

1qczuiv01#

这个解释是完全正确的。你可以在official .NET repo中看到它的源代码:

public static IServiceCollection AddHttpClient(this IServiceCollection services)
{
    // ...
    
    // adds HttpClientFactory, HttpMessageHandlerFactory, HttpMessageHandlerBuilder
    services.TryAddTransient<HttpMessageHandlerBuilder, DefaultHttpMessageHandlerBuilder>();
    services.TryAddSingleton<DefaultHttpClientFactory>();
    services.TryAddSingleton<IHttpClientFactory>(serviceProvider => serviceProvider.GetRequiredService<DefaultHttpClientFactory>());
    services.TryAddSingleton<IHttpMessageHandlerFactory>(serviceProvider => serviceProvider.GetRequiredService<DefaultHttpClientFactory>());

    // ...
    
    return services;
}

public static IHttpClientBuilder AddHttpClient<TClient, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TImplementation>(
    this IServiceCollection services, string name)
    where TClient : class
    where TImplementation : class, TClient
{
    // ...

    AddHttpClient(services);

    // Creates named HttpClient for the exact TImplementation type, so the type will get only this HttpClient
    string name = TypeNameHelper.GetTypeDisplayName(typeof(TClient), fullName: false);
    var builder = new DefaultHttpClientBuilder(services, name);
    builder.ConfigureHttpClient(configureClient);
    builder.AddTypedClientCore<TClient, TImplementation>(validateSingleType: true);
    return builder;
}

客户端(以及更重要的底层处理程序)的创建和处理完全由HttpClientFactory控制,您不应该自己动手。这是微软推荐的方法。关于使用HttpClients in official guidelines.的更多信息

sh7euo9m

sh7euo9m2#

我认为你的答案是,当你通过这个实现创建的容器在一个带有DI的类中示例化它时,IHttpClientFactory将根据需要驱动套接字。
工厂方法,引入消息处理程序,这将是谁将管理请求和可用的websockets。

wh6knrhe

wh6knrhe3#

我检查了.net源代码,我看到在上面的用法中使用了IHttpClientFactory。

public static IHttpClientBuilder AddHttpClient<TClient, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TImplementation>(
        this IServiceCollection services, Action<HttpClient> configureClient)
        where TClient : class
        where TImplementation : class, TClient
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        if (configureClient == null)
        {
            throw new ArgumentNullException(nameof(configureClient));
        }

        AddHttpClient(services);

        string name = TypeNameHelper.GetTypeDisplayName(typeof(TClient), fullName: false);
        var builder = new DefaultHttpClientBuilder(services, name);
        builder.ConfigureHttpClient(configureClient);
        builder.AddTypedClientCore<TClient, TImplementation>(validateSingleType: true);
        return builder;
    }

internal static IHttpClientBuilder AddTypedClientCore<TClient, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TImplementation>(
    this IHttpClientBuilder builder, bool validateSingleType)
    where TClient : class
    where TImplementation : class, TClient
{
    ReserveClient(builder, typeof(TClient), builder.Name, validateSingleType);

    builder.Services.AddTransient(s => AddTransientHelper<TClient, TImplementation>(s, builder));

    return builder;
}

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2091:UnrecognizedReflectionPattern",
    Justification = "Workaround for https://github.com/mono/linker/issues/1416. Outer method has been annotated with DynamicallyAccessedMembers.")]
private static TClient AddTransientHelper<TClient, TImplementation>(IServiceProvider s, IHttpClientBuilder builder) where TClient : class where TImplementation : class, TClient
{
    IHttpClientFactory httpClientFactory = s.GetRequiredService<IHttpClientFactory>();
    HttpClient httpClient = httpClientFactory.CreateClient(builder.Name); // This Line

    ITypedHttpClientFactory<TImplementation> typedClientFactory = s.GetRequiredService<ITypedHttpClientFactory<TImplementation>>();
    return typedClientFactory.CreateClient(httpClient);
}

相关问题