dus*_*ris 20 c# dotnet-httpclient .net-core asp.net-core httpclientfactory
我有一个键入的客户端,我想将其注册为单例:
public class SomeHttpClient
{
private readonly IHttpClientFactory _clientFactory;
public SomeHttpClient(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public Task MakeSomeCallAsync(...)
{
var client = _clientFactory.Create();
// Do more stuff
}
}
Run Code Online (Sandbox Code Playgroud)
类型化的客户端必须是单例的,因为它有一些断路器逻辑,如果 API 对客户端进行速率限制,则会中断电路。电路必须在整个应用程序中断开,显然不仅仅是当前的请求管道(否则客户端将继续访问已经从其他实例进行速率限制的 API)。这已经通过使用封装了该功能的类型化客户端(虽然不是 Polly)来实现的。
现在因为类型化的客户端将是一个单身人士,我们不能注入一个单身人士,HttpClient因为这会带来我们以前在一个 long living 中遇到的所有问题HttpClient。显而易见的解决方案是注入一个HttpClientFactory现在可以用来在HttpClient每次键入的客户端需要一个实例时发出一个实例而不必担心生命周期管理等,因为这已经推迟到HttpClientFactory现在。
我现在的问题是如何HttpClientFactory为一个简单的功能集成测试创建默认值,我想在其中实例化一个类型化的客户端,看看我是否可以点击 API 并从自动化测试中获得成功的响应?
我不想设置一个 ASP.NET Core TestServer 和一个围绕它的整个应用程序,因为这对于我现在想要做的那种功能测试来说太过分了。
没有可用于注入HttpClientFactory?
mar*_*sze 14
@dustinmoris 的回答,但在 C# 中
public sealed class DefaultHttpClientFactory : IHttpClientFactory
{
public HttpClient CreateClient(string name) => new HttpClient();
}
Run Code Online (Sandbox Code Playgroud)
甚至更好,使用单例:
public sealed class DefaultHttpClientFactory : IHttpClientFactory
{
private static readonly Lazy<HttpClient> _httpClientLazy =
new Lazy<HttpClient>(() => new HttpClient());
// NOTE: This will always return the same HttpClient instance.
public HttpClient CreateClient(string name) => _httpClientLazy.Value;
}
Run Code Online (Sandbox Code Playgroud)
我现在的问题是如何为简单的功能集成测试创建默认的 HttpClientFactory ,我想在其中实例化一个类型化的客户端,看看我是否可以点击 API 并从自动化测试中获得成功的响应?
您的测试可以采用您用来配置 HttpClientFactory 的确切代码StartUp(这是一个使用 Polly 策略的示例,但它可以是 HttpClientFactory 上的任何配置)。
IServiceCollection services = new ServiceCollection(); // [1]
services.AddHttpClient(TestClient)
.AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError()
.RetryAsync(3); // [2]
Run Code Online (Sandbox Code Playgroud)
第 [2] 行可能是您StartUp班级的确切代码。您可以将其从正常ConfigureServices(...)方法中分解static为您的测试也可以调用的单独方法 - 因此您的测试准确地测试了StartUp配置。
然后在测试中:
IHttpClientFactory factory = services
.BuildServiceProvider()
.GetRequiredService<IHttpClientFactory>();
var sut = new SomeHttpClient(factory);
Run Code Online (Sandbox Code Playgroud)
我只是自己创建一个用于测试(我认为可能已经有一种方法可以为我做到这一点):
type DefaultHttpClientFactory() =
interface IHttpClientFactory with
member __.CreateClient (name) =
new HttpClient()
Run Code Online (Sandbox Code Playgroud)