.NET核心中的IHttpClientFactory

时间:2019-07-05 06:26:36

标签: c# asp.net-core

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

public interface IStudentClient
{

}

public class StudentClient : IStudentClient
{

}

services.AddHttpClient<IStudentClient, StudentClient>();

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

1 个答案:

答案 0 :(得分:2)

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

与此同时,我了解您的关注,但情况没有您想像的那么严重。

首先,您将获得一个庞大的接口,并因此获得一个庞大的实现类,但是它们的职责很明确:类型化的客户端有责任定义一个代理以访问远程Web服务(您的示例)。

类型化的客户端类的确并不复杂:可以肯定是巨大的,但是它是无状态的,仅公开访问远程Web服务的端点的方法。每种方法都有明确的明确职责:访问远程Web服务上的特定端点;这样的代码很少复杂。

唯一需要考虑的是使用控制器或服务中的接口IStudentClient。该接口非常大,因此,如果将其作为依赖项注入到消费者类中,则会违反interface segregation principle。该问题的一种可能解决方案是对较小的接口进行建模,以适应消费者类别的特定需求。

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

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

public interface IStudentProvider
{
  StudentContract GetstudentById(Guid studentId);
}

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

要实现界面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);
  }
}

重要的免责声明:为了简化讨论,我没有在接口上使用Task类,但是所有方法当然都应该返回Task<T>并接受CancellationToken的实例作为参数,因为http调用是自然的异步操作,并且您要对您的http客户端执行阻塞调用。

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

Microsoft DI容器将为您提供一些扩展方法来注册类型化的客户端。该服务将被注册为临时依赖关系,因此依赖于该服务的每个其他服务也必须被注册为临时依赖关系(以避免captive dependency issue)。

这是您应该注册服务的方式:

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