BigImage

This article will briefly introduce you to SignalR, explain its advantages and get you started with a simple application.

What is SignalR?

ASP.NET SignalR adds real-time functionality to your ASP.NET applications by intelligently identifying the best underlying technique supported on the client as well as the server side on doing so. This means that by using SignalR you won’t have to learn the latest techniques on message passing real-time data as new technology come around. SignalR will simply add functionality for these new techniques meanwhile the API calls will remain the same.

On top of this, SignalR is also OpenSource and hosted on GitHub here: https://github.com/SignalR/SignalR.

Side note:

If you like the methodology of SignalR but aren’t into ASP.NET because you are more of a MEAN-stack developer or just enjoy working with Node.JS. Then you should definitely check out Socket.IO. A comparison between these libraries will be published later on.

The primary supported underlying techniques used by SignalR are the following:

HTML 5 transports

WebSocket

WebSocket is the newest and most optimal solution for sending real-time data as it supports all modern browsers and uses a full duplex solution for message passing.

Server Sent Events

A HTML 5 alternative to WebSocket. Unfortunately, Internet Explorer never adapted this technology.

Comet transports

Forever frame

Can only be used with Internet Explorer.

Ajax long polling

Ajax long polling was the natural choice before WebSocket came around. However, Ajax long polling doesn't provide near as good performance compared to WebSockets.

A more detailed view of these underlying techniques will be discussed in a later post.

Usage

While SignalR is broadly used on chat applications it has the functionality and performance for making a collaborative document writing sessions and even games http://shootr.signalr.net/.

Getting started

To get started with SignalR Microsoft has created a sample application which can be installed by following the instructions below. However, I think that this application is quite advanced to begin with and therefore I will create a simple chat application using SignalR. I would however, suggest you to install the sample application provided by Microsoft later on.

Microsoft SignalR sample

Microsoft has created a SignalR sample project that can be downloaded and installed through nuget. The project contains a fake stock market application which returns dummy data. You can download and play around with this project by creating a blank ASP.NET MVC application and then run the command:

Install-package Microsoft.AspNet.SignalR.Sample

Then follow the instructions in the 3-step process inside the readme to get the application started.

Simple chat application using bootstrap & AngularJs

The final application:

BigImage

Create a new application ASP.NET Web Application:

BigImage

Create a new empty project:

BigImage

Install SignalR using nuget:

Install-Package Microsoft.AspNet.SignalR

Create a Owin startup project and rename it to "Startup.cs":

BigImage

Open the "Startup.cs" file and insert the following which is also provided in the readme.txt:

app.MapSignalR();

This is done to enable SignalR in your application.

Then, create a new folder and name it "Hubs", then create a hub "ChatHub.cs" inside of the folder:

BigImage

Hubs are used for communicating in real-time between the server and the clients. And as described above, it is SignalR's job to provide the best underlying technology in doing so.

Here is the code for the hub:

//Class for handling all user connections
public static class UserConnections
{
//Hashset for keeping track on all unique connections
public static HashSet<string> ConnectionIds = new HashSet<string>();
}

[HubName("chatHub")]
public class ChatHub : Hub
{
//Method for broadcasting message to all connected clients
public void SendMessage(string name, string message)
{
//This will call the method on the client side containing the parameters name and message
Clients.All.broadcastMessage(name, message);
}

//Override onConnected event to keep track connected clients
public override Task OnConnected()
{
UserConnections.ConnectionIds.Add(Context.ConnectionId);
Clients.All.onClientConnected(UserConnections.ConnectionIds.Count);
return base.OnConnected();
}

//Override onDisconnected event to keep track connected clients
public override Task OnDisconnected(bool stopCalled)
{
UserConnections.ConnectionIds.Remove(Context.ConnectionId);
Clients.All.onClientDisconnected(UserConnections.ConnectionIds);
return base.OnDisconnected(stopCalled);
}
}

A few things to note:

Inside of the file, I have two classes: UserConnections and ChatHub.

UserConnections is a static class and will represent our database in this case since it is a small project.

ChatHub is our hub that will take care of all the communications between the server and clients. As you can see, this inherits from the class "Hub" to take advantage of the hub capabilities. Note that there is nothing stopping us from creating multiple hubs for one project, but seeing that this is a small project, one is good enough.

Inside of the hub I have created method called "SendMessage" which takes two parameters; name and message which represent the user who sent the message and the actual message.

