WCF 服务器如何通知 WCF 客户端有关更改的信息?(比简单轮询更好的解决方案,例如彗星或长轮询)
-
19-09-2019 - |
题
也可以看看 ”WCF通过防火墙推向客户"
我需要有一个连接到 WCF 服务器的 WCF 客户端,然后当某些数据 变化 在服务器上,客户端需要 更新 它的显示。
因为客户端和服务器之间可能存在防火墙。
- 所有通信都必须通过 HTTP
- 服务器无法向客户端发出(物理)传出呼叫。
由于我正在编写客户端和服务器,因此我不需要将解决方案限制为仅使用肥皂等。
感谢 Drew Marsh 关于如何在 WCF 中实现长轮询的最翔实的答案。不过,我认为 WCF 的主要“卖点”是您只需在配置文件中配置要使用的通道即可完成此类操作。 例如,我想要一个逻辑上双向但物理上仅传入的通道。
解决方案
在我看来你已经知道答案了:使用长轮询。:) 所以我想唯一需要解释的是如何使用 WCF 并以最有效的方式完成此任务。
基础知识:
- 首先,决定每次“长轮询”的持续时间。为了便于讨论,我将选择 5 分钟超时。
- 在客户端绑定上,更改
sendTimeout="00:05:00"
. - 就像使用 XmlHttpRequest (XHR) 进行长轮询一样,当超时确实发生时,您需要检测它并重新发出下一个轮询请求。这在 WCF 中非常容易,因为有一个特定的例外,
TimeoutException
, ,您可以轻松检测到这是问题所在。其他一些例外。 - 根据您托管 WCF 服务的方式,您需要确保将自己配置为允许处理最多 5 分钟。从纯粹的 WCF 角度来看,您需要确保设置
receiveTimeout="00:05:00"
. 。但是,如果您在 ASP.NET 内部托管,您还需要配置 ASP.NET 运行时以具有更高的超时,这是使用<httpRuntime executionTimeout="300" />
(笔记: 该属性的测量值以秒为单位)。
在客户中保持高效
如果您只是将客户端设置为同步调用服务,并且客户端在等待响应时阻塞 5 分钟,那么这并不是非常有效地利用系统资源。您可以将这些调用放在后台线程上,但是当调用未完成时,这仍然会消耗线程资源。处理这个问题最有效的方法是使用异步操作。
如果您手动创建服务合同,我建议您查看 MSDN 上的此部分 OperationContractAttribute.AsyncPattern
有关如何添加的详细信息 BeginXXX
/EndXXX
每个调用的异步方法对。但是,如果您正在使用 svcutil
要为您生成操作合约,您只需传递以下内容即可生成异步方法 /async
命令行上的选项。有关此主题的更多详细信息, 查看 MSDN 上的同步和异步主题.
现在您已经定义了异步操作,该模式非常类似于使用 XHR。你打电话给 BeginXXX
您传递给的方法 一个 AsyncCallback
代表. 。这 BeginXXX
方法将返回一个 IAsyncResult
, ,如果您希望能够等待操作(在更高级的场景中),您可以保留它,也可以忽略它,然后 WCF 基础结构会将请求异步发送到服务器并在幕后等待响应。当收到回复时 或者 发生异常时,您传入的回调 BeginXXX
方法将被调用。在这个回调方法里面你需要调用相应的 EndXXX
方法传入 IAsyncResult
这是交给你的。在通话期间 EndXXX
方法中,您需要采用异常处理来处理调用该方法时可能发生的任何类型的逻辑错误,但这也是您现在能够捕获的地方 TimeoutException
我们之前谈到过。假设您得到了良好的响应,数据将从 EndXXX
调用,您可以以任何有意义的方式对该数据做出反应。
笔记: 关于此模式需要记住的一件事是线程的性质。来自 WCF 的异步回调将在线程上接收 托管线程池. 。如果您计划使用 WPF 或 WinForms 等技术更新 UI,则需要确保使用以下方法将回调编组回 UI 线程: Invoke
或者 BeginInvoke
方法。
在服务器上保持高效
如果我们要担心客户端的效率,那么当涉及到服务器时我们应该加倍担心。显然,这种方法对服务器端提出了更多要求,因为连接必须保持打开和挂起状态,直到有理由将通知发送回客户端为止。这里的挑战是您只想将 WCF 运行时与实际发送事件的客户端的处理联系起来。其他一切都应该处于睡眠状态,等待事件发生。幸运的是,我们刚刚在客户端使用的相同异步模式也适用于服务器端。然而,现在有一个重大区别:现在 你 必须返回 IAsyncResult
(因此 WaitHandle
) 来自 BeginXXX
WCF 运行时将在调用您的方法之前等待收到信号的方法 EndXXX
方法。
你会 不是 除了我之前提供的链接之外,您还可以在 MSDN 内部找到很多文档,不幸的是,他们关于编写异步服务的示例不太有用。也就是说, Wenlong Dong 写了一篇关于使用异步模型扩展 WCF 服务的文章 前段时间我强烈推荐你去看看。
除此之外,老实说,我无法就如何最好地在服务器端为您实现异步模型提供太多建议,因为这完全取决于您的事件首先来自哪种数据源。文件输入/输出?消息队列?数据库?您试图提供一个外观的其他一些具有自己的消息服务的专有软件?我不知道,但他们都应该提供自己的异步模型,您可以在该模型上搭载自己的服务以使其尽可能高效。
更新处方
由于这似乎是一个受欢迎的答案,我想我应该回到这里并根据最近的情况提供更新。此时已有一个名为的 .NET 库 信号R 它提供了这个确切的功能,并且绝对是我建议实现与服务器的任何此类通信的方式。
其他提示
如果服务器可以与服务总线建立传出连接,您可以实现一种回调类型。这样,客户端/服务器根本不需要了解彼此,只需要了解所依赖的服务总线。看 .NET 服务总线
你会想要调查一下 WSDualHttpBinding
WSDUALHTTPBINDING为WEB服务协议提供了与WSHTTPBINDING相同的支持,但可与双工合同一起使用。WSDUALHTTPBINDING仅支持SOAP安全性,并且需要可靠的消息传递。这种绑定要求客户端具有公共URI,该URI为服务提供了回调端点。这是由客户端戴德斯提供的。双重绑定将客户端的IP地址暴露于服务。客户应使用安全性来确保其仅连接到其信任的服务。
谷歌搜索“WCF双工”。我已经使用 netTcpBinding(跨大陆)成功使用了此功能,但我不确定 basicHttpBinding。
但是,它确实需要服务器回调客户端。如果服务器不允许这样做,轮询可能是您唯一的选择......
如果服务器无法调用客户端(通常不应该),您应该让客户端按照您指定的方式轮询服务器。由于您已经具备 WCF 基础,因此只需为此添加一个操作即可。