Talking to SignalR Hubs from .NET Clients (and fixing version incompatibilities)

In an earlier post I showed how to set up a SignalR hub that would accept requests and send out messages to browser-based, JavaScript clients.  What’s special about SignalR is that those messages are immediately picked up by the browser-based clients like the one I created in the following post (at least, the messages are received immediately with more modern browsers–with older browsers, SignalR falls back on having the browser regularly check for updated information).

However, so far I’ve assumed that the information to go to the server was generated in JavaScript from one of  those browser-based clients. I suspect that, in most cases, the information that clients are interested in–updates and changes to data–is generated at the server, rather than at the client. For instance, it will be updates to server-side data made by one of the other clients that will be of interest to all the rest of the clients (e.g. “Last ticket sold!”, “Customer X has been updated!”). Those updates will be made by server-side code either in a page being posted back to the server or in a server-side Web Service called from client-side JavaScript code. It’s also possible that the client making these updates may not be one of the clients receiving messages from the hub…or may not even be part of the application at all: it may be some external application  making the update (or be an application that monitors the data for updates in order to notify the hub of changes). In these scenarios, it will be .NET, not JavaScript, code that will need to send the information to the hub to be distributed to the clients accepting messages from the hub.

And that’s what this post is all about: integrating non-.NET clients into a SignalR hub. And, along the way, I’ll discuss how to handle having incompatible versions of SignalR on the server and the client (hey: as I said in my first post, this is pre-release software–these kind of problems are going to happen).

Talking to the Hub From Inside the Application

If the data that clients are interested in is being generated by server-side code inside the application with the hub, your server-side code can just piggyback on the hub. The first step in that process is to retrieve a reference to the hub using the GetHubContext method  through the ConnectionManager property of SignalR’s GlobalHost class (the property is static/shared so you don’t need to instantiate the class). You need to specify the type of the hub class that will be returned from the method. My hub was a class called MessageHub, so server-side code in that application to work with that hub would look like this:

Dim hub As IHubContext
hub = GlobalHost.ConnectionManager.GetHubContext(Of MessageHub)()

Now that you have a reference to the hub, you can all the methods set up on the client as you did from inside the hub’s methods. This code, for instance, sends a message to any client that’s implemented AcceptMessage:

hub.Clients.All.AcceptMessage("from server")

One warning: If you’ve try testing this with the WebForm you’ve been using as your client for accepting messages from your hub, don’t be surprised if your message doesn’t get back to the client. During the time your page is posting back to the server and executing this code, the page isn’t present in the browser to receive the message. You’ll need two clients to test this effectively (in IE just right-click on your page’s tab and select Duplicate Tab to create a second client to receive messages while the first client is posting back to the server).

Talking to the Hub From Other Applications

You can also send messages to your hub from .NET applications. The first step is to use NuGet to add the client-side libraries (Microsoft.AspNet.SignalR.Client) to your application. This can cause problems when you go to test your application: You may get the message “Incompatible protocol version” (or the proposed upgraded version of this message: “You are using a version of the client that isn’t compatible with the server. Client version a, server version b.”). The problem is that the version of the client library that you’re using isn’t compatible with the version of the library that your server is using–see the section at the end of this post for how to resolve this.

The first step in the code to have a non-JavaScript client connect to a hub is to instantiate a HubConnection object, passing the URL for the Website with your hub. This code, which I used in a WPF application, does that:

Imports Microsoft.AspNet.SignalR.Client.Hubs

Class MainWindow
  Private conn As HubConnection
  Private hub As IHubProxy

  Private Async Sub InitializeHub()
    conn = New HubConnection("http://localhost:49206/")

Once you’ve created the HubConnection, you create a HubProxy (or, to be more specific, a class that implements the IHubProxy interface) using the HubConnection object’s CreateHubProxy method and passing the name of the hub that you want to talk to as a string. This code connects to the class I called MessageHub that I created back in my first post:

hub = conn.CreateHubProxy("MessageHub")

As in the JavaScipt code, you must now start the connection by calling the Start method. The Start method is asynchronous and, in this code, I’ve chosen to wait until that method completes (which is why I’ve put this code in a separate method: I could add the Async keyword to the method to allow me to use the Await keyword):

  Await conn.Start
End Sub

Once the connection is open, you can send messages by using the HubProxy object’s Invoke method–just pass the name of your method on the server (in my case, “ReceiveMessage”) followed by whatever parameters the the method requires (in my case that’s a single string).  The Invoke method is asynchronous but, here, I’m not going to wait for it to finish:

hub.Invoke("ReceiveMessage", "Hello, World form a .NET Client!")

Since I’m using a WPF application rather than a Web browser I have some control over what happens when the user closes the application. The decent thing for me to do, as part of unloading my application, is to tell the hub that I’m done by calling the HubConnection object’s Stop method:

Private Sub MainWindow_Closing(sender As Object, e As ComponentModel.CancelEventArgs) Handles Me.Closing
End Sub

For completeness sake: Your non-JavaScript clients can also receive messages from the server. When I set up my hub, I had it send messages through an AcceptMessage function on the client. In non-JavaScript clients, I can get the messages sent using AcceptMessage by using the HubProxy’s On method. I just need to specify the type of data I’ll be receiving (string, in my case), the name of the function that the hub is using (AcceptMessage), and provide a lambda expression that will be passed the message when the hub sends it. This code displays a message when the hub sends one out:

hub.On(Of String)("acceptMessage", Function(m) MessageBox.Show(m))

With these additions, you can now send information to your MessageHub that it can distribute to clients. In my next post, I’ll start a case study that will pull all of this proof-of-technology stuff together into something resembling a useful application.

This following section discusses handling those “incompatible protocol/versioning” problems I mentioned earlier and you can safely ignore it until you have the problem.

Dealing with Version Compatibilities

The protocol versioning problem I mentioned earlier can happen if the NuGet versions of your client- and server-side libraries aren’t coordinated at Microsoft’s end (it could happen!) or, more likely, if the libraries have been updated since you created your server and NuGet is delivering a newer version of the libraries to your client project. You have two solutions to the problem: update your server software to the latest version (i.e. use the NuGet manager to remove the current version of SignalR from your server and then use NuGet to add the latest version back in) or download an earlier version of the client software to your client to get a version compatible with your older server version.

If updating the server doesn’t work (or you’d prefer to not to “fix” your working server) rolling back your client to an earlier version isn’t hard. First, use the NuGet manager to remove your client’s existing package. Then go to the list of all the versions of the client software and click on the version you want. That will take you to that version’s download page. The PackageManager command you need to install this version is listed at the top of the page (something like Install-Package Microsoft.AspNet.SignalR.Client -Version 1.0.0-rc2 -Pre). Copy it. Now, to use the command, from the Tools menu, select Library Package Manager | Package Manager Console to display the console, which will (probably) appear in a window at the bottom of Visual Studio. Paste in the command, hit the <Enter> key, and you’ve rolled your client back to the earlier version.

Peter Vogel

PS – To further your .NET education, we have introduced the following new 1-day intensive online courses – Quick Start to Developing Applications with the .NET Framework, Kick-starting C# Object-Oriented Programming & Getting Started with ASP.NET MVC.

Type to search

Do you mean "" ?

Sorry, no results were found for your query.

Please check your spelling and try your search again.