【问题标题】:Using HttpClient in external library for ASP.NET Core在 ASP.NET Core 的外部库中使用 HttpClient
【发布时间】:2021-11-02 06:41:55
【问题描述】:

简介

我正在开发 SDK(它只是 REST API 的包装器)。此 SDK 在内部使用 HttpClient 向 API 发出请求。 SDK 面向 .NET Standard 2.1。这是简化的代码。

public class SomeSdk 
{
    private readonly HttpClient _httpClient;

    public SomeSdk(<some-settings>) 
    {
        _httpClient = new HttpClient(<some-settings>);
    }

    public async Task<string> GetSomethingFromApiAsync() 
    {
        return await _httpClient.GetStringAsync(...);
    }
}

问题

该 SDK 正被 ASP.NET Core 项目中的其他开发人员使用。我知道 HttpClient 的问题,并且我知道 MS DOCS 建议注入 HttpClientFactory 以避免 SocketException 并反映 DNS 更改。

想到的第一个解决方案是让用户在SDK构造函数或其他方法中传递HttpClient(即来自HttpClientFactory)。像这样。

public async Task<string> GetSomethingFromApiAsync(HttpClient clientFromFactory) 
{
    return await clientFromFactory.GetStringAsync(...);
}

但是SDK在使用HttpClient之前会对其进行配置(代理,超时等),因此它的初始化应该留在SDK构造函数中。

问题

我目前的解决方案是在 ASP.NET Core 项目中将 SDK 作为单例注入并接受 DNS 反射问题。我仍然想问是否有人会推荐我解决这个问题的更好方法。

非常感谢你,亚当。

【问题讨论】:

    标签: c# .net-core asp.net-core-webapi webapi httpclientfactory


    【解决方案1】:

    更好的方法是使用 HttpClientFactory 来创建 HttpClient 实例。

    HttpClientFactory 可以创建和管理新的 HttpClient 实例,但在创建新的 HttpClient 实例时,它不会重新创建新的消息处理程序,而是从池中获取一个。然后,它使用该消息处理程序将请求发送到 API。处理程序的默认生命周期设置为两分钟,在此期间,对新 HttpClient 的任何请求都可以重用现有的消息处理程序和连接。这意味着我们不必为每个请求创建新的消息处理程序,也不必打开新连接,从而防止套接字耗尽问题。

    使用 HttpClientHandler,我们可以集中我们的 HttpClient 的配置。如果在每个服务类中使用 HttpClientHandler 重复相同的配置,就可以防止这种情况发生。

    你可以在这里找到如何使用它的例子https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-5.0

    【讨论】:

      【解决方案2】:

      实例化 HttpClient 的更好方法是使用 DI。
      所以,假设你的 SDK 项目中有这样的类

      public interface ISomeSdk
      {
          Task<string> GetSomethingFromApiAsync();
      }
      
      public class SomeSdk: ISomeSdk
      {
          private readonly HttpClient _httpClient;
      
          public SomeSdk(HttpClient httpClient)
          {
              _httpClient = httpClient;
          }
      
          public async Task<string> GetSomethingFromApiAsync()
          {
              return await _httpClient.GetStringAsync("");
          }
      }
      

      您可以轻松添加扩展方法以通过 DI 注册它(此处,在 SDK 项目中)

      public static class HttpClientExtensions
      {
          public static void RegisterSdk(this IServiceCollection services)
          {
              services.AddHttpClient<ISomeSdk, SomeSdk>(client =>
              {
                  client.Timeout = TimeSpan.FromSeconds(60);
                  client.BaseAddress = new Uri("https://google.com");
              });
          }
      }
      

      之后在启动项目中这个类可以添加到DI注册中

      public void ConfigureServices(IServiceCollection services)
      {
          services.RegisterSdk();
          //...
      

      什么允许在需要时使用它

      public class SomeController : ControllerBase
      {
          private readonly ISomeSdk _someSdk;
      
          public SomeController(ISomeSdk someSdk)
          {
              _someSdk = someSdk;
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-31
        • 2017-12-23
        • 2019-09-14
        • 2021-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多