使用回调时 WCF 双工通道被关闭

发布于 2024-08-11 09:00:01 字数 949 浏览 10 评论 0原文

我的 WCF 服务使用 netTcpBinding,并且有一个回调对象。

我需要为多个并发客户端提供服务,并维护会话,因此该服务被装饰为

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple]

为了避免线程死锁,回调类被装饰为 ,

[CallbackBehavior(UseSynchronizationContext=false)]

并且我使用 SynchronizationContext 在 UI 线程中执行该方法。

问题是有时通道会无缘无故关闭(ICommunicationObject.Closing 事件被触发)。之后,我在任何后续服务调用中都会遇到异常。

查看跟踪文件,最后一条消息是回调调用,但是,回调方法永远不会被调用。没有例外。

经过一些调试后,我发现只有在同步操作过程中进行回调调用时才会发生这种情况。步骤如下:

  1. 使用 IsOneWay=true 调用服务方法 A 使用
  2. IsOneWay=false 调用服务方法 B code>
  3. A 调用回调方法,但 B 仍在执行。

这应该不是问题,因为回调具有 UseSynchronizationContext=false,因此回调调用可以在单独的线程中进行。

我无法在更简单的场景中重现该问题。在一个简单的项目中按照这些步骤可以成功执行。

知道可能发生什么或如何识别问题吗?

My WCF service uses netTcpBinding, and has a callback object.

I need to service multiple concurrent clients, and mantain sessions, so the service is decorated with

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple]

To avoid thread deadlocks, the callback class is decorated with

[CallbackBehavior(UseSynchronizationContext=false)]

and I use SynchronizationContext to execute the method in the UI thread.

The problem is that sometimes the channel gest closed with no reason (ICommunicationObject.Closing event gets fired). After that, I get exceptions in any subsequent service call.

Looking in the trace file, the last message is a callback call, however, the callback method never gets invoked. There are no exceptions.

After some debugging I identified that this happens only when the callback call is made in the middle of a synchronous operation. The steps would be this:

  1. Call to service method A with IsOneWay=true
  2. Call to service method B with IsOneWay=false
  3. A invokes a callback method, but B is still executing.

This shouldn't be a problem because the callback has UseSynchronizationContext=false, so the callback call could be attended in a separate thread.

I was unable to reproduce the problem in a simpler scenario. Following these steps in a simple project executes successfully.

Any idea of what could be happening or how to identify the problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

老街孤人 2024-08-18 09:00:01

我认为可能发生的情况是客户端对通道产​​生了故障,因为它在等待回复消息时收到了回调消息。在带有 net.tcp 的 WCF 中,回调和回复使用相同的通道。

通常,您永远不应该在请求/回复 (IsOneWay=false) OperationContract 方法的主体内调用回调方法。最安全的事情是在进行双工时,合约中没有任何请求/回复方法,但只要它们在返回之前不回调到回调合约中,您就可以安全地拥有它们。 (返回后调用回调方法是可以的,例如从另一个工作线程)。

I think what's probably happening is the client is faulting the channel because it received the callback message when it was expecting the reply message. In WCF with net.tcp, callbacks and replies use the same channel.

As a rule, you should never call a callback method inside the body of a request/reply (IsOneWay=false) OperationContract method. The safest thing would be to not have any request/reply methods in your contract whatsoever when doing duplex, but you can safely have them just so long as they don't call back into the callback contract before returning. (It would be ok to call a callback method after returning, for example from another worker thread).

旧时模样 2024-08-18 09:00:01

您应该将此属性添加到 WCF 包装类的顶部:

[CallbackBehavior(UseSynchronizationContext=false)]

来自 cauldwell.net:

事实证明,问题在于 ASP.NET 使用(默认情况下)一个名为 SynchronizationContext 的小东西。据我所知
(说实话,我还没有彻底研究过)它的工作之一
它确保任何回调在 UI 线程上运行,从而
无需像在 WinForms 中那样调用 Control.Invoke。在
我的情况是,那个额外的锁给了一些合适的东西,而且它是
试图清理不再存在的线程上的东西,
因此出现 NullReferenceException。

You should add this attribute on the top of WCF wrapper class:

[CallbackBehavior(UseSynchronizationContext=false)]

From cauldwell.net:

The problem, it turned out, was that ASP.NET uses (by default) a little thing called the SynchronizationContext. As near as I can tell
(I haven't researched this thoroughly, to be honest) one of it's jobs
it to make sure that any callbacks get run on the UI thread, thereby
obviating the need to call Control.Invoke like you do in WinForms. In
my case, that additional lock was giving something fits, and it was
trying to clean stuff up on a thread that wasn't around any more,
hence to NullReferenceException.

怀念你的温柔 2024-08-18 09:00:01

感谢您的回复!
我可以解决这个错误。

这是一个序列化问题,我在服务和回调行为属性中添加了 IncludeExceptionsInFaults=true ,然后我就能够看到错误。

问题是我正在发送一个包含对象类型列的数据表。

Thanks for the response!
I could solve the error.

It was a serialization problem, I added IncludeExceptionsInFaults=true in the service and callback behavior attribute, and then I was able to see the error.

The problem was that I was sending a DataTable with columns of type object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文