views:

1278

answers:

5

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.

A: 

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.

Dani
WCF has a defualt timeout of 60s which can be change, It is a designed for SOA, and I'm not sure that behavior like comet is built into it, altough you can "force" it (never tried it, but you can set the timeout to 1 hour, and then have the operation wait in the server....) I don't think it will be wise.
Dani
A: 

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...

Vijay Patel
+1  A: 
Mark
"A dual binding exposes the IP address of the client to the service. " but I said that there is a firewall that stop the server creating a connection to the cleint, so how will this work?
Ian Ringrose
Sorry, missed that part regarding not being able to make a physical connection from the server to the client.
Mark
+1 for pointer to .NET Service Bus
Ian Ringrose
+2  A: 

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.

BennyM
+9  A: 

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.

Drew Marsh
+1 @Drew: Regarding the server implementation, can you explain why it's better to return an IAsyncResult than just sleeping in a loop on the server until the service has something to return?
Sly
When you sleep in a loop or block the WCF thread using any other mechanism you're actually eating up one of the WCF's runtime's threads. When you do this it is unable to field any other incoming requests with that thread and eventually you can end up starving the entire runtime (and thread pool) causing serious performance degradation for your service. Remember, by default, a WCF service will only allow 16 concurrent calls. It would be very easy in this pattern to chew those up. While you can up that number through the maxConcurrentCalls setting, it's only going to delay the inevitable. :)
Drew Marsh
FWIW this same pattern exists in ASP.NET. They have an asynchronous programming model as well which they expose via the IHttpAsyncHandler interface. It too is extremely underutilized. The key is you can't be doing CPU bound work. It's not about farming the work off to another background thread, 'cause ultimately that competes for the same CPU resources. In those cases you might as well keep it synchronous. It's about calls to other resources which themselves can block and take time: *any* network call, file system, reading/writing from a queue, etc.
Drew Marsh
@Drew Marsh, Thanks for the most informative answer on how to implement long polling with WCF. Do you know of a WCF channel that does this internally? E.g I want a channel that logically two way but physically incoming only.
Ian Ringrose
The closest you can get is the PollingDuplexHttpBinding that comes with Silverlight, but they didn't incorporate this into WCF... even in 4.0. :(
Drew Marsh