Simple Long Polling in WCF - Server

30
Jul 2010

Simple Long Polling in WCF - Server

Tags: .Net, C#, WCF, Anything Dev
comment icon16 comment(s) |

Recently I've been working on a RESTful HTTP server in WCF for a really cool project that isn't public yet, but should be soon.  I say RESTful, but it's not religiously so; more accurately its REST-like.  Essentially it's as basic as can be so that client compatibility can be maximized.  Anyway, the need was presented that client would have to recieve notifications for certain events, and we were wary of letting thousands (tens/hundreds of thousands we hope?) of clients continuously poll the server for those status updates.  We looked into server push techniques, and of course there's no "standard" way of doing things.  While we plan to include some vendor-specific technologies eventually into the server we decided to go with Long Polling as a fall-back for clients that can't handle those specifics.  Long polling is a technique where a client sends a normal request to the server, but the server does not return a response until successful data is available, which could be a long time.  You also usually include a timeout to this request to keep the connections from getting too stale.  The client takes a timeout as a signal to just make another request and wait longer.  In whole the process works like this:

Server

  • Recieve Request
  • Wait (usually on another thread) for data to become available (ex: an object reaches a certain status)
  • Return Response

Client

  • Send Request
  • Wait for reply (usually on another thread)
  • If we get back a timeout error simply restart the process
  • If we get back a valid response this is our "notification"

Doing this in WCF is actually pretty easy.  WCF has the ability to use an "asynchronous pattern" on operation contract methods, which means that the message handling thread can go and handle other requests while your waiting thread does the work.  Once your work thread finishes a service method picks things back up and returns the response to the client.  This page does a good job of explaining the particulars, so I won't repeat them here.  It's pretty simple to setup on the server side, anyway:

[OperationContract]
public string GetNotification();

turns into

[OperationContract(UseAsyncPattern = true)]
public IAsyncResult BeginWaitNotification(AsyncCallback callback, object state);

public string EndWaitNotification(IAsyncResult result);

You now need two methods, one starting with "Begin" and the other with "End".  The begin method is responsible for returning an IAsyncResult implementation, which is passed to the end method once it completes; the end method being responsible for returning the result to the client.  Attached to this blog post is an abstract base class that implements IAsyncResult and provides timeout mechanisms and such.  To use it you would define your strongly-typed async result:

public class MyNotificationResult : LongPollingAsyncResult<string>
{
    //constructors, etc

    protected override DoWork()
    {
        //here we actually check for any notifications, if we have result we call base.Complete(...)
    }
}

And then in your service methods use it like so:

public IAsyncResult BeginWaitNotification(AsyncCallback callback, object state)
{
    return new MyNotificationResult(callback, state);
}

public string EndWaitNotification(IAsyncResult result)
{
    MyNotificationResult myResult = result as MyNotificationResult;
    if(myResult == null)
        throw new ArgumentException("result was of the wrong type!");

    myResult.WaitForResult();
    return myResult.Result;
}

And there you have it!  Clients can now use long polling against the WaitNotification operation.  In future posts I'll expand on the idea and analyze the implementation's behavior more, but for right now I'm just happy that WCF allows long polling in a relatively elegant way.

henji wo matte kudasaine!

AttachmentSize
LongPollingAsyncResult.zip1.72 KB

Subscribe to our Networks

Popular Tags by Blake

IW on Facebook

Comments

February 16, 2011

Anonymous

Parameters

You showed an example without parameters (i.e. GetNotification()),
what if I use a method like GetNotification(Guid personID)?

How must BeginGetNotification have to look like?

thx

February 16, 2011

BAnderton

Re: Parameters

Parameters are just added normally, so in your example the service method would look like:

BeginWaitNotification(Guid personId, AsyncCallback callback, object state);

February 16, 2011

Anonymous

A1

thanx for the quick answer and for the good guide on long polling with wcf!!!

February 19, 2011

