我的WCF服务使用netTcpBinding,并且有一个回调对象。
我需要为多个并发客户端提供服务,并保留会话,因此服务用
进行修饰[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple]
为了避免线程死锁,回调类用
修饰[CallbackBehavior(UseSynchronizationContext=false)]
我使用SynchronizationContext
在UI线程中执行该方法。
问题在于,有时频道关闭没有理由(ICommunicationObject.Closing
事件被触发)。之后,我在任何后续服务调用中都会遇到异常。
查看跟踪文件,最后一条消息是回调调用,但是,永远不会调用回调方法。没有例外。
经过一些调试后,我发现只有在同步操作过程中进行回调调用时才会发生这种情况。步骤如下:
A
IsOneWay=true
B
IsOneWay=false
A
调用回调方法,但B
仍在执行。这应该不是问题,因为回调函数有UseSynchronizationContext=false
,因此回调调用可以在一个单独的线程中进行。
我无法在更简单的场景中重现问题。在一个简单的项目中执行这些步骤后成功执行。
知道可能发生的事情或如何识别问题?
答案 0 :(得分:10)
我认为可能发生的事情是客户端故障通道,因为它在收到回复消息时收到了回调消息。在带有net.tcp的WCF中,回调和回复使用相同的通道。
通常,您不应该在请求/回复(IsOneWay = false)OperationContract方法的主体内调用回调方法。最安全的事情是在进行双工时你的合同中没有任何请求/回复方法,但你可以安全地拥有它们,只要它们在返回之前不回调回调合同。 (可以在返回之后调用回调方法,例如从另一个工作线程调用)。
答案 1 :(得分:0)
感谢您的回复! 我可以解决错误。
这是一个序列化问题,我在服务和回调行为属性中添加了IncludeExceptionsInFaults=true
,然后我就能看到错误。
问题在于我发送的DataTable包含object类型的列。
答案 2 :(得分:0)
您应该在WCF包装类的顶部添加此属性:
[CallbackBehavior(UseSynchronizationContext=false)]
来自cauldwell.net:
事实证明,问题是ASP.NET使用(默认情况下)称为SynchronizationContext的小东西。尽我所知 (说实话,我没有仔细研究过这个问题) 它确保任何回调在UI线程上运行,从而 无需像在WinForms中那样调用Control.Invoke。在 我的情况是,额外的锁定给了适合的东西,而且确实如此 试图在一个不再存在的线程上清理东西, 因此为NullReferenceException。