c# - 类型化的 HttpClient 仅适用于 WebApplicationFactory 的 CreateClient()
问题描述
我为默认的 WeatherForecast API 项目创建了一个客户端,我想在集成测试中使用它:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
namespace API_ClientTest
{
public class WeatherClient : IWeatherClient
{
public HttpClient _client { get; }
public WeatherClient(HttpClient client)
{
client.BaseAddress = new Uri("http://localhost:80/");
client.DefaultRequestHeaders.Add("Accept",
"application/json");
_client = client;
}
public async Task<string> GetWeatherForecast()
{
var response = await _client.GetAsync("weatherforecast");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
}
using System.Threading.Tasks;
namespace API_ClientTest
{
public interface IWeatherClient
{
Task<string> GetWeatherForecast();
}
}
对于我的集成测试,我使用 WebApplicationFactory:
using System.Linq;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace API_ClientTest
{
public class WeatherServiceFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// Build the service provider.
var sp = services.BuildServiceProvider();
//Typed clients (because types are cool)
services.AddHttpClient("WeatherClient")
.AddTypedClient<WeatherClient>()
.AddTypedClient<IWeatherClient, WeatherClient>();
});
}
}
}
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace API_ClientTest
{
public class WeatherServiceTest : IClassFixture<WeatherServiceFactory<API_ClientTest.Startup>>
{
private readonly WeatherServiceFactory<API_ClientTest.Startup>
_factory;
public WeatherServiceTest(WeatherServiceFactory<API_ClientTest.Startup> factory)
{
_factory = factory;
}
[Fact]
public async Task Get_GenerateResponse()
{
// Arrange
var weatherClient = _factory.Services.GetRequiredService<IWeatherClient>();
var factoryClient = _factory.CreateClient();
// Works
var factoryResponse = await factoryClient.GetAsync("weatherforecast");
// Does not work
var response = await weatherClient.GetWeatherForecast();
}
}
}
所以工厂的客户端可以与 API 通信,但是依赖注入(我从工厂的服务中获取)的客户端会抛出 System.Net.Http.HttpRequestException。
Message:
System.Net.Http.HttpRequestException : No connection could be made because the target machine refused it. (Translated by author)
---- System.Net.Sockets.SocketException : Es konnte keine Verbindung hergestellt werden, da der Zielcomputer die Verbindung verweigerte.
Stack Trace:
ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
WeatherClient.GetWeatherForecast() line 24
WeatherServiceTest.Get_GenerateResponse() line 26
--- End of stack trace from previous location where exception was thrown ---
----- Inner Stack Trace -----
ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
你能解释一下不同行为的原因吗?谢谢
编辑:来自工厂的 HttpClient 直接与 WebApi 通信,而来自 WeatherService 的 HttpClient 通过网络向 localhost 发送一个 http 请求。目标是在我的 WeatherClient 中重新创建第一个 HttpClient 的行为。
一个临时的解决方法是使用工厂的 HttpClient 实例初始化类型化的客户端:
var weatherClient = new WeatherClient (_factory.CreateClient());
解决方案
推荐阅读
- reactjs - 使用 SWR Hook 获取带有输入参数的数据
- node.js - 如何在打字稿中导入本机节点模块(node-gyp)
- influxdb - 如何在 Flux (influxdb) 中转义字符串?
- python - jupyter notebook 执行 shell 脚本并忽略输出日志
- unit-testing - 如何在 Jest 中测试 Vue 道具更新
- opencv - 如何从图像中的表格中提取文本并将它们排列到电子表格 OpenCV 中
- flutter - 如何在颤动中使用剪辑路径小部件创建具有形状的自定义按钮
- python - 如何使用 Python 访问 api.hypixel.net
- c - 这意味着什么?#define SOMENAME ((uint32_t *)0x130010f0
- javascript - 使用 CreateJS 缩放 Movieclip 子元素