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

发布于 2024-08-10 00:36:10 字数 769 浏览 5 评论 0 原文

另请参阅“WCF 推送到客户端 防火墙

我需要有一个连接到 WCF 服务器的 WCF 客户端,然后当服务器上的某些数据更改时,客户端需要更新其 。

由于客户端和服务器之间可能存在防火墙,因此

  • 所有通信都必须通过 HTTP
  • 服务器无法向客户端发出(物理)传出呼叫。

正如我所言 我正在编写客户端和服务器,我不需要将解决方案限制为仅使用肥皂等。


我正在寻找“长轮询" / "Comet " 等


感谢 Drew Marsh 关于如何在 WCF 中实现长轮询的信息最丰富的答案。不过,我认为 WCF 的主要“卖点”是,您只需将通道配置为即可完成此类操作在配置文件中使用。例如,我想要一个逻辑上双向但物理上仅传入的通道。

see also "WCF push to client through
firewall
"

I need to have a WCF client that connect to a WCF server, then when some of the data changes on the server the clients need to update its display.

As there is likely to be a firewall between the clients and the server.

  • All communications must be over HTTP
  • The server can not make an (physical) outgoing call to the client.

As I am writing both the client and the server I do not need to limit the solution to only using soap etc.


I am looking for built in surport for "long polling" / "Comet" etc


Thanks for the most informative answer from Drew Marsh on how to implement long polling in WCF. However I thought the main “selling point” of WCF was that you could do this sort of thing just by configuring the channels to be used in the config file. E.g I want a channel that logically two way but physically incoming only.

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

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

发布评论

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

评论(5

郁金香雨 2024-08-17 00:36:10

在我看来,您已经知道答案:使用长轮询。 :) 所以我想唯一需要解释的是如何使用 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 运行时以具有更高的超时,这是使用 完成的> (注意:此属性的测量单位为秒)。

在客户端中保持高效

如果您只是将客户端设置为同步调用服务,并且客户端在等待响应时阻塞 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,则需要确保使用 调用BeginInvoke 方法。

服务器上的效率

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

除了我之前提供的链接之外,您在 MSDN 中找不到太多文档,不幸的是,他们关于编写异步服务的示例不太有用。也就是说, Wenlong Dong 不久前写了一篇关于使用异步模型扩展 WCF 服务的文章,我强烈建议您查看。

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

更新的处方

由于这似乎是一个受欢迎的答案,我想我应该回到这里并根据最近的情况提供更新。此时,现在有一个名为 SignalR 的 .NET 库,它提供了这种确切的功能,这绝对是我推荐的方式实现与服务器的任何此类通信。

It sounds to me like you already know the answer: use long polling. :) So I guess the only thing left to explain is how you might be able to accomplish this with WCF and in the most efficient manner possible.


The basics:

  1. First, decide how long you want each "long poll" to be. For argument's sake I'm going to choose 5min timeouts.
  2. On the client side binding, change the sendTimeout="00:05:00".
  3. Just like using XmlHttpRequest (XHR) for long polling, when the timeout does actually occur, you will need to detect it and re-issue the next polling request. This is quite easy in WCF because there is a specific exception, TimeoutException, that you can catch to easily detect this was the issue vs. some other exception.
  4. Depending on how you're hosting your WCF service, you will need to make sure to configure yourself to allow processing for up to 5mins. From a pure WCF perspective you'll want to make sure you set the receiveTimeout="00:05:00". However, if you're hosting inside of ASP.NET you will also need to configure the ASP.NET runtime to have a higher timeout which is done using the <httpRuntime executionTimeout="300" /> (note: the measurements are in seconds for this attribute).

Being efficient in the client

If you just setup your client to synchronously call the service and the client blocks for 5mins while waiting for a response, that's not a very efficient use of system resources. You could put these calls on background threads, but that's still going to chew up a thread resource while the call is outstanding. The most efficient way to deal with this is to use async operations.

If you're creating your service contracts by hand, I would suggest checking out this section on MSDN on OperationContractAttribute.AsyncPattern for details on how to add a BeginXXX/EndXXX async method pair for each of your calls. However, if you're using svcutil to generate your operation contracts for you, all you need to do to have async methods generated is pass the /async option on the command line. For more details on this topic, check out the Synchronous and Asynchronous topic on MSDN.

Now that you've go your async operations define, the pattern is very much like working with XHR. You call the BeginXXX method to which you pass an AsyncCallback delegate. The BeginXXX method will return you an IAsyncResult, which you can either hold onto if you wanted to be able to wait on the operation (in more advanced scenarios) or ignore, and then the WCF infrastructure will asynchronously send the request to the server and wait for a response behind the scenes. When a response is received or an exception occurs, the callback you passed into the BeginXXX method will be invoked. Inside of this callback method you need to call the corresponding EndXXX method passing in the IAsyncResult that is handed to you. During the call to the EndXXX method you need to employ exception handling to deal with any kind of logical fault that may have occurred while calling the method, but this is also where you'd now be able to catch the TimeoutException we talked about earlier. Assuming you got a good response, the data will be the returned from the EndXXX call and you can react to that data in whatever way makes sense.

