我想在我的.NET Core项目中使用IHttpClientFactory
。问题是我需要使用大量的API。那么我应该为所有API使用单个Typed Client还是将它们分叉?所有API请求均来自同一来源。
public interface IStudentClient
{
}
public class StudentClient : IStudentClient
{
}
services.AddHttpClient<IStudentClient, StudentClient>();
我已遵循上述结构,并计划将所有API都包含在IStudentClient
内,并在StudentClient
中实现。现在我的问题是,当将所有API的实现仅包含在一个类中时,这是否会使StudentClient
类变得更加复杂。
答案 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>();
}