WCF перестает отвечать после примерно 10 или около того вызовов (дросселирование)
У меня есть служба WCF и приложение с Service Reference к нему, а с приложением у меня есть цикл и на каждой итерации он делает вызов метода в этом веб-сервисе wcf.
Проблема в том, что после примерно 9 звонков или просто она останавливается... и если вы нажмете кнопку Pause
на VS, вы увидите, что она застряла в строке, где она совершает вызов.
После некоторого времени ожидания этого TimeoutException выдается:
В течение ожидая ответа после 00: 00: 59,9970000. Увеличение таймаута значение, переданное на вызов для запроса или увеличьте значение SendTimeout на Связывание. Время, отведенное для этого возможно, была частью более длинный тайм-аут.
Я немного поработал над этим и нашел некоторые решения, связанные с редактированием app.config в приложении, и вот выдержки из него:
<serviceBehaviors>
<behavior name="ThrottlingIssue">
<serviceThrottling maxConcurrentCalls="500" maxConcurrentSessions="500" />
</behavior>
</serviceBehaviors>
.
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
Затем, после прекращения отладки, через пару минут появляется сообщение об ошибке, сообщающее мне, что произошел Катастрофический сбой.
Как я могу исправить эту проблему? У меня не было этой проблемы, когда я работал с обычной веб-службой.
Для справки, вот целая app.config
:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ThrottlingIssue">
<serviceThrottling maxConcurrentCalls="500" maxConcurrentSessions="500" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IDBInteractionGateway" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:28918/DBInteractionGateway.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IDBInteractionGateway"
contract="DBInteraction.IDBInteractionGateway" name="WSHttpBinding_IDBInteractionGateway">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
[Обновить] Решение:
По-видимому, после каждого запроса вы должны Close
подключиться... Я закрываю соединение после каждого запроса, и оно работает как шарм.
Хотя то, что я до сих пор не могу понять, это то, что в моем app.config я установил мои maxConcurrentCalls и maxConcurrentSessions на 500, и все же я могу сделать только 10. У кого-нибудь есть ответ на этот вопрос? (возможно, у меня что-то не так в моем app.config выше)
Ответ на указанный вопрос (теперь пунктирный) заключается в том, что я редактировал клиент app.config
, а не файл конфигурации службы (web.config
)
Ответы
Ответ 1
Число разрешенных одновременных подключений по умолчанию равно 10.
Скорее всего, ваш клиент не закрывает соединения.
Чтобы увеличить количество одновременных вызовов, вам придется добавить свое поведение к конфигурации службы, а не к клиенту.
Ответ 2
Вызов функции clientservice.close() позволит решить проблему.
Ответ 3
На этой неделе я столкнулся с этой проблемой, и мне не удалось понять, что происходит.
Я действительно изменил свой вызов на мою службу Dispose()
на клиентскую службу, но, похоже, это не повлияло. По-видимому, там был другой служебный вызов.
Что может быть интересно отметить, так это то, что заставило меня решить, что это не проблема: этот предел не связан с фактическим количеством подключений сокетов к веб-сервису. Когда вы нажимаете предел maxConcurrentSessions
, все еще существует только одно фактическое соединение сокета. Я проверял это на netstat
, что привело меня к неправильному выводу. Итак, не путать сеансы с сокетами.
У нас есть интерфейсы, определенные для всех наших сервисов WCF, поэтому я планирую сейчас адаптировать этот шаблон в своем коде:
IMyService service = new MyServiceClient();
using (service as IDisposable)
{
service.MyServiceMethod();
}
Интересно также, что проблема не возникла для меня, когда службы (и веб-сайт) были размещены в IIS. Конфигурация (почти) идентична, но я не мог воспроизвести это поведение на этой машине. Я думаю, что это хорошо:)
@Джон Сондерс (о присвоении переменной в using
):
Я обычно помещаю назначение переменной в оператор using
. Но созданный IMyService неявно конвертируется в IDisposable
. Если вы действительно хотели получить задание, я полагаю, что альтернативой было бы следующее:
IService service;
using ((service = new ServiceClient()) as IDisposable)
{
}
Это все еще оставляет проблему с областью переменной. Ссылка на IService service
непригодна для использования, но все же в области видимости. Поэтому в этом отношении было бы лучше:
using (IDisposable serviceDisposable = new ServiceClient())
{
IService service = (IService)serviceDisposable;
}
Это требует от меня ввести дополнительное имя переменной. * Мех *
Ответ 4
Это можно решить, создав класс singleton как интерфейс между ссылкой веб-службы и приложением. Затем он создаст только один экземпляр ссылки на службу.
class ServiceInterface
{
private static ServiceInterface _instance;
private ServiceClient _service = new ServiceClient ;
private ServiceInterface()
{
//Prevent accessing default constructor
}
public static ServiceInterface GetInstance()
{
if(_instance == null)
{
_instance = new ServiceInterface();
}
return _instance;
}
// You can add your functions to access web service here
Public int PerformTask()
{
return _service.PerformTask();
}
}
Ответ 5
Можете ли вы настроить трассировку и запустить цикл? Возможно, канал становится ошибочным и заставляет клиента отключиться.
Ответ 6
После того, как я потянул за волосы по той же проблеме, которая не была решена с помощью Close()
или Dispose()
, я хотел бы добавить простое решение, которое сделало мой день, а именно, увеличив ServicePointManager.DefaultConnectionLimit
, который по умолчанию 2.
"Свойство DefaultConnectionLimit устанавливает максимальное количество одновременных подключений по умолчанию, которое объект ServicePointManager присваивает свойству ConnectionLimit при создании объектов ServicePoint."
В моем случае мое приложение успешно подключилось к моему удаленному сервису 2 раза, с третьей попытки он просто не пытался подключиться к службе. Вместо этого он подождал некоторое время, прежде чем тайм-аут с тем же сообщением об ошибке, что и в вопросе выше. Увеличение DefaultConnectionLimit
разрешило это. Чтобы добавить к разочарованию, это поведение было несколько случайным - в одном случае из 10 веб-служба была успешно использована несколько ( > 2) раз.
Решение возникает и далее обсуждается эти два потока: wcf-timeout-exception-detailed-investigation и wcf-service-throttling. решил мою проблему.