NOTE: One thing to keep in mind about this pattern is the nature of the threading. The async callbacks from WCF will be received on a thread from the managed thread pool. If you're planning on updating the UI in a technology such as WPF or WinForms, you need to make sure you marshal the calls back to the UI thread using the Invoke or BeginInvoke methods.

Being efficient on the server

If we're going to be worried about efficiency in the client, we should be doubly so when it comes to the server. Obviously this type of approach puts more demand on the server side because a connection must remain open and pending until there is a reason to send notification back to the client. The challenge here is that you only want to tie the WCF runtime up with the processing of those clients who are actually being sent an event. Everything else should just be asleep, waiting for the event to occur. Luckily the same async pattern we just used on the client side also works on the servers side. However, there is now a major difference: now you must return the IAsyncResult (and thus a WaitHandle) from the BeginXXX method which the WCF runtime will then wait to be signaled on before calling your EndXXX method.

You will not find much in the way of documentation inside of MSDN other than the links I've already provided earlier and, unfortunately, their samples on writing an async-service are less than useful. That said, Wenlong Dong wrote a piece about scaling WCF services with the async model some time ago that I highly recommend you check out.

Beyond this, I honestly I can't give too much advice on how best to implement the asynchronous model on the server side for you bcause it depends entirely on what kind of data source your events will be coming from in the first place. File I/O? A message queue? A database? Some other proprietary software with its own messaging service that you're trying to provide a façade over? I don't know, but they should all offer an async models of their own on which you can piggy back your own service to make it as efficient as possible.

Updated Prescription

Since this seems to be a popular answer, I figured I should come back here and provide an update given the recent changes in the landscape. At this point there is now a .NET library called SignalR which provides this exact functionality and is definitely how I would recommend implementing any such communication with the server.

梦亿 2024-08-17 00:36:10

如果服务器可以与服务总线建立传出连接,您可以实现一种回调类型。这样,客户端/服务器根本不需要了解彼此,只需要了解所依赖的服务总线。请参阅 .NET 服务总线

您将需要研究一下WSDualHttpBinding


WSDualHttpBinding 提供
对 Web 服务协议的相同支持
作为 WSHttpBinding,但用于
复式合同。 WSDualHttpBinding
仅支持 SOAP 安全性
需要可靠的消息传递。这
绑定要求客户端有一个
提供回调的公共 URI
服务的端点。这是
由 ClientBaseAddress 提供。一个
双重绑定暴露了IP地址
客户端到服务。客户
应使用安全性来确保
只连接到它信任的服务。


If the server could make an outgoing connection to a service bus you could implament a type of call back. This way the client/server would not need to know about each other at all, just the relying service bus. See .NET Service Bus

You will want to look into WSDualHttpBinding

The WSDualHttpBinding provides the
same support for Web Service protocols
as the WSHttpBinding, but for use with
duplex contracts. WSDualHttpBinding
only supports SOAP security and
requires reliable messaging. This
binding requires that the client has a
public URI that provides a callback
endpoint for the service. This is
provided by the ClientBaseAddress. A
dual binding exposes the IP address of
the client to the service. The client
should use security to ensure that it
only connects to services it trusts.

謸气贵蔟 2024-08-17 00:36:10

虽然不是 WCF,但您可以尝试使用 XMPP 来实现该功能。 InfoQ 上有一篇关于它和其他系统的文章。虽然文章指出 XMPP 不能通过 HTTP 使用,但使用 BOSH

有一些可用的 .NET 库 agsXMPP 就是其中之一。

我工作的公司开始使用它向应用程序推送更新通知,以便它刷新部分用户界面。

While not WCF you could try to use XMPP to get that functionality going. There's an article on InfoQ about it and other systems. While the article states that XMPP can't be used over HTTP, you can when using BOSH.

There are .NET libraries available agsXMPP to name one.

The company where I work is starting to use it to push update notifications to an application for it to refresh parts of the user interface.

我要还你自由 2024-08-17 00:36:10

Google 搜索“WCF 双工< /a>”。我已经使用 netTcpBinding(跨大陆)成功使用了此功能,但我不确定 basicHttpBinding。

但是,它确实需要服务器回调客户端。如果服务器不允许这样做,轮询可能是您唯一的选择......

Google for "WCF duplex". I've used this successfully using netTcpBinding (across continents), but I'm not sure over basicHttpBinding.

However, it does require the server to call back to the client. If the server isn't allowed to do this, polling may be your only option...

裸钻 2024-08-17 00:36:10

如果服务器无法调用客户端(通常不应该),您应该让客户端按照您指定的方式轮询服务器。
由于您已经具备 WCF 基础,因此只需为此添加一个操作即可。

IF the server cannot call the client (and it shouldn't usually) you should have the client polling the server as you specified.
since you have WCF foundation already in place, just add an operation for that.

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