В этой статье показана известная проблема с HttpClient, которая может привести к истощению сокетов.
У меня есть ASP. NET Core 3.1 веб-приложение. В библиотеке классов. NET Standard 2.0 я добавил ссылку на веб-службу WCF в Visual Studio 2019, следуя этим инструкциям .
В службе, использующей клиент WCF, как это описано в документации . Создание экземпляра клиента WCF с последующим закрытием клиента для каждого запроса.
public class TestService
{
public async Task<int> Add(int a, int b)
{
CalculatorSoapClient client = new CalculatorSoapClient();
var resultat = await client.AddAsync(a, b);
//this is a bad way to close the client I should also check
//if I need to call Abort()
await client.CloseAsync();
return resultat;
}
}
Я знаю, что закрывать клиент без каких-либо проверок плохо, но для целей этого примера это не имеет значения.
Когда я запускаю приложение и делаю пять запросов к методу действия, использующему клиент WCF, а затем смотрю на результат netstat, я обнаруживаю открытые соединения со статусом TIME_WAIT, очень похожим на проблемы в статье выше о HttpClient.

Мне кажется, что использование встроенного клиента WCF может привести к истощение сокета или я что-то упустил?
Клиент WCF наследуется от ClientBase<TChannel>
. Читая эту статью , мне кажется, что клиент WCF использует HttpClient. Если это так, то я, вероятно, не должен создавать новый клиент для каждого запроса, верно?
Я нашел несколько статей ( это и это ) говорить об использовании одиночного или повторного использования клиента WCF. Это способ go?
ОБНОВЛЕНИЕ
Отладка соответствующих частей исходного кода WCF Я обнаружил, что новые HttpClient и HttpClientHandler создавались каждый раз, когда я создавал новый клиент WCF, который Я делаю для каждого запроса. Вы можете проверить код здесь
internal virtual HttpClientHandler GetHttpClientHandler(EndpointAddress to, SecurityTokenContainer clientCertificateToken)
{
return new HttpClientHandler();
}
Этот обработчик используется для создания нового HttpClient в методе GetHttpClientAsyn c:
httpClient = new HttpClient(handler);
Это объясняет почему клиент WCF в моем случае ведет себя так же, как HttpClient, который создается и удаляется для каждого запроса.
Мэтт Коннов пишет в выпуске в репозитории WCF, что он сделал возможным внедрите свою собственную фабрику HttpMessage в клиент WCF. Он пишет:
Я реализовал возможность предоставить Fun c для включения изменения или замены HttpMessageHandler. Вы предоставляете метод, который принимает HttpClientHandler и возвращает HttpMessageHandler.
Используя эту информацию, я внедрил собственную фабрику, чтобы иметь возможность управлять генерацией HttpClientHandlers в HttpClient.
Я создал моя собственная реализация IEndpointBehavior, которая внедряет IHttpMessageHandlerFactory для получения пула HttpMessageHandler.
public class MyEndpoint : IEndpointBehavior
{
private readonly IHttpMessageHandlerFactory messageHandlerFactory;
public MyEndpoint(IHttpMessageHandlerFactory messageHandlerFactory)
{
this.messageHandlerFactory = messageHandlerFactory;
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
Func<HttpClientHandler, HttpMessageHandler> myHandlerFactory = (HttpClientHandler clientHandler) =>
{
return messageHandlerFactory.CreateHandler();
};
bindingParameters.Add(myHandlerFactory);
}
<other empty methods needed for implementation of IEndpointBehavior>
}
Как вы можете видеть в AddBindingParameters, я добавляю очень простую фабрику, которая возвращает объединенный HttpMessageHandler.
1064
1064 поведение моего WCF-клиента выглядит следующим образом.
public class TestService
{
private readonly MyEndpoint endpoint;
public TestService(MyEndpoint endpoint)
{
this.endpoint = endpoint;
}
public async Task<int> Add(int a, int b)
{
CalculatorSoapClient client = new CalculatorSoapClient();
client.Endpoint.EndpointBehaviors.Add(endpoint);
var resultat = await client.AddAsync(a, b);
//this is a bad way to close the client I should also check
//if I need to call Abort()
await client.CloseAsync();
return resultat;
}
}
Когда я запускаю приложения с этими изменениями, у меня больше нет открытого соединения для каждого запроса, который я делаю.