30
Jul 2010

Simple Long Polling in WCF - Server

Tags: .Net, C#, WCF, Anything Dev
comment icon15 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

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

Re: Parameters

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

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

A1

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

Great example. It's exactly

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

pass callback and object

Hi,

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

Janaka

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?

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.

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.

Since this is a RESTful

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

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.