I am not exaggerating when I say I have now spent two weeks (that’s 10 man days) fighting tooth and nail with Microsoft’s Silverlight PollingDuplexHttpBinding in an attempt to find a way to push notifications to Silverlight clients. If you’re like me at this point you’re probably thinking: what a muppet I got the PubSub sample and Scaled out (cough cough) PubSub sample working in next to no time, piece of cake. Well I did to. It was only once I started to “use” the binding in a real application that the pain started.

First it’s not abundantly clear how the binding works. After a couple of days of mucking around I ended up with a reasonable understanding of how it operates and the best description of the binding I came across is from Peter McGrattan’s “Silverlight 2 WCF Polling Duplex Support” articles: Part 1: Architecture, Part 2: The Server and Part 3: The Client. For an interface that boils down to 3 methods: Subscribe, Publish and NotifyReceived; and considering I already understood how HTTP works including how it needs to be bent to facilitate push communications I was expecting it to take 5 minutes to get to grips with the binding. While I wasn’t overjoyed at having to take a deep dive to “use” the binding because it was Microsoft and WCF I considered it likely to be a worthwhile investment in time, how wrong I was!

The gripes:

IPubSub
The IPubSub interface provides two one way methods for the Silverlight client, Publish and Subscribe.

namespace Microsoft.ServiceModel.PollingDuplex.Scalable
{
    [ServiceContract]
    public interface IPubSub : IPollingDuplex
    {
        [OperationContract(IsOneWay=true)]
        void Subscribe(string topic);

        [OperationContract(IsOneWay = true)]
        void Publish(string topic, string content);
    }
}

That’s fine, nice and simple. Or at least that’s what I thought. Because the methods are one way there is obviously no way to respond to the client regarding the success of their attempt to Subscribe. In my case I let my clients set a filter for real-time notifications by sending it as the topic in the Subscribe method. In order to decide whether the filter is allowed the Subscribe call needs to be authenticated. To do that I add a custom SOAP header and check it on the server. No problems so far. If the subscribe method is authorised it’s fine and dandy no response needs to be sent to the client it can safely assume the filter was accepted. But what if the Subscribe was rejected? Hmm now there is no way to let the client know. Ok a bit of a pain but I reasoned that can be lived with I’ll just track the client’s address on the server and when they request a notification will tell them then.

IPollingDuplex
That leads onto the second interface that’s exposed by the channel which is IPollingDuplex.

namespace Microsoft.ServiceModel.PollingDuplex.Scalable
{
    [ServiceContract]
    public interface IPollingDuplex
    {
        [OperationContract(
            AsyncPattern = true,
            Action="http://docs.oasis-open.org/ws-rx/wsmc/200702/MakeConnection",
            ReplyAction="*")]
        IAsyncResult BeginMakeConnect(MakeConnection poll, AsyncCallback callback, object state);
        Message EndMakeConnect(IAsyncResult result);
    }
}

Again it’s simple and lean as a service interface should be. It’s not as intuitive as IPubSub in that BeginMakeConnect and EndMakeConnects’ functions aren’t blindingly obvious. Luckily the namespace on the Action provides a big enough hint to run off and lookup the WS-MakeConnection standard and from there it’s possible to grasp that the BeginMakeConnect and EndMakeConnect calls are where the nuts and bolts of the HTTP polling take place. When BeginMakeConnect is called the Silverlight client sends a HTTP request with its address which doesn’t change for the application’s lifetime and is of the form http://docs.oasis-open.org/ws-rx/wsmc/200702/anonymous?id=ffd19b9b-0390-409d-8a4b-8f3194f480b9 asking for any messages the server has pending for it. There is also a concept of sessions for each address and each Subscribe call creates a new SessionId. The server needs to track which SessionId a notification belongs to and set it accordingly. The Silverlight client side of the PollingDuplexHttpBinding will take care of de-multiplexing the responses and firing the NotifyReceived event for the correct listener.

At this point I came back to the problem of the unauthorised Subscribes and started looking around for a way to inform the client to not send any more BeginMakeConnect requests because there would never be anything waiting for it. This is where the banging the head against the brick wall started to hurt a bit and in hindsight is where I should have called it quits and wasted only a couple of days instead of two weeks.

The first thing I tried was to send an empty payload back to the client in EndMakeConnect. That was a big mistake as that simply results in the client thinking it’s got a notification and results in it immediately sending another BeginMakeConnect request to get the next notification. I tried throwing an exception in EndMakeConnect which worked a bit better since it meant a response never got sent to the client and the next BeginMakeConnect at least wouldn’t turn up for 90 seconds. But I wanted to stop the client sending any BeginMakeConnect requests at all so I started looking into MakeConnection class to see if there was a way I could send an error to the client. I played around with MessageFaults and while it was easy enough to create and send one from the server I could not get it to reach my Silverlight application and I got the distinct impression the PollingDuplex channel was gobbling it up and ignoring it.

