Приложение Winforms перестает отвечать на запросы через некоторое время при выполнении асинхронных вызовов WCF через netTcpBinding
сценарий
Я поддерживаю / улучшаю приложение Windows Form, которое взаимодействует через службу WCF, размещенную в IIS, с использованием класса ServiceHostFactory.
Для решения проблемы, которую я пытаюсь решить, я имею дело с этими двумя методами в ServiceContract. ServiceContract помечен как PerCall.
[OperationContract(IsOneWay = true)]
void RunJob(int jobId);
[OperationContract]
byte[] GetUserJobs(int userID);
Пользователь отправит задание через метод RunJob в режиме пожара и забудет о моде. Эта работа сделает вызов WCF в другую службу, вернет некоторые данные, сделает с ними много всего и сохранит их в базе данных. Эта конкретная работа занимает около 62 минут.
Когда задание находится в состоянии "Выполнено", клиент каждые 10 секунд асинхронно вызывает метод GetUserJobs, чтобы проверить состояние задания и соответствующим образом обновить графический интерфейс. Клиент связывается со службой WCF через netTcpBinding.
проблема
Примерно через 1 час, GUI становится полностью не отвечает. Асинхронные вызовы все еще выполняются, но завершенное событие никогда не вызывается. Мне кажется, что-то заблокировано или заблокировано, и я не могу точно понять, почему это происходит. GUI может перестать отвечать на запросы до того, как RunJob (OneWay) будет фактически завершен на сервере, но само задание всегда завершается и данные сохраняются в базе данных.
Таким образом, даже если графический интерфейс непригоден для использования, Сервер все еще работает, за исключением того, что он не будет отвечать на любые вызовы WCF.
Если я отредактирую файл web.config на сервере, чтобы перезапустить IIS, графический интерфейс снова станет отзывчивым.
Я ни в коем случае не эксперт WCF, и я действительно изо всех сил пытаюсь найти решение этой проблемы. Я почти уверен, что это происходит из-за асинхронных вызовов, но пока не могу точно определить точную причину. Асинхронные вызовы закрываются в соответствии с кодом ниже.
Согласно моим журналам трассировки, я сразу вижу следующие ошибки, когда графический интерфейс перестает отвечать на запросы:
<ExceptionType>System.ServiceModel.CommunicationException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>There was an error writing to the pipe: The pipe is being closed. (232, 0xe8).</Message>
Тогда для Активности http://tempuri.org/IConnectionRegister/ValidateUriRoute я увижу:
<DataItem> <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Warning"> <TraceIdentifier>http://msdn.microsoft.com/en-US/library/System.ServiceModel.CommunicationObjectFaulted.aspx</TraceIdentifier> <Description>Faulted System.ServiceModel.Channels.ClientFramingDuplexSessionChannel</Description> <AppDomain>/LM/W3SVC/2/ROOT/Service_mt-4-130395564562210673</AppDomain> <Source>System.ServiceModel.Channels.ClientFramingDuplexSessionChannel/56837067</Source> </TraceRecord> </DataItem>
<DataItem> <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Warning"> <TraceIdentifier>http://msdn.microsoft.com/en-US/library/System.ServiceModel.CommunicationObjectFaulted.aspx</TraceIdentifier> <Description>Faulted System.ServiceModel.Channels.ServiceChannel</Description> <AppDomain>/LM/W3SVC/2/ROOT/Service_mt-4-130395564562210673</AppDomain> <Source>System.ServiceModel.Channels.ServiceChannel/3537205</Source> </TraceRecord> </DataItem>
Соответствующий код / Config (немного продезинфицировать)
Конфигурация привязки клиента
Я попытался установить для всех тайм-аутов "бесконечный" на данный момент, просто чтобы исключить какое-то странное поведение тайм-аута. Я пробовал различные настройки тайм-аута, но, похоже, ничего не работает.
<binding name="MyEndpoint" closeTimeout="infinite"
openTimeout="infinite" receiveTimeout="infinite" sendTimeout="infinite"
transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard" listenBacklog="10"
maxBufferPoolSize="2147483647" maxBufferSize="2147483647"
maxConnections="100" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
<reliableSession ordered="true" inactivityTimeout="infinite"
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
<message clientCredentialType="Windows" />
</security>
</binding>
Конфигурация привязки сервера
<netTcpBinding>
<binding name="MyBinding" portSharingEnabled="true" transferMode="Buffered" closeTimeout="infinite" openTimeout="infinite" receiveTimeout="infinite" sendTimeout="infinite" maxBufferPoolSize="524288" maxBufferSize="2147483647" maxConnections="10" listenBacklog="200" maxReceivedMessageSize="2147483647">
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
<message clientCredentialType="Windows" />
</security>
<reliableSession ordered="true"
inactivityTimeout="infinite"
enabled="false" />
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
<netTcpBinding>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<ServiceErrorHandler />
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
GUI выполняет нечто подобное следующему для асинхронного вызова службы WCF:
public void RefreshJobs()
{
//When the GUI becomes unresponsive, a lot of these log statements start piling up in the log file, until service is restarted
Logger.GetInstance().Info("Begin RefreshJobs");
ServiceClient svc = new ServiceClient("MyEndpoint", url);
try
{
svc.GetUserJobsCompleted += new EventHandler<GetUserJobsCompletedEventArgs>(svc_GetJobsCompleted);
}
catch (Exception e)
{
throw e;
}
svc.GetUserJobsAsync(SomeSingleton().CurrentUser.UserID, false, svc);
Logger.GetInstance().Info("End RefreshJobs");
}
private void svc_GetJobsCompleted(object sender, GetUserJobsCompletedEventArgs e)
{
Logger.GetInstance().Info("Start GetJobsCompleted");
if (e.Result != null)
{
//Do Stuff to Update GUI
}
//Close the connection
if (e.UserState is ServiceClient)
{
((ServiceClient)e.UserState).Close();
}
Logger.GetInstance().Info("End GetJobsCompleted");
}
1 ответ
Проблема закончилась перегрузкой ЦП, из-за чего Smsvchost.exe перестал отвечать.
Исправление от Microsoft доступно