What’s quite different from SignalR than most libraries are that dynamic calls are being used to call methods on the client side from the hub.

This means that "broadcastMessage" in the following line of code has to be setup on the client side:

Clients.All.broadcastMessage(name, message);

Which also means that you won’t get any intellisense on these method calls since they only exist on the client side.

Before the dynamic function call however, we specify which client should receive this message. In this case we will broadcast the message to all connected clients.

Inside of the hub we also want to keep track on the connected clients using our fake database represented as a static hash list.

This is done by overriding the OnConnected as well as the OnDisconnected method and by sending the count value to all connected clients when these events are triggered.

Moving on to the client side:

 

Install bootstrap using nuget:

Install-Package bootstrap

Create a new folder named "Views" and add a HTML-file named "Index.html":

BigImage

Provided that you have bootstrap.css in a folder named "Content" and signalR, jquery and boostrap.js in a folder named "Scripts":

Insert the following code to the file:

<!DOCTYPE html>
<html ng-app="signalrApp">
<head>
<title></title>
<meta charset="utf-8" />
<link href="../Content/bootstrap.css" rel="stylesheet" />
</head>
<body ng-controller="MainCtrl">
<div class="container">
<div class="row">
<div class="col-xs-12">
<span>Connections: {{clientCount}}</span>
</div>
</div>
<div class="row">
<div class="col-sm-2">
Name:
<input type="text" id="nameInput" ng-model="name" class="form-control" />
</div>
<div class="col-sm-8">
Message:
<input type="text" id="textInput" ng-model="text" class="form-control" />
</div>
<div class="col-sm-2">
<button style="margin-top:20px;" class="btn btn-sm" ng-click="sendMessage()">Send Message</button>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<br />
<div ng-repeat="message in messages">
<div class="col-sm-2"><b>{{message.name}}</b>:</div>
<div class="col-sm-10">{{message.text}}</div>
</div>
</div>
</div>
</div>
<footer>
<script src="../Scripts/jquery-1.9.1.min.js"></script>
<script src="../Scripts/jquery.signalR-2.2.1.min.js"></script>
<script src="/signalr/hubs"></script> <!--Will be generated by SignalR-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.js"></script>
<script src="../Scripts/bootstrap.min.js"></script>
<script src="../Scripts/script.js"></script>
</footer>
</body>
</html>

What you should note here is the reference to the auto-generated hubs directory at the bottom. This is where SignalR will tell the client how to communicate with the hubs setup on the server. Without this reference, we wouldn't be able to do any calls to the created hub.

Now create a file named "script.js" inside of the Scripts folder:

BigImage

Insert the following:

var signalrApp = angular.module('signalrApp', []);

signalrApp.controller('MainCtrl', ['$scope', function ($scope) {
//Initialize variables
$scope.clientCount = 0;
$scope.name = '';
$scope.text = '';

//Focus name input
$('#nameInput').val('').focus();

//Array that will hold messages
$scope.messages = [];

//Declare proxy to the chat hub
$scope.chat = $.connection.chatHub;

//Create a function that will be called from the hub
$scope.chat.client.broadcastMessage = function (name, text) {
//Validate message
if (name && text) {
//push the message to the array
$scope.messages.push({ 'name': name, 'text': text });
//Update the angular scope
$scope.$apply();
}
}
//Create function that will be called from the hub when client connects
$scope.chat.client.onClientConnected = function (count) {
//Set the client count to
$scope.clientCount = count;
//Update the angular scope
$scope.$apply();
}

//Start connection
$.connection.hub.start().done(function () {
//Setup method that will be called from the UI
$scope.sendMessage = function () {
//Call the sendMessage method on the hub containing the name and text.
$scope.chat.server.sendMessage($scope.name, $scope.text);
//Reset text
$scope.text = '';
//Focus text input
$('#textInput').val('').focus();
//Update the angular scope
$scope.$apply();
}
})
}])

 

The code is quite well documented. But make sure that you understand that this method will call with the chatHub:

$scope.chat.server.sendMessage($scope.name, $scope.text);

Which will then be received and then call the client method:

$scope.chat.client.broadcastMessage = function (name, text) {

The same goes for the online count

As you have seen Angular is used to update the user interface, but since SignalR is outside of the Angular scope we will need to call the $apply() method on the scope to update the UI.

Now you should be able to create your very own ASP.NET SignalR Web Application :)

...And here is the source code:

SignalRChatApp.zip

Good luck!