SignalR is the latest in a long string of new technologies pouring out from the ASP.NET team recently, when Microsoft rolled out version 1.0 of SignalR when Visual Studio Update 2 was announced. In a nutshell, SignalR is technology for .NET that allows you to build real time, connected Web applications. Connected in the sense that you can build Web applications that can send and receive and broadcast data in real time. The canonical example of a 'connected' application is a chat application where a client can broadcast messages to all other connected clients. While that's pretty cool in and of itself, that only begins to scratch the surface of what's possible with SignalR as you can communicate in a wide variety of ways between client and server and between all clients to push data around.
Go ahead - Push Me Around!
The idea behind SignalR and other tools like it (like the socket.io or now.js JavaScript libraries) is that you can push data from client to server, from server to client and even from client to client, all in real time without having to poll or check for new data at specified intervals. Callback driven interfaces on both client and server receive pushed messages immediately. The key word here is push -servers and clients can push data at any time and the other end of the connection sees the updated data immediately. It's pretty cool to watch an application, where one browser client updates a value in a text field and all other instances that are connected see that same change at the same time. Or having a server push a notification message down, and having all browsers immediately update to see the new data.
This sort of thing used to be the domain of connected TCP/IP services and peer to peer servers, but SignalR makes all of this available using standard Web protocols, using the HTTP protocol and port 80 or any other HTTP port and with .NET services on the server side. Behind the scenes SignalR combines the use of various connection protocols from WebSockets, to Long Polling to plain AJAX callbacks when all else fails, to bridge the compatibility gap between what modern browsers support and what you can do with legacy browsers. If you want to see all of these techniques highlighted along with a older preview of SignalR, there's a great conference session by Steve Sanderson on Channel 9 that discusses the various Async messaging approaches.
The key feature here is that SignalR's server maintains a persistent connection - abstracted over WebSockets/LongPolling/Ajax depending on what's available on the browser - to the client. So while with AJAX we could always push data to the server, but the server could never push data to the client, with SignalR you can push data both from client to server and from server to client. In order to broadcast messages from one client to all other clients you can callback to the server which can then broadcast a message to all or selected connected clients.
SignalR Server and Client Components
SignalR abstracts these various protocols and allows a seamless experience regardless of what the client supports. Additionally SignalR provides a very easy to use .NET server side framework for creating the backend services that either push data directly or broadcast data in bulk to many clients. SignalR includes the concept of Hubs which use simple methods in a .NET class as endpoints, as well as a lower level Connection interface that allows for streaming and low level access for the data that is both sent and received. SignalR then also provides rich client libraries for JavaScript, full .NET, Win8, Silverlight and a host of other clients to easily connect to either Hubs or Connections on the server, using an easy to use dynamic mapping model that is very flexible and easy to use. It's surprisingly easy to create SignalR services and consume them, both in Web and non-Web applications.
One of the cool things about SignalR is that you can also easily self host a SignalR server. A typical SignalR server application hosts in ASP.NET and is totally transparent and easy to run as part of the ASP.NET stack. However, you can also host SignalR in a self-hosted application, using an OWIN server host that can bootstrap SignalR and make it available in Console applications, Services or even full blown desktop applications. I recently built a monitoring service application that is running as a Windows Service and was able to use SignalR to efficiently push notification messages to a Web Browser based front end interface, pushing over 50 messages a second to several connected clients in real time. The possibilities this opens up really can't be overstated.
Signal What? A small real World Use Case
When I first heard about SignalR about a year and a half ago, the first thing that came to my mind was: "Yeah that's nice, but it's not a common scenario to have truly connected Web applications." The first thing that springs to mind are chat applications, messaging popups or continuous tickers of updating data pushed down to clients. That demo's nicely and is impressive to see, but it's not exactly a very common use case.
However, recently I had a chance to put SignalR to use in a real application with a scenario that's a little bit different. Specifically we needed a way to connect a standalone Windows Service application to a Web browser clients to provide real time updates. This project involved a queue service application running as a Windows Service with a Web front end that can monitor and manipulate the queue's operation using any browser.
The specific UI use case was to replace an old and ugly Windows Forms user interface that had to run on the physical server to monitor the real time queue activity and manipulate the queue application settings. With SignalR we were able to move this app to a real time, Web browser based interface.
There are a several important pieces that SignalR provided and made possible for this project:
- The ability to have a Windows Service push real time messages to a Web browser
- The ability for many Web browser clients to be connected
- The ability for many users to modify settings on the Web browser user interface and reflect those changes immediately for other browser users
While the application created for this is not very complex it did highlight these various different scenarios of sending messages that you can use with SignalR:
- Sending messages from the server to all clients (message list display)
- Sending two-way messages from one client to the server (updates - like AJAX calls but using SignalR)
- Sending messages from the server a specific caller (individual status updates)
- Sending messages from a single browser instance to all browsers (Updating the global queue settings or stopping the service)
The interface for this application is basically a list type view of real-time active queue requests as they occur, some status information of the pending items in the queue and the current connection status to the server, as well as a small set of input controls that manage the queue operational status - the number of threads running the wait time and the ability to start and stop the queue.
Here's what the UI for this interface looks like:
As requests hit the queue they show up in this monitor and the main form's list. The queue service calls SignalR when it starts processing a queue request and again when a queue request either completes successfully or fails. The list status bar then displays the number of pending messages that are waiting in the queue. The textboxes above let the administrators of this application who have access to the the service manage the queue by tweaking a few settings or by stopping the service altogether. When the update or start/stop button is clicked, a SignalR request is fired to save and or change the service status and then fire a notification to all clients to update their status.
The web site client uses knockout.js for databinding a couple of fairly simple models - the list of visible list items and the queue's status - which are updated by the SignalR callback methods that receive message data from the server. When the model data is updated knockout bindings kick in and refresh the UI immediately resulting in a mostly codeless update process. The only explicit code to display server content are the status messages which are not bound but explicitly called via a showStatus message.
For what it does there's a surprisingly little amount of code involved and the logic involved to make this work is pretty simple.
Granted this isn't a very complex UI, but still it was pretty amazing for me to see hundreds of requests rolling through in a few seconds and updating 10 browser windows simultaneously - until you see this happen with your own application it's hard to appreciate how much satisfaction you get from that very concept working so efficiently! It brings me back to the very early days of the Web when it was exciting to see any dynamic content on a live Web page :-)
I can think of a bunch of use cases where this technology makes a lot of sense:
- Any sort of two-way messaging applications (chat, messaging)
- Real time data feeds or ticker displays
- Real time data monitors for logs, lists, users etc. (Admin interfaces)
- Long running async requests with real-time status updates
- A replacement for some Queue type operations with direct real-time connections
- Screen sharing applications with shared editing data by multiple users
- Interactive multi-player games with real time screen updates
- and, and, and…
Ease of Use
Another thing that impressed me about SignalR when I started working with it is that this has to be some of the easiest to use Microsoft technology to come along in a long time, while providing some really powerful features. SignalR is based on dynamic language features which do away with a lot of ceremony in defining of interfaces and mapping client to server. In many cases it's as easy as creating a class on the server and having the client reference the server side hub and method and just call it. End of story. The same is true for broadcasting of messages from the server to the client - there's no contract, no special interface, all you do is call a method that may or may not exist on the client - if you implement it on the client it will get called. End of story - again.
What was really surprising about this project was that going from zero knowledge of SignalR to a fully functional, initial implementation that hit all the initial usage points I mentioned above, took all of 2 work days to accomplish. This included learning about SignalR and experimentation with a few different approaches, dealing with knockout.js, plus building robust connection management code that can deal with disconnects and reconnects (which truthfully was the most complex and time-consuming piece and the only part that required a bit of research and some help on the SignalR Jabbr channel).
This solution uses a Windows Service Project on the server using SignalR's OWIN hosting, which trivial to set up. In fact it takes all of 10 lines of code to hoist up the server.
Low Ceremony
It's extremely easy and low ceremony to broadcast a SignalR message even in a self hosted environment. The following C# server side code calls a JavaScript callback on all clients that are listening (this method displays a queue list item):
// Write out message to SignalR clients
HubContext.Clients.All.writeMessage(id,
"Info",
DateTime.Now.ToString("HH:mm:ss"),
message, string.Empty);
where the writeMessage method call is translated to the client side JavaScript handler. On the client there's a callback handler registered on a writeMessage operation which is then fired on the client. The script code then proceeds to bind the values to a view model item using knockout.js and updates the display dynamically.
On the client I can simply register a method that handles a callback which effectively 'publishes' that method on the client:
hub.client.writeMessage = self.writeMessage;
And I can then implement the writeMessage callback method that handles this logic (or use an anonymous method):
writeMessage: function (message, status, time, id, elapsed, waiting) { … update collection item viewModel and let knockout.js bind
}
The server can now call the writeMessage function on the client using the C# code shown above. It's all dynamic.
Calls in the other direction - from client to server are equally simple. The client calls a server method like this (where self is my top level object container and hub is an instance of the SignalR hub stored on it):
self.hub.server.getServiceStatus()
.fail(page.statusMessage);
This calls a GetServiceStatus() method on the server's hub.
Once a hub has been created and stored you can simply call the server object which maps any methods you call straight to the .NET server methods implemented on the hub. Here's the server code:
public void GetServiceStatus()
{
var instance = Globals.Controller;
if (instance == null)
Clients.Caller.getServiceStatusCallback(null);
else
Clients.Caller.getServiceStatusCallback(
new QueueControllerStatus()
{
queueName = instance.QueueName,
waitInterval = instance.WaitInterval,
threadCount = instance.ThreadCount,
paused = instance.Paused
});
}
This server code receives the JavaScript client's request and then broadcasts a message back to all connected clients. Effectively this code has a single JavaScript client requesting that the server should broadcast a message to all clients. Here the code basically pushes down status information which is then picked up on the client and bound via knockout to the textboxes and the start/stop button.
The server code can use the Client.All, Clients.Caller, Clients.AllExcept collections to reference common groups or you can add users to specific Groups that you can then broadcast to. Lots of flexibility again in a really easy to use model.
Performance and Resources
Since this was my first time using SignalR I had no idea what to expect in regards to performance with using SignalR's messaging. I was actually surprised that I couldn't overload the UI operation by stuffing even 5000 messages into the queue. SignalR happily and rapidly kept up with the service in sending out messages and updating the list UI faster than you could even begin to keep reading it. 1000 queue requests (x2 for begin/end message) went through in less than 4 seconds! Also tried this with 10 clients connected simultaneously and performance didn't change noticably with the increased number of connected clients.
It's important to understand that this application will be used by a small number of administrative users, so it's not going to be used by thousands of users simultaneously. At most we figure there may be 10 people connected at a time. However, connections are something to consider with SignalR. As cool as this technology is, it's connected technology meaning that each client connected through SignalR is using a persistent and dedicated connection on the Web Server. 10 users or 100 are probably not much of a problem, but thousands of users may bump up against the Web server connection and Windows thread and resource limits eventually. SignalR also includes some scalability features, but these get very complex quickly and if this becomes an issue I personally think that one should reconsider whether SignalR or a real-time connection based interface is the right choice…
While the SignalR's docs claim that it's capable of thousands of simultaneously connected clients (given the connection pool is high enough), there is a finite limit to the amount of connections you can simultaneously run with IIS or self-hosting along with the CPU and memory overhead associated with each connection.
Caveat emptor - make sure you understand the implications of using SignalR in terms of connection, memory, cpu and bandwidth usage.
Documentation and Support
As I mentioned the basics and overall behavior of SignalR are pretty easy to grasp and put into practice and the online documentation does a pretty good job of getting you started and explain the general model of how the messaging flow and program implementation code works. There are nice and simple examples and it works great.
However, some of the more specific documentation is a bit sketchy and often limited or missing altogether. The hardest part of this small component we built was dealing with the connection and disconnection notifications required to determine whether the Windows Service is online and the SignalR server running and how to deal with scenarios where connections are dropped and then reconnecting as necessary. SignalR actually includes some very sophisticated logic to notify you of connect and disconnect events on the client, but there are quite a few overlapping different events that fire on the client and I for one got lost in which one actually needed to be handled to reliably re-connect. There were a handful of other issues at this same lower level that were difficult to resolve through the documentation or even searching.
I also found searching on SignalR content a bit frustrating because a lot of the hits I'd get for topics in blog posts or StackOverflow answers ended up being from preview versions with information that was no longer valid. Hopefully this stuff will work itself out in time.
In the meantime however, I hopped over to the SignalR Jabbr Channel and posted a few of my conundrums over there. There's lots of help offered on this channel from peers and from the authors of SignalR (or David Fowler mostly) frequently jumping in and answering questions. David helped me with two sticky issues and in a few minutes pointed me in the right direction. This type of interactive support is just awesome and it also shows the enthusiasm by some of the people involved with SignalR. I do wonder though how well this type of support will scale in the future. We'll see - in the meantime it's great to see this kind of direct interaction which hopefully helps the SignalR guys iron out some rough spots that come up more frequently.
SignalR - Hell Yeah!
As you can probably tell I'm pretty jazzed about what SignalR offers to .NET developers. Web based real-time communication technology like SignalR offers many opportunities to rethink of what we can actually build with Web applications today, offering many more opportunities to build interactive and collaborative applications. It provides a different way to access information in Web applications in a more direct, real time manner and it does this in a way that is relatively simple to accomplish. SignalR is amongst the cleanest and easiest to implement solutions I've seen coming from Microsoft in a very long time.
I'm especially excited about the ability to interface SignalR's server side code with self-hosted applications that gives us the ability to more easily connect back end services to browser front ends. For administrative applications or dashboards this is incredibly powerful stuff and it's easy to integrate into existing applications. I'll post more on this topic in the future.
But even in plain old Web applications the opportunities to provide real time data or to have users share information across multiple live browser instances is pretty cool. The abstraction provided by SignalR's client and server make it so easy to take advantage of this functionality in just about any application. There are so many opportunities here - from the obvious real time broadcast services to more subdued server callbacks that can replace traditional AJAX interfaces to providing real time access to changing data in Line of Business or even public facing applications. Then there is the use case for running long running async operations on the server and providing real-time feedback to the client page. And there's the whole opportunity with interactive games or productivity applications where multiple users can interact with the same shared information to provide a live and updating interface. Doing simple interactive games like Battleship etc. become almost trivial with this sort of technology and even more interactive graphics intensive games become a possibility with this toolset.
Lots of opportunities to dream up, so dream on…