Я использую netNamedPipeBinding
для выполнения межпроцессного взаимодействия WCF между приложением Windows и службой Windows.
Теперь мое приложение работает хорошо во всех других учетных записях (после отбрасывания моей справедливой доли исключений WCF, как знал бы любой, кто работал с WCF ...), но эта ошибка оказывается весьма устойчивой.
Чтобы нарисовать картину моего сценария: моя служба Windows может быть поставлена в очередь для выполнения какой-либо работы в любой момент времени с помощью кнопки, нажатой в приложении Windows, и затем она передает netNamedPipeBinding
, который является привязкой, которая поддерживает обратные вызовы ( двусторонняя связь), если вы не знакомы и инициируете запрос на выполнение этой работы (в данном случае процедура загрузки файла), он также генерирует обратные вызовы (события) каждые несколько секунд, начиная от прогресса файла до скорости передачи и т. д. и т. д. и т. д. Вернемся к приложению Windows, поэтому существует довольно тесная интеграция клиент-сервер; Вот как я получаю информацию о том, что работает в моей службе Windows, обратно в мое приложение Windows.
Теперь все отлично, боги WCF сейчас относительно мной довольны, за исключением одного неприятного исключения, которое я получаю каждый раз, когда преждевременно закрываю приложение (что является вполне допустимым сценарием). Пока идет передача, а обратные вызовы запускаются довольно сильно, я получаю эту ошибку:
System.ServiceModel.ProtocolException:
The channel received an unexpected input message with Action
'http://tempuri.org/ITransferServiceContract/TransferSpeedChangedCallback'
while closing. You should only close your channel when you are not expecting
any more input messages.
Теперь я понимаю эту ошибку, но, к сожалению, я не могу гарантировать закрытие своего канала после того, как больше не буду получать входные сообщения, так как пользователь может закрыть приложение в любое время, поэтому работа все равно будет продолжаться в фоновом режиме службы Windows. (вроде как работает антивирусный сканер). Пользователь должен иметь возможность без каких-либо помех запускать и закрывать приложение инструмента управления выигрышем.
Теперь об ошибке я получаю сразу после выполнения моего Unsubscribe()
вызова, который является вторым последним вызовом перед завершением работы приложения, и, как я считаю, является предпочтительным способом отключения клиента WCF. Все, что отписывается перед закрытием соединения, просто удаляет идентификатор клиента из массива, который хранился локально в wcf-сервисе win-службы (так как это экземпляр SHARED, предоставляемый как службой win, так и приложением windows, так как служба win может выполнять работу в запланированные события сами по себе) и после удаления массива идентификаторов клиентов я выполняю то, что, я надеюсь (чувствую), должно быть чистым разъединением.
Результатом этого, помимо получения исключения, является зависание моего приложения, пользовательский интерфейс полностью заблокирован, индикаторы выполнения и все в середине, со всеми признаками, указывающими на наличие состояния гонки или тупик WCF [вздох], но Сейчас я достаточно разбираюсь в потоках, и я думаю, что это относительно изолированная ситуация, и я читаю исключение как есть, я не думаю, что это проблема «потока» как таковая, поскольку в ней больше говорится о проблеме раннего отключения, которая затем превращает все мои темы в хаос, возможно, вызывая блокировку.
Мой Unsubscribe()
подход на клиенте выглядит следующим образом:
public void Unsubscribe()
{
try
{
// Close existing connections
if (channel != null &&
channel.State == CommunicationState.Opened)
{
proxy.Unsubscribe();
}
}
catch (Exception)
{
// This is where we receive the 'System.ServiceModel.ProtocolException'.
}
finally
{
Dispose();
}
}
И мой Dispose()
метод, который должен выполнить чистое отключение:
public void Dispose()
{
// Dispose object
if (channel != null)
{
try
{
// Close existing connections
Close();
// Attempt dispose object
((IDisposable)channel).Dispose();
}
catch (CommunicationException)
{
channel.Abort();
}
catch (TimeoutException)
{
channel.Abort();
}
catch (Exception)
{
channel.Abort();
throw;
}
}
}
И служба WCF Subscription()
атрибуты аналога и класса (для справки) в службе Windows сервер (здесь нет ничего сложного, и мое исключение происходит на стороне клиента):
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TransferService : LoggableBase, ITransferServiceContract
{
public void Unsubscribe()
{
if (clients.ContainsKey(clientName))
{
lock (syncObj)
{
clients.Remove(clientName);
}
}
#if DEBUG
Console.WriteLine(" + {0} disconnected.", clientName);
#endif
}
...
}
Интерфейс:
[ServiceContract(
CallbackContract = typeof(ITransferServiceCallbackContract),
SessionMode = SessionMode.Required)]
public interface ITransferServiceContract
{
[OperationContract(IsInitiating = true)]
bool Subscribe();
[OperationContract(IsOneWay = true)]
void Unsubscribe();
...
}
Интерфейс контракта обратного вызова, он не делает ничего особенного, просто вызывает события через делегатов и т. Д. Я включил это, чтобы показать вам мои атрибуты. Я уже ослабил один набор взаимоблокировок, добавив UseSynchronizationContext = false
:
[CallbackBehavior(UseSynchronizationContext = false,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TransferServiceCallback : ITransferServiceCallbackContract
{ ... }
Действительно надеюсь, что кто-нибудь может мне помочь! Большое спасибо =:)