SignalR And Knockout In ASP.NET Web Pages Using WebMatrix

4.75 (24 votes)

SignalR is a library that simplifies the creation and management of persistent connections between web servers and clients. This facilitates the development of applications that can display updates to data held on the server in real-time. Chat applications are the most obvious beneficiaries of this technology, but line-of-business applications that need to report availability to users can benefit too. Here, I look at extending the canonical SignalR chat example to incorporate a "who's typing" feature, and I also extend my previous Knockout example to use SignalR.

First, what is the problem that SignalR is designed to solve? The web works on a Request-Response model. Browsers and other user agents make requests and web server provide a response to that request.The response is sent to the delivery address provided in the request by the user agent. And that is the natural order of things on the Web - servers can't make responses without a request. For the most part, this is not an issue, but if you want to display real-time updates on your web page, you have needed to resort to techniques like repeatedly polling the server using AJAX to see if any changes had been made to data. Alternatively, you could use Comet technology, which keeps a persistent connection open between the server and the client. HTML5 introduced two new techniques - Server Sent Events and WebSockets. SignalR is a user-friendly wrapper around all these technologies that makes it a lot easier to create applications that require the real-time display of data. SignalR utilises HTML5 Web Sockets API where it is available, and falls back onto other technologies where they are not - Server Sent Events, Forever Frames or Long Polling, the last two of which are Comet techniques.

SignalR is currently in pre-release - Release Candidate 1 to be precise. It is available via Nuget or Github. However, since it is pre-release, it is not available via the WebMatrix Nuget client. But you can get it using Visual Studio (and Express For Web version, which is free) if you choose "Include Prerelease" instead of the default "Stable Only" option. Or you can use the Package Manager Console and simply type:

Install-Package Microsoft.AspNet.SignalR -Pre

It is recommended to install the package this way (via Nuget) as there are quite a few bits and pieces to be installed:


The centre piece of a SignalR application is a hub, which is similar to a Controller in ASP.NET MVC. A hub is responsible for receiving input and generating output. Hubs are written as server-side classes that inherit from Microsoft.AspNet.SignalR.Hubs.Hub. Public methods created in a hub class are intended to be called from client code. They typically result in a response being sent to the client. Here's the hub and method that the Chat example at the ASP.NET web site features:

using Microsoft.AspNet.SignalR.Hubs;

public class ChatHub : Hub
    public void Send(string name, string message)
        Clients.All.broadcastMessage(name, message);

