Server push (AKA long polling and Comet) is a relatively recent technology where servers initiate data transfer to connected browsers. Contrast this with the normal request-response interaction shown below:
For a long running job, the browser would have to constantly pester the server for updates. With server push, the browser could initiate the job, then sit back and let the server respond at its leisure:
For Google App Engine developers this is implemented by the Channel API. There are also third party services like Pusher and Beaconpush that provide this capability through their API. And recently, thanks to David Fowler and Damian Edwards, .NET developers can also integrate this technology into their projects using SignalR.
I’ve cooked up a small demo that uses SignalR to demonstrate one solution to the problem of conflicting updates. When multiple users act on the same set of information, it’s easy for it to get out of sync. This demo uses SignalR’s Hub to push updates to the users the moment they occur so they can immediately act on the changes.
Our application is a student registry form. Users can update a student’s name, GPA and enrollment status. A server section, visible only for demo purposes, shows us the state of the database. Because the most recent data is always pushed to the browser, we can take immediate action instead of discovering a save conflict at the end of a long form.
Shown right is your typical N-tier MVC stack. Browser requests are handled by the controller, data is passed to the service for the real legwork, the DB is consulted as necessary and the data is passed back up the chain to the browser. Fantastic. Where SignalR comes into play is when the
StudentService decides a legitimate update has taken place. It then notifies the Hub that a new update has occurred and it should broadcast the new record to all listening browsers.
Let’s take a look at the setup.
1 2 3 4 5 6
1 2 3 4
This starts the hub on the client side. Once started, a unique id is assigned to this browser which comes in handy as we’ll see later. Next we look at the Hub,
1 2 3 4 5 6 7 8
1 2 3 4 5
StudentHub derives from the abstract
updateStudent and sends it one argument -
transport. By the way,
StatusTransport is a wrapper around the data to be sent -
transport object sent by
Recall the video demo above. When the student is saved, all other browsers immediately show a dialog notifying them that an update recently occurred with the option to accept the recent changes. Note also that the browser that issues the save will receive an updated record from both the Ajax save response and the
StudentHub. We use the
ClientId to check for the identity of the sender and ignore the duplicate update when the client id is self.
To contrast this behavior with the conventional approach, disable the hub by commenting out this line in
Now, concurrency violations will only detected at save time.
I’ve built this example as an MVC project, but Webforms could be used as well and I’ve included a WCF service as an example. To use it, in the
Index.cshtml view, change the
serviceUrl ternary to
To wrap up,
- Very responsive UX. Events can be reported within milliseconds of a database save.
- Allows interaction with other connected clients (e.g., customer service chat).
- Can be added to existing projects.
- Introduces some complexity in the code, especially on the client side. More states to keep track of.
The source for this demo is available on github: Registry.