Beat Kiener

Great example. It's exactly

Great example. It's exactly what I'm looking for. Thanks!

March 28, 2011

Anonymous

pass callback and object

Hi,

Would you be able to send me implementation of this post please?

Janaka

March 28, 2011

BAnderton

Re: pass callback and object

There's a zip file attached to the article that has the only real complicated part - the rest of the code is directly in the article since it's not that lengthy. The only implementation details I didn't show are very basic WCF stuff (like setting up the service, etc). Is there something specific you are looking for?

March 29, 2011

Anonymous

Re: pass callback and object

Thank you very much for your reply.

What I am struggling is not related to this post. I am new to threading. So I am not sure how I code inside Dowork().
I have a string variable in the session (or database). Once this variable changes (Happens in another function) i want to pass that value from DoWork() function. I am not sure how I do this.

March 29, 2011

BAnderton

Re: pass callback and object

DoWork might be called synchronously (on the same thread) or asynchronously (on a different thread) but in general you should assume it's on a different thread. Unless you're doing something complicated like writing to shared (and non-static) data this shouldn't be a problem, though. You have several options for accessing resources (databases, etc) from within DoWork, including but not limited to:

  1. Passing in or building resources in the constructor of the concrete result class (named MyNotificationResult in the example above)
  2. Accessing resources through static contexts in DoWork
  3. Assigning Properties when building the result object in the service (BeginWaitNotification in the example)

Basically you have the same options as you would any other potentially multithreaded object. Option #2 I would try to avoid as it might indicate a problem of using too much global data, but without specific knowledge about your architecture I can't say that for sure.

May 13, 2011

JohnA

Since this is a RESTful

Since this is a RESTful service can it be invoked from jQuery.ajax() like other RESTful services?

May 14, 2011

BAnderton

Certainly, currently I test

Certainly, currently I test my services with manually crafted GET/POST requests using fiddler so any sort of HTTP client (including jQuery) will do.

June 14, 2011

Wojtek

Hello. I have a little

Hello.

I have a little problem with your example.
When the client disconects while waiting for DoWork to finish
i don't get any exception or information that this happened.

The End function is called and it finishes gracefully...

Is there any way to find out that this particular client disconnected ?

June 14, 2011

BAnderton

Re: Hello. I have a little

Not to my knowledge. This is one of the drawbacks of this implementation of long polling; the client may not be in a state to receive the message but the full process must finish which can lead to performance issues server-side. From how I understand it you could achieve better results if you had lower-level/more-manual access to the HTTP requests, but I've never had time to fully investigate whether this is feasible.

If you find anything let me know and I'd be more than happy to update the example to include these improvements.

July 1, 2011

J de Swardt

Connections running out

Hi Blake,

Thanks for the awesome article, really explains the concept well. I am however running into a bit of trouble after implementing a long polling framework. When I test on my local machine (Windows 7) I can only connect 10 sessions to the polling framework. Is this something I'm doing wrong, or just Windows 7 not allowing more connections?

Kindly,
Johann

July 1, 2011

BAnderton

Re: Connections running out

Not 100% sure on this since we never ended up doing load testing with this technique (we switched the application to short polling and platform-specific push messages for various reasons) but I'd probably say this has to do with some connection limit within WCF itself. This thread seems to support that theory:

http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/2df5458f-3b83-4...

I would adjust your service behavior's throttling configuration as described in the accepted answer post and see if that doesn't help out.

December 7, 2011

John Bushell

WCF Max Instances seems to be limited to 10

Hi Johann,

It seems that Microsoft have capped the number of threads to 10 on the client OS -Windows 7. I also had the same problem.

Blake: great article thanks.

http://stackoverflow.com/questions/7822477/wcf-max-instances-seems-to-be...

October 29, 2012

Leo

Can U send me a whole example?

I didn't understand how to integrate the server with LongPollingAsyncResult, and how is work in the client side
10X

Search