WCF服务器如何通知WCF客户端有关更改?(更好的解决方案然后简单的轮询,例如Comet或长轮询)

Ian*_*ose 32 .net wcf design-patterns comet long-polling

另见" WCF通过防火墙推送到客户端 "

我需要一个连接到WCF服务器的WCF客户端,然后当服务器上的某些数据发生变化时,客户端需要更新其显示.

因为客户端和服务器之间可能存在防火墙.

  • 所有通信都必须通过HTTP
  • 服务器无法对客户端进行(物理)传出呼叫.

当我写客户端和服务器时,我不需要将解决方案限制为仅使用肥皂等.


我正在寻找" 长期投票 "/" 彗星 "等的内置支持


感谢Drew Marsh提供的关于如何在WCF中实现长轮询的最丰富的答案.但是我认为WCF的主要"卖点"是你可以通过配置在配置文件中使用的通道来做这种事情. 例如,我想要一个逻辑上只有两个但只是物理传入的频道.

Dre*_*rsh 49

听起来像你已经知道答案:使用长轮询.:)所以我想唯一要解释的是你如何能够以最有效的方式完成WCF.


基础:

  1. 首先,决定你希望每次"长期民意调查"的持续时间.为了论证,我将选择5分钟超时.
  2. 在客户端绑定,更改sendTimeout="00:05:00".
  3. 就像使用XmlHttpRequest(XHR)进行长轮询一样,当实际发生超时时,您需要检测它并重新发出下一轮询请求.这在WCF中非常简单,因为有一个特定的例外,TimeoutException您可以捕获以轻松检测到这是问题与其他一些异常.
  4. 根据您托管WCF服务的方式,您需要确保自己配置为允许最多5分钟的处理.从纯WCF的角度来看,您需要确保设置receiveTimeout="00:05:00".但是,如果您在ASP.NET内部托管,则还需要将ASP.NET运行时配置为使用更高的超时<httpRuntime executionTimeout="300" />(注意:此属性的测量值以秒为单位).

在客户端高效

如果您只是将客户端设置为在等待响应时同步调用服务和客户端阻塞5分钟,那么这不是非常有效地使用系统资源.你可以将这些调用放在后台线程上,但是当调用未完成时,它仍然会咀嚼一个线程资源.处理此问题的最有效方法是使用异步操作.

如果您手动创建服务合同,我建议您在MSDN上OperationContractAttribute.AsyncPattern查看此部分,以获取有关如何为每个调用添加BeginXXX/ EndXXXasync方法对的详细信息.但是,如果您正在使用svcutil为您生成操作合同,那么生成异步方法所需要做的就是/async在命令行上传递该选项.有关此主题的更多详细信息,请查看MSDN上的同步和异步主题.

现在您已经进行了异步操作定义,该模式非常类似于使用XHR.您调用BeginXXX方法,你传递一个AsyncCallback代表.该BeginXXX方法将返回一个IAsyncResult,如果您希望能够等待操作(在更高级的方案中)或忽略,您可以保留,然后WCF基础结构将异步地将请求发送到服务器并等待在幕后回应.收到响应发生异常时,将调用传递给BeginXXX方法的回调.在这个回调方法的内部,你需要调用EndXXX传递IAsyncResult给你的相应方法.在调用EndXXX方法期间,您需要使用异常处理来处理调用方法时可能发生的任何类型的逻辑错误,但这也是您现在能够捕获TimeoutException我们之前讨论过的问题的地方.假设您得到了良好的响应,数据将从EndXXX调用返回,您可以以任何有意义的方式对该数据做出反应.

注意:关于这种模式要记住的一件事是线程的性质.来自WCF的异步回调将在来自托管线程池的线程上接收.如果您计划使用WPF或WinForms等技术更新UI,则需要确保使用InvokeBeginInvoke方法将调用封送回UI线程.

在服务器上高效

如果我们要担心客户端的效率,那么在涉及服务器时我们应该加倍.显然,这种方法对服务器端提出了更多要求,因为连接必须保持打开状态并等待,直到有理由将通知发送回客户端.这里的挑战是您只想将WCF运行时与实际发送事件的客户端的处理联系起来.其他一切都应该睡着了,等待事件发生.幸运的是,我们在客户端使用的异步模式也适用于服务器端.但是,现在有一个重要区别:现在必须返回IAsyncResult(因此WaitHandle从)BeginXXX方法,WCF运行时会那么等待你打电话之前要对信号EndXXX的方法.

除了我之前已经提供的链接之外,你不会在MSDN内部找到很多文档,不幸的是,他们编写异步服务的样本不太有用.也就是说,文龙东写了一篇关于使用异步模型扩展WCF服务的文章,我强烈建议你看一下.

除此之外,老实说,我不能就如何最好地在服务器端实现异步模型给出太多建议,因为它完全取决于您的事件将首先来自何种类型的数据源.文件I/O?一个消息队列?一个数据库?一些其他专有软件有自己的消息服务,你试图提供一个外观?我不知道,但他们都应该提供自己的异步模型,您可以在这些模型上备份自己的服务,以使其尽可能高效.

更新处方

由于这似乎是一个受欢迎的答案,我想我应该回到这里,并根据最近的景观变化提供更新.此时,现在有一个名为SignalR的.NET库,它提供了这种确切的功能,我肯定会建议如何与服务器实现任何此类通信.

  • 当您在循环中休眠或使用任何其他机制阻塞WCF线程时,实际上实际上是在消耗WCF运行时线程之一。当您执行此操作时,它将无法使用该线程来处理任何其他传入请求,最终您最终可能会饿死整个运行时(和线程池),从而导致服务的性能严重下降。请记住,默认情况下,WCF服务将仅允许16个并发调用。以这种方式咀嚼那些东西非常容易。尽管您可以通过maxConcurrentCalls设置增加该数字,但这只会延迟不可避免的情况。:) (2认同)
  • @Drew Marsh,感谢您提供有关如何使用WCF进行长时间轮询的最有用的信息。您知道内部有WCF频道吗?例如,我想要一个逻辑上双向但仅物理上传入的通道。 (2认同)