Introduction
Yesterday I wrote a blog about SignalR and just 5 seconds after posting it I got this on twitter.
So, here I am on a Sunday morning writing about SignalR and Hubs.
Why hubs? You ask.
Hubs provide a higher level RPC framework over a PersistentConnection. If you have different types of messages that you want to send between server and client then hubs is recommended so you don’t have to do your own dispatching.
It took me a while to figure this out, but I got there in the end.
The server
Setting up the server should have been easy. But it lacked something.
So watch out if you are working with VB.Net.
First I started to create my hub.
Imports Microsoft.AspNet.SignalR.Hubs
Public Class Plants
Inherits Hub
Dim _plants As IList(Of Plant)
Public Sub New()
_plants = New List(Of Plant)
_plants.Add(New Plant With {.Id = 1, .Genus = "Fagus", .Species = "Sylvatica", .CommonNames = {"Common Beech"}})
End Sub
Public Function GetPlant(id As Integer) As Plant
Return _plants.Where(Function(x) x.Id = id).FirstOrDefault
End Function
End Class
This hub should return a plant for the id given or nothing when the id is not found.
If you start this you should get the url to your server.
if you browse to that url and add /signalr/hubs to it you should get something like this.
/*!
ASP.NET SignalR JavaScript Library v1.0.0
*
Copyright Microsoft Open Technologies, Inc. All rights reserved.
Licensed under the Apache 2.0
*
*/
///
///
(function ($, window) {
///
“u
But I did not get that. I got a 404 not found page instead. Which isn’t good.
And it was caused by the routes not being registered. Which normally happens via this cs file that is in your App_Start folder (which was created by the nuget package).
.Web.Routing; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hosting.AspNet; [assembly: PreApplicationStartMethod(typeof(SignalRTesting.RegisterHubs), "Start")] namespace SignalRTesting { public static class RegisterHubs { public static void Start() { // Register the default hubs route: ~/signalr/hubs RouteTable.Routes.MapHubs(); } } }
And normally you don’t need to setup any roots in your Global.asax.
But when I did. It worked.
So add a Global.asax and change it to this.
Imports System.Web.SessionState
Imports System.Web.Routing
Imports Microsoft.AspNet.SignalR
Public Class Global_asax
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
RouteTable.Routes.MapHubs()
End Sub
End Class```
And now your server should return the correct page on browsing to /signalr/hubs
## The client
First thing to try is to make a console client.
Look at the code of our server and see that we return an object of type Plant.
Our Plant object looks like this BTW.
```vbnet
Public Class Plant
Public Property Id As Integer
Public Property Genus As String
Public Property Species As String
Public Property CommonNames As String()
End Class```
The return means that only the caller will get that returnvalue, not any of the other clients.
And here is such a client.
```vbnet
Imports Microsoft.AspNet.SignalR.Client.Hubs
Imports Microsoft.AspNet.SignalR.Client
Module Module1
Sub Main()
Dim connection = New HubConnection("http://localhost:50865")
Dim plants = connection.CreateHubProxy("Plants")
connection.Start().Wait()
Dim line As String = Nothing
Console.WriteLine("type the id + enter to send, type exit + enter to exit.")
While line <> "exit"
line = Console.ReadLine()
plants.Invoke(Of Object)("GetPlant", line).ContinueWith(Sub(data)
If data.Result IsNot Nothing Then
Console.WriteLine(data.Result.ToString)
Else
Console.WriteLine("No plant with that id.")
End If
End Sub)
End While
End Sub
End Module
And if you type 1 you should get this in return.
But we could have just use ServiceStack if we needed something like that.
So what is the point?
Let’s just say that we want to inform all our clients that someone just requested a plant with id 1 than we could do this instead.
Change the server code and start it up.
Imports Microsoft.AspNet.SignalR.Hubs
Public Class Plants
Inherits Hub
Dim _plants As IList(Of Plant)
Public Sub New()
_plants = New List(Of Plant)
_plants.Add(New Plant With {.Id = 1, .Genus = "Fagus", .Species = "Sylvatica", .CommonNames = {"Common Beech"}})
End Sub
Public Function GetPlant(id As Integer) As Plant
Clients.All.addMessage("Someone requested id: " & id)
Return _plants.Where(Function(x) x.Id = id).FirstOrDefault
End Function
End Class
As you can see I use Clients.All.addMessage to send a message to all Clients with the id that was requested.
Change the console client to this.
Imports Microsoft.AspNet.SignalR.Client.Hubs
Module Module1
Sub Main()
Dim connection = New HubConnection("http://localhost:50865")
Dim plants = connection.CreateHubProxy("Plants")
plants.On(Of String)("addMessage", Sub(data) Console.WriteLine(data.ToString()))
connection.Start().Wait()
Dim line As String = Nothing
Console.WriteLine("type the id + enter to send, type exit + enter to exit.")
While line <> "exit"
line = Console.ReadLine()
plants.Invoke(Of Object)("GetPlant", line).ContinueWith(Sub(data)
If data.Result IsNot Nothing Then
Console.WriteLine(data.Result.ToString)
Else
Console.WriteLine("No plant with that id.")
End If
End Sub)
End While
End Sub
End Module
I just added the plants.On method to intercept the addMessage events.
And now when I open multiple clients I get this.
Which is cool.
Conclusion
Hubs are what you will mostly use when you use SignalR.