My cheat sheet for using SignalR

Good gravy, I spent several HOURS going through the samples and watching videos to get my own sample app working. Sure, the pre-built ones worked – but trying to reverse-engineer WHY they worked was a chore.

If you are not familiar, SignalR is a Microsoft technology which uses several browser technologies to allow the server to update the client in real-time. This is a mechanism that lets a web server push down updates to a web browser.

OK, for the impatient like me, here are the nuts and bolts of what you actually need:

STEP 1: Install SignalR from NuGet
Right-click on your project and choose “Manage NuGet Packages”. On my machine, I have these installed:

mx3BC76

Which ones do you “need”? Who knows. There is so much conflicting documentation, it’s anyone’s guess. But while having these installed, my app works.

STEP 2: Create a hub
Ideally in a class library – or you can create a sub-folder (called SignalR?) for your code – you’ll at least need a “hub”. This is the mechanism which lets you send data back-and-forth to the client.

For my sample app, I am sending back some basic statistics. Here is all of the code for the hub and the data structure which holds the current status:

[HubName("statusHub")]
public class StatusHub : Hub
{
    private static StatusDetail currentStatus = new StatusDetail();
    private static Random random = new Random();
    private static Timer timer = new Timer(400);
    public StatusHub() : base()
    {
        currentStatus.StartTime = DateTime.Now;

        // Generates random data to send to the client
        timer.Elapsed += (sender, e) =>
        {
            OnStatusChanged();
        };
        timer.Enabled = true;
        timer.Start();
    }

    [HubMethodName("onStatusChanged")]
    public void OnStatusChanged()
    {
        currentStatus.BytesProcessed += random.Next(121, 23767);
        currentStatus.RequestsProcessed += random.Next(0, 11);

        // Fire the event on all of the clients
        Clients.All.onStatusChanged(currentStatus);
    }
}

public class StatusDetail
{
    public DateTime StartTime { get; set; }
    public Int32 RequestsProcessed { get; set; }
    public Int64 BytesProcessed { get; set; }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Perhaps the most noteworthy thing here is that “Clients.All.onStatusChanged” – this is going to fire a JavaScript event called “onStatusChanged”, to which we need to wire up an event handler.

STEP 3: Map the SignalR URL
One of the things SignalR does for you is dynamically generate a JavaScript proxy file which you can use from your client-side code. In order to set up that virtual mapping, you must add some code. Again, you will find several, conflicting ways to do this in the documentation. The current way, as of this writing, is to set up a method which maps the SignalR URL. Per the sample code:

public static class Startup
{
    public static void ConfigureSignalR(IAppBuilder app)
    {
        // For more information on how to configure your application using OWIN startup, visit http://go.microsoft.com/fwlink/?LinkID=316888
        app.MapSignalR();
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

So – the above is all we need on the server-side.

STEP 4: Add JavaScript references
On the client side, in the HTML file, this is what I have for JavaScript references:

<script src="/scripts/jquery-1.10.2.js"></script>
http://span
"/signalr/hubs">script>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The order of these is important, and you should also note that we add a script reference to /signalr/hubs. This is that virtual URL which that .MapSignalR() method set up. You should be able to navigate to this “file” in the browser and see JavaScript. In fact, you should be able to scroll down and see the definition for your hub(s) too.

STEP 5: Wire up events and start connection
One thing I found was that I would get a $.connection is undefined. That ended up being an issue of where my scripts were on the page. So, I wrap all of this in a @section scripts { } block to resolve it.

So, assuming that I have HTML like this which I’d like to update:

table>
    tr>
        th>Up Since:th>
        td id="startTime">01-Jan-2000 00:00:00amtd>
    tr>
    tr>
        th>Requests:th>
        td id="requestsProcessed">1,231td>
    tr>
    tr>
        th>Bytes:th>
        td id="bytesProcessed">1.46MB (1,532,459 bytes)td>
    tr>
table>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

My complete JavaScript to open the SignalR connection, wire up the event handler, and to update the UI, looks like this:

@section scripts{
script src="/scripts/jquery-1.10.2.js">script>
http://span
http://span

    <script>
        $().ready(function () {

            var $statusHub = $.connection.statusHub;

            $statusHub.client.onStatusChanged = onStatusChanged;

            $.connection.hub.start();

        });

        function onStatusChanged(currentStatus) {
            $("#startTime").text(currentStatus.StartTime);
            $("#requestsProcessed").text(currentStatus.RequestsProcessed);
            $("#bytesProcessed").text(currentStatus.BytesProcessed);
        }
    </script>
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Dear Future-Robert, hopefully this saves you from wasting hours in the future piecing all of this together, again! Love, Past-Robert

Posted in ASP.NET, ASP.NET MVC, Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
Categories

Enter your email address to follow this blog and receive notifications of new posts by email.

Join 5 other followers

%d bloggers like this: