这是HttpClient .Net Core源代码的类设计。
有趣的方法在于CheckDisposedOrStarted()
。
private void CheckDisposedOrStarted()
{
CheckDisposed();
if (_operationStarted)
{
throw new InvalidOperationException(SR.net_http_operation_started);
}
}
现在当设置这些属性时会被调用:
BaseAddress
Timeout
MaxResponseContentBufferSize
因此,如果您计划重复使用 HttpClient
实例,则应设置一个单独的实例,该实例预设这 3 个属性,并且所有使用必须不要修改这些属性。
或者您可以创建一个工厂或使用简单的AddTransient(...)
。请注意,AddScoped
在这里不是最适合的,因为您将在每个请求作用域中收到相同的实例。
编辑基本工厂
现在,工厂只是负责为另一个服务提供实例的服务。以下是一个构建HttpClient
的基本工厂,现在意识到这只是最基本的,您可以扩展此工厂以根据需要预设每个HttpClient
的实例。
public interface IHttpClientFactory
{
HttpClient CreateClient();
}
public class HttpClientFactory : IHttpClientFactory
{
static string baseAddress = "http://example.com";
public HttpClient CreateClient()
{
var client = new HttpClient();
SetupClientDefaults(client);
return client;
}
protected virtual void SetupClientDefaults(HttpClient client)
{
client.Timeout = TimeSpan.FromSeconds(30);
client.BaseAddress = new Uri(baseAddress);
}
}
为什么我使用接口?这是因为使用依赖注入和控制反转,我们可以非常轻松地“交换”应用程序的部分。现在,我们访问 IHttpClientFactory
代替直接访问 HttpClientFactory
。
services.AddScoped<IHttpClientFactory, HttpClientFactory>()
现在在你的类、服务或控制器中,你需要请求工厂接口并生成一个实例。
public HomeController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
readonly IHttpClientFactory _httpClientFactory;
public IActionResult Index()
{
var client = _httpClientFactory.CreateClient();
return View();
}
这里的关键是。
- 工厂负责生成客户端实例并管理默认值。
- 我们请求接口而非实现,这有助于让组件保持独立以及实现更加模块化的设计。
- 该服务被注册为作用域实例。单例模式也有它们的用途,但在这种情况下,您更可能需要一个作用域实例。
作用域生命周期服务每个请求创建一次。
AddScoped
代替,以便获得一个新的请求实例。 - KaltenAddScoped
,因为会导致上述异常抛出。 - Nico