After working in web development for many years its rare that you get to work with a technology that changes how you program a web app. I recently had the opportunity to work with one such web technology generally known as Comet. While it has been around for several years, its become more common as the demand for real time data and responsive applications has increased.
I’ll walk through creating a real time stock price tracker using SignalR, knockoutjs, and underscore to show how easy it is to feed real time data to a client browser without the typical heavy-handed async updates and DOM manipulation of most applications.
Setup Hub
For our simple example the client will only be listening for messages, and not sending them to the server. So we only need an empty class that inherits from Hub to send updates to the client.
public class DemoHub : SignalR.Hubs.Hub { }
Add NuGet packages
- jQuery – Dependency for signalr
- knockoutjs – viewmodel ->view binding framework
- signalr – Both client and server libraries for sync communication
- underscore.js – collection querying
Reference signalR as well the other javascript libraries:
@Scripts.Render("~/bundles/jquery") <script src="~/Scripts/jquery.signalR-1.1.3.js" type="text/javascript"></script> <script src="~/signalr/hubs" type="text/javascript"></script> <script src="~/Scripts/underscore.js" type="text/javascript"></script> <script src="~/Scripts/knockout-2.3.0.js" type="text/javascript"></script>
Send data
We’ll create a separate thread to send price updates to the client via the Hub.
protected void Application_Start() { .... var random = new Random(); ThreadPool.QueueUserWorkItem(_ => { var hubContext = GlobalHost.ConnectionManager.GetHubContext(); while (true) { hubContext.Clients.UpdatePrice(new DemoHubPriceUpdateModel { Symbol = "AAPL", Price = (random.Next(620, 650) + random.NextDouble())}); Thread.Sleep(500); } }); }
Create binding template
<table> <tbody> <tr> <th>Symbol</th> <th>Price</th> <th>Last Updated</th> </tr> </tbody> <tbody data-bind="foreach: stocks"> <tr> <td data-bind="text: symbol"></td> <td data-bind="text: price"></td> <td data-bind="text: updated"></td> </tr> </tbody> </table>
Create ViewModel
Here we will create the viewmodel, which is just a plain old javascript object. We will also create the function listener for when price updates are sent. The UpdatePrice function will be passed the data from the server side as JSON, and update the price and last updated date of the relevant stock.
function Stock(symbol, price, updated) { this.symbol = symbol; this.price = ko.observable(price); this.updated = ko.observable(updated); }; $(function () { var now = new Date(); var viewModel = { stocks: [ new Stock("AAPL", 648.11, now), new Stock("MSFT", 30.90, now), new Stock("FB", 19.05, now), new Stock("YHOO", 15.03, now)] }; $(function () { // Proxy created on the fly var demoHub = $.connection.demoHub; demoHub.UpdatePrice = function (priceUpdate) { _.chain(viewModel.stocks) .filter(function (stock) {return stock.symbol == priceUpdate.Symbol;}) .each(function (stock) { stock.price(priceUpdate.Price.toFixed(2)); stock.updated(new Date()); }); }; // Start the connection $.connection.hub.start(); }); ko.applyBindings(viewModel); });
Live Running App
I hope this example demonstrate the simplicity of working with real time data with a few open source libraries. The source code of this post is available for download here.