Adventures in learning SignalR

Signal-R Code

As our web application matures and we add long running processes we’ve run into page timeouts; but, more annoying is not knowing what is going on other than an animated gif.  In the Window’s world we can show progress bars and status’ during long running processes with relative ease.  Not so much in the web world.  That is where SignalR comes to the rescue.

SignalR is  a “new library for ASP.NET developers that makes developing real-time web functionality easy.  SignalR allows bi-directional communication between server and client. Servers can now push content to connected clients instantly as it becomes available.  SignalR supports Web Sockets, and falls back to other compatible techniques for older browsers. SignalR includes APIs for connection management (for instance, connect and disconnect events), grouping connections, and authorization.” Source

The first thing I did was look for samples.  There were many chat program samples that illustrated how you can broadcast to all clients; but, I was looking for a progress bar.  I found one on MSDN: “Build a Progress Bar with SignalR” by Dino Esposito in the March 2012 issue.  Note: You’ll need an MSDN subscription to view the article.  This sample uses version 1.0.0.0 of SignalR.

 I downloaded the sample code from the article and it ran as advertised.  Feeling good.  My next step was to write my own sample using the MSDN sample code as my guide.  Fired up Visual Studio 2013, created a new project which targeted the .Net Framework 4.5.1 and creating a new web application.

 

First Learning Experience: Framework Matters

Using NuGet I fetched the latest release of SignalR (2.2.0 as of 3/27/15) successfully.  Then I realized, wait… we target .Net Framework 4 in our web applications not 4.5.1 and then went to change the project’s targeted framework and received this error:

Some NuGet packages were installed using a target framework different from the current target framework and may need to be reinstalled. Visit http://docs.nuget.org/docs/workflows/reinstalling-packages for more information.  Packages affected: Microsoft.AspNet.SignalR.Core, Microsoft.AspNet.SignalR.SystemWeb, Microsoft.Owin, Microsoft.Owin.Host.SystemWeb, Microsoft.Owin.Security, Newtonsoft.Json

After reading the supported platforms: “SignalR 2 is only supported on .NET Framework 4.5”.  Back to the internet we go.

From this source I learned that Version 1.2.2 is the last supported version for .Net 4 Framework and using the NuGet package manager console I can get NuGet to install the version that worked with .Net 4 with these commands:

Install-Package Microsoft.AspNet.SignalR.Client -Version 1.2.2

Install-Package Microsoft.AspNet.SignalR -Version 1.2.2


 

Now I am back at my sample and start writing the code.  As I start writing my Hub class Visual Studio begins to complain on:

 Clients.Caller.displayMessage(“Stage 2 of 4”)

Option Strict On disallows late binding.

 

Second Learning Experience: RTFM

What?  I looked everywhere in the sample project and there is no method in the code behind and I usually don’t turn off the Strict Option; but, I was still a little hazy on how and where .displayMessage  was going to be called on the server side / client side.  I set Option Strict Off and move on.  For the next few hours I go in circles trying to get my sample to work.

I struggled a little because much of the books and recent documentation is on 2.0; but, there is documentation for 1.x  and a tutorial: Getting started with SingalR 1.x.  Reading through these and knowing a little bit about what some of the references are and knowing that <script src=”/signalr/hubs” type=”text/javascript”></script> is dynamically created and some of the magic is in this hubs file helped clear up some of the haziness.  More about this script reference later.  Here are some other tidbits that helped the light bulb turn on in my head:

Client Side

Server Side

var ltHub = $.connection.longTaskHub;

Imports Microsoft.AspNet.SignalR

Imports Microsoft.AspNet.SignalR.Hubs

 

Public Class LongTaskHub

    Inherits Hub

On the client the proxy name is a camel-cased version of the Hub class name. SignalR automatically makes this change so that JavaScript code can conform to JavaScript conventions.

