При нормальной работе с этим подходом проблем не возникает, поскольку HttpClient объект создается один раз и никогда не меняется на протяжении всего срока службы приложения. Проблема возникает, когда я пытаюсь запустить модульные тесты, поскольку я создаю несколько HttpClients, чтобы можно было имитировать их ответы.
Вот как в основном выглядит мой одноэлементный класс (это не реальный код, просто пример, демонстрирующий основную идею).
Код: Выделить всё
internal sealed class MySingleton
{
private static readonly Lazy _ instance = new Lazy(() => new MySingleton());
public static MySingleton Instance => _instance.Value;
private HttpClient _httpClient;
internal HttpClient HttpClient
{
get => _httpClient;
set //This is provided for testing, so I can mock the HttpMessageHandler
{
_httpClient = value;
}
}
private MySingleton()
{
SocketsHttpHandler
handler = new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(10)
};
_httpClient = new HttpClient(handler);
}
internal async Task SendRequest()
{
//Uses the HttpClient to send a request.
return true;
}
}
Проблема возникает, когда я запускаю модульные тесты, поскольку они манипулируют HttpClient и выполняются параллельно. В настоящее время я заставляю тесты выполняться синхронно, но это не идеальное решение. Вот примерное представление о том, как выглядят мои тесты.
Код: Выделить всё
public class Tests
{
[Fact]
public async Task This_Is_A_Test()
{
string
jsonText = """
{
"id" : 1,
"name" : "testing",
"value" : 23
}
""";
HttpMessageHandler
httpMessageHandler = new MockHttpMessageHandler(jsonText, System.Net.HttpStatus.Created);
MySingleton.Instance.HttpClient = new HttpClient(httpMessageHandler);
bool
result = await MySingleton.Instance.SendRequest();
Assert.IsTrue(result);
}
}
Как видно из тестового кода, я заменяю HttpClient в синглтоне на тот, который будет возвращать нужные мне данные. Побочным эффектом этого является сбой тестов, когда они выполняются параллельно.
Мне интересно, есть ли способ синхронизировать доступ к экземпляру синглтона, поэтому что он может использоваться только одним потоком одновременно. По сути, поток захватывает синглтон, использует его по назначению, а затем отпускает обратно для использования другим потоком.
Возможно, мой подход здесь совершенно неправильный, и в этом случае я Я открыт для предложений. Хотя мне бы очень хотелось знать, возможно ли сделать то, что я пытаюсь сделать. Я пытался найти ответ в Google, но придумал только синхронизацию создания экземпляра (который Lazy уже обрабатывает). Я даже пробовал использовать ИИ, но это не помогло.
Подробнее здесь: https://stackoverflow.com/questions/791 ... leton-in-c
Мобильная версия