Reputation: 1
This is a problem that I have only when trying to write a test. In a .NET 5 solution, I test GetResult() in MyController:
public class MyController : ControllerBase
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IConfiguration _config;
public MyController(IHttpClientFactory httpClientFactory, IConfiguration config)
{
_httpClientFactory = httpClientFactory;
_config = config;
}
public async Task<IActionResult> GetResult(int id)
{
var firstResult = await GetFirstResult(id);
var secondResult = await GetSecondResult(id);
return Ok("")
}
private async Task<int> GetFirstResult(int id)
{
using (var httpClient = _httpClientFactory.CreateClient("MySetting"))
{
var response = await httpClient.GetAsync($"MyUrl1{id}");
return (response.IsSuccessStatusCode ? 0 : 1);
}
}
private async Task<int> GetSecondResult(int id)
{
using (var httpClient = _httpClientFactory.CreateClient("MySetting"))
{
var response = await httpClient.GetAsync($"MyUrl2{id}");
return (response.IsSuccessStatusCode ? 0 : 1);
}
}
My test:
[Test]
public async Task Get_Should_Return_OK_String()
{
var httpClientFactory = new Mock<IHttpClientFactory>();
var client = new HttpClient();
client.BaseAddress = new Uri("https://sthing/server.php");
httpClientFactory.Setup(_ => _.CreateClient(It.IsAny<string>))).Returns(client);
var config = InitConfiguration();
var controller = new MyController(httpClientFactory.Object, config);
var result = await controller.GetResult(1);
Assert.NotNull(result);
}
An exception is thrown in GetSecondResult() at the line of return(response...). Message: "Cannot access a disposed object. Object name: 'System.Net.Http.HttpClient'."
I am aware of this case Why is this HttpClient usage giving me an "Cannot access a disposed object." error? but there is no use of httpClientFactory. Is there a way to pass false to the constructor of the client through the factory? Why would it work out of the test anyway?
Upvotes: 0
Views: 1055
Reputation: 131712
First of all, .NET 5 goes out of support today. You should migrate to .NET 6, the current Long-Term-Support version. This isn't a sudden change, .NET Core's lifecycle was announced several years ago. For the most part, all you need to do is change net5.0 to net6.0 in your projects and update NuGet packages.
As for the error, it's caused by the using
block :
using (var httpClient = _httpClientFactory.CreateClient("MySetting"))
This isn't needed (it's actually discouraged), HttpClient instances and sockets are pooled and recycled by the HttpClientFactory.
The test code is configured to return the same HttpClient instance every time :
var client = new HttpClient();
client.BaseAddress = new Uri("https://sthing/server.php");
httpClientFactory.Setup(_ => _.CreateClient(It.IsAny<string>)))
.Returns(client);
The call to GetFirstResult()
disposes this instance and any subsequent use throws
To fix this just don't use using
. HttpClient is meant to be reused anyway:
var httpClient = _httpClientFactory.CreateClient("MySetting");
Upvotes: 1