ltHub.displayMessage = function (message) {

                $(“#msg”).html(message);

            };

Clients.Caller.displayMessage(“Stage 1 of 4”)

The above syntax did not work originally; but, that is how the MSDN sample code had it.  I added the .Client  to ltHub.client.displayMessage to get past the error.

 

 

I run my sample application again this time I get a JavaScript Error:

0x800a138f – JavaScript runtime error: Unable to set property ‘displayMessage’ of undefined or null reference

RTFM: Setup Project (Step 8) … Add the following line of code in the Application_Start method of the Global class to register the default route for SignalR hubs.

        Sub Application_Start(sender As Object, e As EventArgs)
RouteTable.Routes.MapHubs()
End Sub

 I put the required entry into Global.asax and run my sample again…. SAME ERROR!?!?!

RTFM: Run the Sample (Step 5) … In Solution Explorer, inspect the Script Documents node for the running application. There is a script file named hubs that the SignalR library dynamically generates at runtime. This file manages the communication between jQuery script and server-side code.

 Guess what… I didn’t see any hubs file created?!?!  On GitHub there is a SignalR FAQ and it just so happens I put my sample .aspx page inside a subfolder so I can keep all my different samples in one project.

RTFM: Why does signalr/hubs return 404 or Why do I get ‘myhub’ is undefined?
If you’re writing a regular ASP.NET application use

<span style="font-size: 10.0pt;">ResolveClientUrl</span>

for your script references:

<script type=”text/javascript” src=’<%= ResolveClientUrl(“~/signalr/hubs”) %>‘></script>

 I had updated all my other script references except: <script src=”/signalr/hubs” type=”text/javascript”></script>


Eureka… I have a running app!

 Ready to click the button… ready to see a progress bar do some progressing… drum roll … click … and nothing!  Using Fiddler I see something is happening after clicking the button a few times:

Reviewing the Getting Started with SingalR 1.x article again, in the chat sample the syntax was a little different than the MSDN sample (which was referencing version 1.0.0.0 of SignalR, did not have the .client in the sample code):

 In the MSDN sample:

     var bookingHub = $.connection.bookingHub;

            bookingHub.displayMessage = function (message) { <snip>

In the Getting Started article:

            // Declare a proxy to reference the hub.

            var chat = $.connection.chatHub;

            // Create a function that the hub can call to broadcast messages.

            chat.client.broadcastMessage = function (name, message) { <snip>

 

Take 2: Running the Sample

I am ready to take another stab at running the sample.  Page loads, click the button …. Drum roll…

0x800a139e – JavaScript runtime error: SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.

 The error is occurring in the jquery.SignalR-1.2.2.js file:

if (connection.state === signalR.connectionState.connecting) {

                // Connection hasn’t been started yet

                throw new Error(“SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.”);

            }

Kudos on the descriptive error message!  Turns out I was a little trigger happy and SignalR wasn’t quite ready for me to click the button. I added some extra code to prevent such an error:

     //disable button until SignalR is ready

            $(“#btnRun”).prop(‘disabled’, true)

            $(“#msg”).html(‘<b>Connecting to SignalR Hub.</b>’);

 

<snip>

    

     $.connection.hub.start().done(function () {

                //enable the button now that we are connected to the hub

                $(“#btnRun”).prop(‘disabled’, false)

                $(“#msg”).html(‘Connected.’);

            });

 

At the end of the day

I got my sample working, check it out:

1. Connecting (button disabled)

2. Connected (button enabled):

3. Run

4. Running (showing the counter)

5. Running (showing a static message)

 

Resources

There are a lot of resources on SignalR and here is a list of the ones I found useful and/or used in my sample (in no particular order):

 

Finally

Thanks to Microsoft’s Damien Edwards and David Fowler for building this tool that started out as a side project that now saves developers so much time because SignalR abstracts the best available method to execute the client server communication.

Now that I have my sample, time to integrate it into our existing product.  Onto the next adventure

 

See Also

Leave a thought