听起来你已经知道答案了:使用长轮询。:) 所以我想唯一需要解释的是你如何能够使用 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
async 方法对的详细信息。但是,如果您正在使用svcutil
为您生成操作合同,则生成异步方法所需要做的就是/async
在命令行上传递选项。有关此主题的更多详细信息,请查看 MSDN 上的同步和异步主题。
现在您已经定义了异步操作,该模式非常类似于使用 XHR。您调用BeginXXX
传递委托的AsyncCallback
方法。该BeginXXX
方法将返回一个IAsyncResult
,如果您希望能够等待操作(在更高级的场景中)或忽略,您可以保留它,然后 WCF 基础结构将异步发送请求到服务器并等待幕后的回应。当收到响应或发生异常时,将调用您传递给BeginXXX
方法的回调。在此回调方法中,您需要调用EndXXX
传递给您的相应方法IAsyncResult
。在通话期间EndXXX
方法,您需要使用异常处理来处理调用该方法时可能发生的任何类型的逻辑错误,但这也是您现在能够捕获TimeoutException
我们之前讨论过的地方。假设您得到了良好的响应,数据将从EndXXX
调用中返回,您可以以任何有意义的方式对该数据做出反应。
注意:关于这种模式要记住的一件事是线程的性质。来自 WCF 的异步回调将在托管线程池的线程上接收。如果您计划使用 WPF 或 WinForms 等技术更新 UI,则需要确保使用Invoke
orBeginInvoke
方法将调用编组回 UI 线程。
在服务器上高效
如果我们要担心客户端的效率,那么当涉及到服务器时,我们应该加倍担心。显然,这种方法对服务器端提出了更多要求,因为连接必须保持打开和挂起状态,直到有理由将通知发送回客户端。这里的挑战是您只想将 WCF 运行时与实际发送事件的那些客户端的处理联系起来。其他一切都应该只是睡着了,等待事件发生。幸运的是,我们刚刚在客户端使用的相同异步模式也适用于服务器端。但是,现在有一个主要区别:现在您必须从WCF 运行时将等待发出信号的方法中返回IAsyncResult
(因此 a WaitHandle
),然后再调用您的BeginXXX
EndXXX
方法。
除了我之前已经提供的链接之外,您不会在 MSDN 中找到太多的文档方式,不幸的是,它们关于编写异步服务的示例不太有用。也就是说, Wenlong Dong前段时间写了一篇关于使用异步模型扩展 WCF 服务的文章,我强烈建议您查看。
除此之外,老实说,我不能就如何最好地为您在服务器端实现异步模型提供太多建议,因为这完全取决于您的事件首先来自哪种数据源。文件输入/输出?消息队列?数据库?其他一些具有自己的消息服务的专有软件,您正试图为其提供外观?我不知道,但他们都应该提供自己的异步模型,您可以在其上搭载自己的服务以使其尽可能高效。
更新处方
由于这似乎是一个流行的答案,我想我应该回到这里并根据最近的形势变化提供更新。在这一点上,现在有一个名为SignalR的 .NET 库,它提供了这个确切的功能,并且绝对是我推荐的实现与服务器的任何此类通信的方式。