由 HttpClientFactory 创建的长期存在的 HttpClient

Long lived HttpClient created by HttpClientFactory

我读到 HttpMessageHandlers 每 2 分钟回收一次,但我不确定是否将新的分配给现有的 HttpClient

我已经使用 SetHandlerLifetime(TimeSpan.FromSeconds(5)); 对其进行了测试,即使经过 2 分钟的无数请求,httpClient 仍在继续工作,这是一个好兆头吗?

这是否意味着我无需担心 DNS changes/socket 耗尽?

内部 ConfigureServices 方法:

var myOptions = app.ApplicationServices.GetService<IOptionsMonitor<MyOptions>>();
HttpClient httpClient = app.ApplicationServices.GetService<IHttpClientFactory>().CreateClient();
MyStaticObject.Configure(myOptions, httpClient);

编辑: 添加了一些示例代码。

这里有几件事要看,第一个是 MyStaticObject 实际上需要是静态的吗?如果是这样,我会建议将其注册为 Singleton,这样您仍然可以利用依赖注入。完成后,您可以注册 IHttpClientFactory 并在您的代码中使用它。您的 ConfigureServices 方法最终可能看起来像这样

public void ConfigureServices(IServiceCollection services)
{
  //The base extension method registers IHttpClientFactory
  services.AddHttpClient();
  services.AddSingleton<IMySingletonObject, MySingletonObject>();
}

然后在你的消费中class,在这种情况下MySingletonObject,你会这样配置它

public class MySingletonObject
{
  private readonly IHttpClientFactory _clientFactory;

  public MySingletonObject(IHttpClientFactory clientFactory)
  {
    _clientFactory = clientFactory;
  }

  public async Task SomeMethodThatUsesTheClient()
  {
    var client = _clientFactory.CreateClient();
    //use the client
  }
}

这样做的原因是 IHttpClientFactory 为我们处理了生命周期和池问题。根据 docs:

Manages the pooling and lifetime of underlying HttpClientMessageHandler instances. Automatic management avoids common DNS (Domain Name System) problems that occur when manually managing HttpClient lifetimes.

当您进行 CreateClient 调用时会发生这种情况,因此您想使用客户端在代码中执行此操作,而不是在您的应用程序启动时执行此操作。

附带说明一下,如果您根本不需要此 class 成为单例,则可以使用扩展名 services.AddHttpClient<IMyClass, MyClass>() 并将 HttpClient 直接注入 class。 DI 容器将在幕后为您处理从工厂获取客户端。

     public static IServiceCollection AddApiClient(this IServiceCollection services,
        Action<RgCommunicationClientOptions> action)
    {
        services.AddHttpClient<ISomeApiClient, SomeApiClient>()
            .AddPolicyHandler(GetRetryPolicy())
            .SetHandlerLifetime(TimeSpan.FromMinutes(4));
        services.AddOptions();
        services.Configure(action);

        return services;
    }
    
    static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
    {
        return HttpPolicyExtensions
            .HandleTransientHttpError()
            //.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
            .WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
    }

 services.AddApiClient(options => options.BaseAddress = configuration.GetSection("ExternalServices:SomeApi")["Url"]);
       

You can inject HttpClient like above in the class via dependency injection. I have used Poly extension to add RetryPolicy. Also you can set the LifetTime of the handler by using SetHaandlerLifeTime. This way you can individually configure client for each client. In the logs you can see that httpHandler expires after 4 mins for the respective call. I have used the extension method to pass the options in the method, getting values via app settings. Hope this helps. Blockquote