问题描述
在以下两种设置HttpClient的方案之间有什么区别吗?
我要不要一个?
键入的客户端
public class CatalogService
{
private readonly HttpClient _httpClient;
public CatalogService(HttpClient httpClient) {
_httpClient = httpClient;
}
public async Task<string> Get() {
var response = await _httpClient.GetAsync();
....
}
public async Task Post() {
var response = await _httpClient.PostAsync();
...
}
}
// Startup.cs
//Add http client services at ConfigureServices(IServiceCollection services)
services.AddHttpClient<ICatalogService,CatalogService>();
IHttpClientFactory:
public class CatalogService
{
private readonly IHttpClientFactory _factory;
public CatalogService(IHttpClientFactory factory) {
_factory = factory;
}
public async Task<string> Get() {
var response = await _factory.CreateClient().GetAsync();
....
}
public async Task Post() {
var response = await _factory.CreateClient().PostAsync();
...
}
}
// Startup.cs
//Add http client services at ConfigureServices(IServiceCollection services)
services.AddHttpClient();
```
解决方法
IMO,我将通过HttpClient
。原因是,
- KISS原则-
CatalogService
真正需要的是HttpClient
。该服务不关心如何获得客户。 - 单一职责原则(SRP)-明天说,您必须保留两个
CatalogService
实例才能将请求发送到两个不同的端点,- 您可以传入
IHttpClientFactory
并在CatalogService
内实现路由,但这会破坏SRP。 - 或者,您可以创建一个
CatalogServiceFactory
。该工厂被传入IHttpClientFactory
并在内部实现路由。这也称为关注点分离。
- 您可以传入
我认为,从消费的角度看,最大的区别就会显现出来。
键入的客户端
您将收到一个HttpClient
实例,该实例可能已饰有一些针对瞬时故障的弹性策略和一些默认值。您甚至可能会收到已经设置了BaseUrl
的客户端。
因此,如果您需要将REST API客户端隐藏在强类型的服务层后面,则此方法特别有用。
指定客户
当您需要来自特定客户端的多个实例或需要多个不同的客户端时,此技术会发光。如果您已经注册了多个具有不同名称的不同客户端,则可以通过单个API轻松检索它们。
因此,如果您需要调用不同的下游系统并且需要汇总其结果,则此方法可能很有用。
阅读文章很好
- Use IHttpClientFactory to implement resilient HTTP requests
- Make HTTP requests using IHttpClientFactory in ASP.NET Core
- IHttpClientFactory with named Clients
- IHttpClientFactory with typed clients
- IHttpClientFactory with Polly
拥有抽象(即IHttpClient
)要好得多,并且受到社区的好评。它使您可以分配HttpClient
以及自定义编写的IHttpClient
,而无需更改CatalogService
。
当您创建大型系统时,这非常关键,因为您对具体实现的依赖性降低了,维护成本也降低了。
此外,使用抽象可以显示实际使用的目的,并减少可能的干扰。一个例子:
public interface MyInterface
{
void UsefulMethod();
}
public class MyClass : MyInterface
{
public float variable1;
public float moreBurden;
public float thisIsNotRequiredAtAll;
public void UsefulMethod() {}
public void AnotherMethod() {}
public void MoreNoiseMethod() {}
}
public class MyService
{
private MyClass _myClass;
public MyService(MyClass myClass)
{
_myClass = myClass;
}
public void MyOnlyMethod()
{
_myClass.UsefulMethod();
}
}
在这种情况下,您仅使用单一方法,但是您的服务可以访问大量不必要的信息,从而分散了目标的注意力。要创建MyService
,其创建者必须能够创建MyClass
的实例。
现在图像MyService
的写法是
public class MyService
{
private IMyInterface _myInterface;
public MyService(IMyInterface myInterface)
{
_myInterface = myInterface;
}
public void MyOnlyMethod()
{
_myInterface.UsefulMethod();
}
}
现在,_myInterface
的用途很明确-您只需要方法的特定子集。 MyService
仅可访问该单一方法,不会因所有可能的实现细节而分心。