我正在使用netNamedPipeBinding
执行从Windows应用到Windows服务的进程间WCF通信。在使用回调关闭连接时收到WCF异常
现在我的应用程序在所有其他帐户中运行良好(消除了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客户端的首选方式。在关闭连接之前,所有的退订操作只是简单地将客户端ID从本地存储在win服务wcf服务上的数组中删除(因为win服务和windows应用程序共享此实例,因为win服务可以在预定的事件本身)和我执行客户端ID数组删除后,我希望(感觉)应该是一个干净的断开连接。
这样做的结果是,除了接收到一个异常,我的应用程序挂起,用户界面完全锁定,进度条和一切中途,所有迹象指出有竞争条件或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
{ ... }
真的希望有人能帮帮我!非常感谢= :)
我不知道具体的问题,但对于信息螺纹天翻地覆声音*可能是由于WCF如何使用同步上下文(通过在的WinForms等形式为)*。 – 2010-09-18 07:56:34
谢谢马克,是抓住了我,并通过阅读这个问题缓解了一组僵局,诀窍就是在回调协议上设置UseSynchronizationContext = false;我将这个添加到我的示例中。 – GONeale 2010-09-18 08:04:56
啊,对;很高兴看到你已经覆盖; p – 2010-09-18 08:10:24