public Message CreateErrorResponse(Exception excp)
{
    FaultException fe = new FaultException(excp.Message);
    MessageFault fault = fe.CreateMessageFault();
    Message response = Message.CreateMessage(MessageVersion.Default, fault, null);

    HttpResponseMessageProperty http = new HttpResponseMessageProperty();
    http.StatusCode = System.Net.HttpStatusCode.OK;
    http.SuppressEntityBody = true;
    response.Properties.Add(HttpResponseMessageProperty.Name, http);

    return response;
}

This was turning out to be way way harder than it should have been and I was starting to swear under my breath at the short sightedness of the Microsoft developers who appear to have taken some big shortcuts in the binding’s implementation.

In the end I had to resort to the the very crude approach of sending a notification with “closesession” in it as a way to tell my Silverlight application to stop sending requests for notifications. Not what I’d call elegant and of course very fragile for future use but at least it works.

IIS6
This is where my blood really starts to boil. After a week of trying (that’s 5 man days) I am yet to have anything but limited success using the PollingDuplexHttpBinding with IIS6. The problem is that everything will start off fine, push notifications will be flowing then a few more clients will connect and still everything is ok and then a few more clients connect and IIS6 just decides to go on a holiday and not only stop processing the requests for the IPubSub service but all ASP.Net requests full stop. It seems like the binding works a lot better with IIS7, at least there seem to be a few comments around the place from people that have built real working applications with the binding and I’m assuming they must be using IIS7, but in my case my deployment environment is set in stone and Windows Server 2003 with IIS6 is what’s available.

Now this issue gets a mention in a couple of places, the Silverlight team blog has an article about an issue with ASP.Net session state causing a conflict Having a PollingDuplex service and any other WCF service in the same website causes Silverlight calls to be slow. The idea being to turn off, or avoid, ASP.Net session management with the PollingDuplex channel because it forces IIS to process every request for a particular session in the order they are received and if one of those requests is a polling request that is going to sit around for up to 90 seconds that’s a problem. In my case I made sure that my web site had session state completely turned off. Another article touches on IIS/WCF Tuning for use with the PollingDuplex channel. What that article fails to state in big bold letters is either that using the PollingDuplexHttpBinding channel with IIS6 is impossible for more than a handful of clients due to the way requests are pipelined or provide the IIS6 configuration settings that are needed ot be able to use the channel. It does link off to a further article about ASP.NET Thread Usage on IIS 7.0 and 6.0 which goes into a more in-depth discussion and then it links off to a knowledge base article Contention, poor performance, and deadlocks when you make Web service requests from ASP.NET applications that finally gets into the nitty-gritty of what settings to tweak. Unfortunately in my case after doing the tweaking the issue doesn’t go away, it does improve but after somewhere between 5 and 10 minutes IIS6 will just stop processing requests. Without the tweaks it was seemingly terminal and I’d need to kill the w3p.exe process to get ASP.Net working again,. With the tweaks it is able to recover itself after a while, clear the request pipeline and keep processing requests. It should be noted that I’m not talking about big loads here. I Monitored the performance monitor counter “ASP.NET Applications\Requests Executing” and at the point IIS6 gave up the ghost the counter hit a maximum of 50.

Pissed off and moaning about it
I came to PollingDuplexHttpBinding to replace a raw TCP socket connection from my Silverlight clients to my server. That mechanism worked very well but had no security. Rather than implement a mechanism to transfer a symmetric key I thought a better approach would be to avoid re-inventing the wheel and use HTTPS and that’s where fate got decidedly cruel and I stumbled across PollingDuplexHttpBinding.

Since .Net came into existence we as developers have gotten used to an incredibly high standard of product from Microsoft. Up until now I can’t think of case where I’d ever had reason to bemoan a piss poor design effort (although the initial .Net v1.0 WS-Enhancements library wasn’t the greatest). It’s one thing to for Joe Bloggs to drop a code sample on sourceforge and developers will be wary of investing a lot of effort in getting to grips with the code and another thing altogether for Microsoft to evangelise a new plugin for their flagship networking stack and throw it out half-baked and unusable knowing that developers will waste time on it.

What have I learnt from the experience? Not very damn much which is the annoying thing. When all you do is fight bad libraries or interfaces it leaves you severely pissed off. To the PollingDuplexHttpBinding developers you need to pick up your game to get to the same standard as the rest of WCF or at the very least use your product in a real application and then make it clear as crystal which deployment scenarios it works with and which ones it doesn’t. In this case I’ll do it for you:

The PollingDuplexHttpBinding does not work reliably under minimal load with IIS6!

A cut down version of the code I was using in my application with PollingDuplexHttpBinding.