.net 核心中的 IHttpClientFactory

Sun*_*nny 4 c# asp.net-core

我想IHttpClientFactory在我的 .NET Core 项目中使用。问题是我需要使用大量 API。那么我应该为所有 API 使用单个类型化客户端还是应该将它们分叉?所有 API 请求都来自同一个源。

public interface IStudentClient
{

}

public class StudentClient : IStudentClient
{

}

services.AddHttpClient<IStudentClient, StudentClient>();
Run Code Online (Sandbox Code Playgroud)

我遵循了上述结构,并计划将所有 API 包含在内IStudentClient并在StudentClient. 现在我的问题是,StudentClient当仅在一个类中包含所有 API 的实现时,这会不会使类变得更复杂。

Enr*_*one 5

在我看来,为所有对特定远程服务的访问编写一个大类型的客户端是正确的方法。这正是 Microsoft 为类型化 http 客户端设想的使用模式。

同时我理解你的担忧,但情况并不像你想象的那么绝望。

首先,您将获得一个巨大的接口,从而获得一个巨大的实现类,但它们的责任很明确:类型化客户端有责任定义访问远程 Web 服务的代理(示例中的学生服务) .

类型化的客户端类实际上并不复杂:当然,它可以很大,但它是无状态的,并且只公开访问远程 Web 服务端点的方法。每个方法都有一个明确且定义明确的职责:访问远程 Web 服务上的特定端点;像这样的代码很少复杂。

唯一的问题是使用IStudentClient控制器或服务的接口。接口很大,所以如果你将它作为依赖注入到消费者类中,你将违反接口隔离原则。这个问题的一个可能的解决方案是建模更小的接口,为消费者类的特定需求而塑造。

想象一下,您的远程 Web 服务公开的端点之一允许您获取单个学生的详细信息(它可能类似于 GET /students/{studentId})。这意味着公开的方法之一IStudentClient将是GetStudentById(Guid studentId)将 GET 请求包装到/students/{studentId}.

此时,您可以定义一个名为 的较小接口IStudentProvider,其形状如下:

public interface IStudentProvider
{
  StudentContract GetstudentById(Guid studentId);
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以IStudentProvider在您的使用者类(例如,您在应用程序中定义的 MVC 控制器或服务类)中注入较小的接口。

要实现该接口,IStudentProvider您可以执行以下操作:

public class HttpStudentProvider : IStudentProvider 
{
  private readonly IStudentClient client;

  public HttpStudentProvider(IStudentClient client)
  {
    this.client = client;
  }

  public StudentContract GetstudentById(Guid studentId) 
  {
    return this.client.GetStudentById(studentId);
  }
}
Run Code Online (Sandbox Code Playgroud)

重要声明:为了使讨论简单的我没有使用Task类的接口,但当然,所有的方法应该返回Task<T>和接受的一个实例CancellationToken作为参数,因为HTTP调用是天然的异步操作,你做想要与您的 http 客户端执行阻塞调用。

如何在 DI 容器上注册这些类

Microsoft DI 容器将为您提供一些扩展方法来注册类型化客户端。该服务将注册为瞬态依赖项,因此依赖于它的其他服务也必须注册为瞬态依赖项(以避免俘虏依赖问题)。

这是您注册服务的方式:

public void ConfigureServices(IServiceCollection services)
{
   services.AddHttpClient<IStudentClient, StudentClient>();
   services.AddTransient<IStudentProvider, HttpStudentProvider>();
}
Run Code Online (Sandbox Code Playgroud)