This should be saved as ChatHub.cs (a C# class file) in App_Code. A using directive is added to the top of the file which makes Microsoft.AspNet.SignalR.Hubs available to the code. At runtime, a JavaScript file is generated dynamically which contains a client-side implementation of the public Send method so that it can act as a proxy to the server-side method. You write an implementation of the broadcastMessage method in client-code so that the Hub method can call it and thereby provide a response. You can also determine who should receive the response through the options available:


Here's the full client-side code starting with the Layout page:


<!DOCTYPE html>

<html lang="en">
        <meta charset="utf-8" />
        <link href="~/Styles/site.css" rel="stylesheet" type="text/css" />
        <script src="~/Scripts/jquery-1.6.4.min.js" ></script>
        <script src="~/Scripts/jquery.signalR-1.0.0-rc1.min.js"></script>
        <script src="~/signalr/hubs"></script>
        @RenderSection("script", required: false)

Notice that there is a reference to a script called hubs in a signalr folder, neither of which exist. This is a placeholder for the dynamically generated script that translates the Hub methods to client code.



    <div class="container">
        <input type="text" id="message" />
        <input type="button" id="sendmessage" value="Send" />
        <input type="hidden" id="displayname" />
        <ul id="discussion"></ul>

@section script{
    <script type="text/javascript">
        $(function () {
            var chat = $.connection.chatHub;

            chat.client.broadcastMessage = function (name, message) {
                $('#discussion').append('<li><strong>' + name
                    + '</strong>:&nbsp;&nbsp;' + message + '</li>');

            $('#displayname').val(prompt('Enter your name:', '')); 
            $.connection.hub.start().done(function () {
                $('#sendmessage').click(function () {
                    var encodedName = $('<div />').text($('#displayname').val()).html();
                    var encodedMsg = $('<div />').text($('#message').val()).html();
                    chat.server.send(encodedName, encodedMsg);

Some HTML elements are created at the top of the file - a text box, button, a hidden field and an unordered list. In the script block, a client-side proxy is created for the server-side ChatHub class:

var chat = $.connection.chatHub;

The client-side version of the hub is generated using camel-case (first word lower case). Remember that you have to write your own client-side implementation of the dynamic broadcastMessage method? The next section shows that. It takes the two strings provided by the Hub method, and uses them to generate a list item that is added to the unordered list. The next couple of lines set up the user by prompting for a name which is stored in the hidden field, and setting the focus on the textbox. Then the connection to the hub is opened, and a click event handler is added to the button which results in the Send method in the server version of the hub being invoked:

chat.server.send(encodedName, encodedMsg);

So just to recap, the button click invokes the client-side chat.server.send method, which calls the public ChatHub.Send method, which responds with Clients.All.broadcastMessage which invokes the client-side chat.client.broadcastMessage function.

There is one final thing needed to get this working, asn that is to register the default route for hubs, which is best done in an _AppStart.cshtml file:

@using System.Web.Routing
@using Microsoft.AspNet.SignalR


The chat example is easy to understand and illustrates the basic workflow nicely. But it is not a complete application by any stretch of the imagination. It needs more, and a common feature of chat applications is an indicator of who is currently typing. We can use the workflow logic above to plan an implementation.

Something on the client needs to invoke a server-side method. Keystrokes are as good an indication of typing as any, so that will do:

$('#message').keypress(function () {
    var encodedName = $('<div />').text($('#displayname').val()).html();

From the definition of the client method, it should be easy to discern the name and signature of the additional method required in the ChatHub class:

public void IsTyping(string name){

With each keypress, the name of the current user is passed to the server-side IsTyping method, which responds by calling a client-side function called sayWhoIsTyping:

chat.client.sayWhoIsTyping = function (name) {
    $('#isTyping').html('<em>' + name + ' is typing</em>');
    setTimeout(function () { 
    }, 3000);

It's a rough and ready function, which takes the name passed from the server-side method, and displays it as part of a string in a div with an ID of isTyping. The text is cleared after 3 seconds.

SignalR with Knockout

I have written about Knockout before. If you are not sure what Knockout is all about, you should read the previous article first. In that previous article, the example shows a simple application where the user can select a products, and from the resulting list, select one product to view the details. There is a simple button that results in the ViewModel's unitsInStock value decreasing by one as if a purchase had been made, and the UI being updated as a result. And that's one of the benefits of Knockout - changes to observable values in the ViewModel result in that change being reflected wherever it is bound in the UI. But the change is localised to the individual user's browser. If a product unit is actually purchased, or indeed if more are made available, it would be a really good idea if ALL current users are notified of the change in unitsInStock in real-time, right? Sounds like a task for SignalR.

The number of changes needed to the existing Knockout sample code are actually quite small. I amended the existing ViewModel buy function and added another function to manage reordering products. I also added two computed observables (they used to be called dependent observables); one that works out whether the user can buy a product based on availability, and the other that works out whether the reorder level has been reached: = function() {
    var id = this.productId();

viewModel.reorder = function() {
    var quantity = this.reorderQuantity();
    var id = this.productId();
    productsHub.server.reorderProduct(quantity, id);

viewModel.canBuy = ko.computed(function() {
    return this.unitsInStock() > 0;
}, viewModel);

viewModel.canReorder = ko.computed(function() {
    return this.unitsInStock() <= this.reorderLevel();
}, viewModel);

I also added a reorderLevel property to the ViewModel, and then added a textbox and button for reordering, and wired up its visibility to the canReorder computed observable. The reordering button and textbox will only be visible if the units in stock reaches the reorder level value. The Buy One button is now only enabled if there are units in stock. Previously, when there were no units in stock, the result of clicking the Buy One was an alert indicating that no stock existed:

<div class="row" data-bind="visible: canReorder">
    <span class="label"><input data-bind="value: reorderQuantity" class="reorder" /></span>
    <span><button data-bind="click: reorder">Reorder</button></span>
<div class="row">
    <span class="label">&nbsp;</span>
    <span><button data-bind="click: buy, enable: canBuy">Buy One</button></span>

If you have been following along so far, you can see that the two ViewModel functions: buy and reorder point to server-side Hub methods that don't currently exist: BuyProduct (indicated by productsHub.server.buyProduct) and ReorderProduct (indicated by productsHub.server.reorderProduct). So here is the code for the ProductHub with its methods:

using Microsoft.AspNet.SignalR.Hubs;
using WebMatrix.Data;

public class ProductHub : Hub
    public void BuyProduct(int productId) {
        using (var db = Database.Open("Northwind")) {
            var unitsInStock = db.QueryValue("SELECT UnitsInStock FROM Products WHERE ProductId = @0", productId);
            if (unitsInStock > 0) {
                db.Execute("UPDATE Products Set UnitsInStock = UnitsInStock - 1 WHERE ProductId = @0", productId);
                unitsInStock -= 1;
            Clients.All.updateAvailableStock(unitsInStock, productId);

    public void ReorderProduct(int quantity, int productId){
        using (var db = Database.Open("Northwind")) {
            db.Execute("UPDATE Products Set UnitsInStock = UnitsInStock + @0 WHERE ProductId = @1", quantity, productId);
            var unitsInStock = db.QueryValue("SELECT UnitsInStock FROM Products WHERE ProductId = @0", productId);
            Clients.All.updateAvailableStock(unitsInStock, productId);

This time, the changes caused by user action will be stored in the database, which didn't happen in the previous Chat example. The BuyProduct method retrieves the current number of units in stock for the selected product, and permits a purchase if there are are any. The revised number of units in stock, along with the product ID are sent to the all currently connected clients via an updateAvailableStock method. The ReorderProduct method simply increases the UnitsInStock value by whatever quantity was passed in to the method by the ViewModel function. Again, the revised number of units in stock is broadcast to all connected clients.

So how does the client handle this broadcast? It needs an updateAvailableStock function so that the hub methods can call it:

productHub.client.updateAvailableStock = function(unitsInStock, productId) {
    if (viewModel.productId() == productId) {
        $('span[data-bind="text: unitsInStock"]').effect('highlight', { color: '#9ec6e2' }, 3500);

First is checks to see if the ID of the product being updated is the one currently bound to the ViewModel, and if it is, the value is updated and a highlight effect is applied to the span that displays the units in stock:


All that remains to do is to create a client-side proxy for the ProductHub and establish a connection:

productsHub = $.connection.productHub;


Both of these examples are available as part of a sample site available at GitHub.

SignalR is a lot more powerful than these introductory demonstrations illustrate. You can write your own PipelineModule class and inject your own processing code into the hub pipeline. You can add authorization really easily to a hub method or a complete hub using data annotiation style attributes. You can read more about the latest SignalR release here.


You might also like...

Date Posted:
Last Updated:
Posted by:
Total Views to date: 51777


- Saeed Saedvand

Thanks Mike for your nice article. I really enjoy studying and using them. Thanks again

- Alex

Hi Mike,

Excited to learn! Although it is quite hard to follow along for a newbie and find the right place for a piece of code.
Also a screenshot of final site structure can be helpful for the newbies. Anyway - a few hours of troubleshooting and I got through the first part ;) Keep up!

- boboty

signalR doesn't work for me. i tried folowing instructions but it didn't work it only created a textbox with a button that does nothing.

- goel

hi , Mike
you can make tutorial facebook-wall-posts-comments-knockout-aspnet
I try convert it to webpage but cannot.
link mvc:

Recent Comments

Borut 17/02/2018 12:59
In response to I'm Not Writing A Book On Razor Pages
Mike, is it possible that Web Pages and Razor Pages "live" together in one web application? I a I...

hrboyce 09/02/2018 04:44
In response to I'm Not Writing A Book On Razor Pages
Mike, First thanks for doing this but I have to ask, any chance you would consider converting one of...

aziz sallam 07/02/2018 10:18
In response to I'm Not Writing A Book On Razor Pages
u are a great man...

Satyabrata Mohapatra 31/01/2018 11:36
In response to I'm Not Writing A Book On Razor Pages
This is a great news!!!! Thanks...

tangdf 30/01/2018 07:25
In response to I'm Not Writing A Book On Razor Pages
=> { o.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute()); }); The extension method does...

Obinna Okafor 30/01/2018 04:02
In response to I'm Not Writing A Book On Razor Pages
Thank you very much. I would like to see a project built from scratch using Razor Pages. And it show...

rachida Dukes 31/10/2017 13:52
In response to Customising Identity in Razor Pages
Thanks again for this wonderful tutorial. I followed all the steps in this section called: Adding...

Rachida 31/10/2017 12:06
In response to Customising Identity in Razor Pages
Thanks very much for this wonderful tutorial, it helped a lot....

Satyabrata Mohapatra 13/10/2017 10:17
In response to Customising Identity in Razor Pages
Thanks for sharing. Learned a lot!!...

Cyrus 23/09/2017 11:44
In response to Routing in Razor Pages
I want to have dynamic sitemap in my razor page app so I've created a page named "SiteMap" and route...