Introduction to WebSockets with SignalR in .NET Part 6: the basics of publishing to groups

Introduction

So far in this series on SignalR we’ve published all messages to all connected users. The goal of this post is to show how you can direct messages to groups of people. It is based on a request of a commenter on part 5. You can think of groups as chat rooms in a chat application. Only members of the chat room should see messages directed at that room. All other rooms should remain oblivious of those messages.

We’ll build upon the SignalR demo app we’ve been working on in this series. So have it open in Visual Studio. We’ll simulate the following scenario:

  • When a client connects for the first time they are assigned a random age between 6 and 100 inclusive
  • The client joins a “chat room” based on this age by calling a function in ResultsHub
  • When the client sends a message then only those already in the chat room will be notified

The real-life version would of course involve some sign-up page where the user can define which room to join or what their age is. You can also store those users if the chat application is closed to unanonymous users. However, all that would involve too much extra infrastructure irrelevant to the main goals.

Joining a group

We first need to assign an age to the client when they navigate to the Home page. Locate HomeController.cs. The Index action currently only returns a View. Extend it as follows:

public ActionResult Index()
{
	Random random = new Random();
	int next = random.Next(6, 101);
	ViewBag.Age = next;
        return View();
}

Normally you’d pass the age into the View in a view-model object but ViewBag will do just fine. In Index.cshtml add the following markup just below the Register message header:

<div>
    Your randomised age is <span id="ageSpan">@ViewBag.Age</span>
</div>

Now we want to call a specific Hub function as soon as the connection with the hub has been set up. The server side function will put the user in the appropriate chat room based on their age. Insert the following code into results.js just below the call to hub.start():

$.connection.hub.start().done(function ()
{        
        var age = $("#ageSpan").html();
        resultsHub.server.joinAppropriateRoom(age);
});  

When the start() function has successfully returned we’ll read the age from the span element and run a method called joinAppropriateRoom in ResultsHub. Open ResultsHub.cs and define the function and some private helpers as follows:

public void JoinAppropriateRoom(int age)
{
	string roomName = FindRoomName(age);
	string connectionId = Context.ConnectionId;
	JoinRoom(connectionId, roomName);
	string completeMessage = string.Concat("Connection ", connectionId, " has joined the room called ", roomName);
	Clients.All.registerMessage(completeMessage);
}

private Task JoinRoom(string connectionId, string roomName)
{			
	return Groups.Add(connectionId, roomName);
}	

private string FindRoomName(int age)
{
	string roomName = "Default";
	if (age < 18)
	{
		roomName = "The young ones";
	}
	else if (age < 65)
	{
		roomName = "Still working";
	}
	else
	{
		roomName = "Old age pensioners";
	}
	return roomName;
}

We’ll first find the appropriate room for the user based on the age. We’ve defined 3 broad groups: youngsters, employed and old age pensioners. We extract the connection ID and put it into the correct room. Note that we didn’t need to define a group beforehand. It will be set up automatically as soon as the first member is added to it. We then also notify every client that there’s a new member.

While we’re at it let’s define the function that will be called by the client to register the message together with their age. The age is again needed to locate the correct group. Add the following method to ResultsHub.cs:

public void DispatchMessage(string message, int age)
{			
	string roomName = FindRoomName(age);			
	string completeMessage = string.Concat(Context.ConnectionId
		, " has registered the following message: ", message, ". Their age is ", age, ". ");
	Clients.Group(roomName).registerMessage(completeMessage);
}

We again find the correct group, construct a message and send out the message to everyone in that group.

There’s one last change before we can test this. Locate the newMessage function definition of the messageModel prototype in results.js. It currently calls the simpler sendMessage function of ResultsHub. Comment out that call. Update the function definition as follows:

newMessage: function () {
            var age = $("#ageSpan").html();
            //resultsHub.server.sendMessage(this.registeredMessage());
            resultsHub.server.dispatchMessage(this.registeredMessage(), age);
            this.registeredMessage("");
        },
.
.
.

Run the application. The first client should see that they have joined some room based on their age. In my case it looks as follows:

First client joining a group

Open some more browser windows with the same URL and all of them should be assigned an age and a group. The very first client should see them all. In my test I got the following participants:

First client sees all subsequent chat participants

I started up 6 clients: 3 old age pensioners, 2 youngsters and 1 still working. It’s not easy to copy all windows so that we can see everything but here are the 6 windows:

All clients joining some group and conversing

The top left window was the very first client, a 77-year-old who joined the pensioners’ room. The one below that is a 65-year-old pensioner. Under that we have a 24-year-old worker. Then on the right hand side from top to bottom we have a 15-year-old, a 90-year-old and finally a 6-year-old client. Then the 65-year-old client sent a message which only the other pensioners have receiver. Check the last message in each window: the clients of 24, 6 and 15 years of age cannot see the message. Then the 6-year-old kid sent a message. This time only the 2 youngsters were sent the message. You’ll see that the 24-year old worker has not received any of the messages.

We’ve seen a way how you can direct messages based on group membership. You can define the names of the rooms in advance, e.g. in a database, so that your users can pick one upon joining your chat application. Then instead of sending in their age they can send the name of the room which to join. However, if you’re targeting specific users without them being aware of these groups you’ll need to collect the criteria from them based on which you can decide where to put them. In the above example the only criteria was their age. In other case it can be a more elaborate list of conditions.

View the list of posts on Messaging here.

Advertisements

Introduction to WebSockets with SignalR in .NET Part 5: dependency injection in Hub

Introduction

We’ve now gone through the basics of SignalR. We’ve looked at a messaging project and a primitive, but working stock ticker. Actually most of the work is put on the client in form of JavaScript code. The WebSockets specific server side code is not too complex and follows standard C# coding syntax.

However, the relative server side simplicity doesn’t mean that our code shouldn’t follow good software engineering principles. I mean principles such as SOLID, with special subjective weight given to my favourite, the letter ‘D‘.

You’ll recall from the previous post that the stock prices were retrieved from a concrete StockService class, an instance of which was created within the body of StartStockMonitoring(). The goal now is to clean up that code so that the stock prices are retrieved from an interface instead of a concrete class. The interface should then be a parameter of the ResultsHub constructor.

We’ll use StructureMap to inject the dependency into ResultsHub.cs.

Demo

I’ll use two sources from StackOverflow to solve the problem:

Let’s start by creating the abstraction. Add the following interface to the Stocks folder:

public interface IStockService
{
	dynamic GetStockPrices();
}

Then modify the StockService declaration so that it implements the abstraction:

public class StockService : IStockService

Change the ResultsHub constructor to accept the interface dependency:

private readonly IStockService _stockService;

public ResultsHub(IStockService stockService)
{
	if (stockService == null) throw new ArgumentNullException("StockService");
	_stockService = stockService;
	StartStockMonitoring();
}

Make sure you refer to the private field in the Task body of StartStockMonitoring:

Task stockMonitoringTask = Task.Factory.StartNew(async () =>
				{					
					while(true)
					{
						dynamic stockPriceCollection = _stockService.GetStockPrices();
						Clients.All.newStockPrices(stockPriceCollection);
						await Task.Delay(5000);
					}
				}, TaskCreationOptions.LongRunning);

Next, create an interface for ResultsHub in the Stocks folder:

public interface IResultsHub
{
	void Hello();
	void SendMessage(String message);
}

…and have ResultsHub implement it:

public class ResultsHub : Hub, IResultsHub

Next import the StructureMap NuGet package:

StructureMap NuGet package

We’ll need a custom HubActivator to find the implementation of IResultsHub through StructureMap. Add the following class to the solution:

public class HubActivator : IHubActivator
{
	private readonly IContainer container;

	public HubActivator(IContainer container)
	{
		this.container = container;
	}

	public IHub Create(HubDescriptor descriptor)
	{
		return (IHub)container.GetInstance(descriptor.HubType);
	}
}

IContainer is located in the StructureMap namespace.

Next insert the following class that will initialise the StructureMap container:

public static class IoC
{
	public static IContainer Initialise()
	{
		ObjectFactory.Initialize(x =>
			{
				x.Scan(scan =>
					{
						scan.AssemblyContainingType<IResultsHub>();
						scan.WithDefaultConventions();
					});
			});
		return ObjectFactory.Container;
	}
}

The last step is to register our hub activator when the application starts. Add the following code to Application_Start() in Global.asax.cs:

IContainer container = IoC.Initialise();
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => new HubActivator(container));

That’s it actually. Set a breakpoint within the ResultsHub constructor and start the application. If all goes well then code execution should stop at the breakpoint. Inspect the incoming stockService parameter. If it’s null then something’s gone wrong but it shouldn’t be. Let the code execution continue and you’ll see that it works as before except that we’ve come a good step closer to loosely coupled code.

Read the finishing post in this series here.

View the list of posts on Messaging here.

Introduction to WebSockets with SignalR in .NET Part 4: stock price ticker

Introduction

In the last post we saw the first basic, yet complete example of SignalR in action. We demonstrated the core functionality of a messaging application where messages are shown on screen in real time.

We’re now ready to implement the demo that I promised before: update a stock price in real time and propagate the changes to all listening browsers.

We’ll build on the sample project we’ve been working on so far in this series, so have it open and let’s get into it!

Demo: server side

Add a folder to the solution called Stocks. Add a new class called Stock:

public class Stock
{
	public Stock(String name)
	{
		Name = name;
	}

	public string Name { get; set; }
	public double CurrentPrice 
	{
		get
		{
			Random random = new Random();
			return random.NextDouble() * 10.0;
		}
	}
}

We need a stock name in the constructor. We’ll simply randomize the stock price using Random.NextDouble(). In reality it will be some proper repository that does this but again, we’ll keep the example simple.

Next add a new class called StockService which will wrap stock-related methods.

Note that such service classes should be hidden behind an interface and injected into the consuming class to avoid tight coupling. However, for this sample we’ll ignore all such “noise” and concentrate on the subject matter. If you’re not sure what I’m on about then read about dependency inversion here. The next post on SignalR will explore dependency injection.

StockService takes the following form:

public class StockService
{
	private List<Stock> _stocks;

	public StockService()
	{
		_stocks = new List<Stock>();
		_stocks.Add(new Stock("GreatCompany"));
		_stocks.Add(new Stock("NiceCompany"));
		_stocks.Add(new Stock("EvilCompany"));
	}

	public dynamic GetStockPrices()
	{
		return _stocks.Select(s => new { name = s.Name, price = s.CurrentPrice });
	}
}

We maintain a list of companies whose stocks are monitored. We return an anonymous class for each Stock in the list, hence the dynamic keyword.

We’ll read these values from our ResultsHub hub. We’ll need to constantly monitor the stock prices in a loop on a separate thread so that it doesn’t block all other code. This calls for a Task from the Task Parallel Library. If you don’t know what Tasks are then check out the first couple of posts on TPL here, a basic knowledge will suffice. We’ll need to start monitoring the prices as soon as someone opens the page in a browser. We can start the process directly from the hub constructor:

public ResultsHub()
{
	StartStockMonitoring();
}

private void StartStockMonitoring()
{
	
}

Here’s the complete StartStockMonitoring method:

private void StartStockMonitoring()
{
	Task stockMonitoringTask = Task.Factory.StartNew(async () =>
		{
			StockService stockService = new StockService();
			while(true)
			{
				dynamic stockPriceCollection = stockService.GetStockPrices();
				Clients.All.newStockPrices(stockPriceCollection);
				await Task.Delay(5000);
			}
		}, TaskCreationOptions.LongRunning);
}

We start a task that instantiates a stock service and starts an infinite loop. We retrieve the stock prices and inform all clients through a newStockPrices JavaScript method and pass in the stock prices dynamic object. Then we pause the loop for 5 seconds using Task.Delay. Task.Delay returns an awaitable task so we need the await keyword. In order for that to take effect through we’ll need to decorate the lambda expression with async. You’ve never heard of await and async? Start here. Finally, we notify the task scheduler in the task constructor that this will be a long running process.

Demo: client side

Let’s extend our GUI and results.js to show the stock prices in real time. We’ll use a similar approach as we had in case of the messaging demo: knockout.js with a view-model. Add the following code to results.js:

resultsHub.client.newStockPrices = function (stockPrices) {
     viewModel.addStockPrices(stockPrices);
}

…which will be the JS function that’s called from ResultsHub.StartStockMonitoring. We’ll complete the addStockPrices later, we need some building blocks first. We’ll need a new custom JS object to store a single stock. Add the following constructor function to results.js:

var stock = function (stockName, price) {
        this.stockName = stockName;
        this.price = price;
};

Also, we need a new property in the messageModel constructor function to store the stock prices in an array:

var messageModel = function () {
        this.registeredMessage = ko.observable(""),
        this.registeredMessageList = ko.observableArray(),
        this.stockPrices = ko.observableArray()
    };

Add the following function property to messageModel.prototype:

addStockPrices: function (updatedStockPrices) {
            var self = this;     

            $.each(updatedStockPrices, function (index, updatedStockPrice) {
                var stockEntry = new stock(updatedStockPrice.name, updatedStockPrice.price);
                self.stockPrices.push(stockEntry);                
            });
}

We simply add each update to the observable stockPrices array. updatedStockPrice.name and updatedStockPrice.price come from our dynamic function in StockService:

public dynamic GetStockPrices()
{
	return _stocks.Select(s => new { name = s.Name, price = s.CurrentPrice });
}

We just need some extra HTML in Index.cshtml:

<div data-bind="foreach:stockPrices">
    <p><span data-bind="text:stockName"></span>: <span data-bind="text:price"></span></p>
</div>

The stockName and price properties in the text bindings come from the stock object in results.js.

This should be it. Start the application and you’ll see the list of stocks and their most recent prices coming in from the server in a textual form.

View the next part of this series here.

View the list of posts on Messaging here.

Introduction to WebSockets with SignalR in .NET Part 3

Introduction

We’ll continue our discussion of SignalR where we left off in the previous post. So open the SignalRWeb demo project and let’s get to it!

Demo continued

We left off having the following “scripts” section in Index.cshtml:

@section scripts
{
    <script src="~/Scripts/jquery.signalR-2.0.3.js"></script>
    <script src="~/Scripts/knockout-3.1.0.js"></script>
    <script src="~/Scripts/results.js"></script>
}

We’ll build on this example to see how a client can interact with the server through WebSockets. At present we have an empty Hello() method in our ResultsHub class. Insert another method which will allow the clients to send a message to the server:

public void SendMessage(String message)
{

}

There’s a property called Context that comes with SignalR. It is similar to HttpContext in ASP.NET: it contains a lot of information about the current connection: headers, query string, authentication etc. Just type “Context.” in the method body and inspect the available properties, they should be self-explanatory. We have no authentication so we’ll use the connection ID property of Context to give the sender some identifier:

public void SendMessage(String message)
{
	string completeMessage = string.Concat(Context.ConnectionId
		, " has registered the following message: ", message);

	Clients.All.registerMessage(completeMessage);
}

You’ll recall from the previous post that we need to deal with JavaScript in SignalR. The above piece of code will result in a JavaScript method called “registerMessage” to be invoked from the server. Where is that method? We need to write it of course. We inserted a JavaScript file called “results.js” previously. Open that file and enter the following stub:

(function () {
    var resultsHub = $.connection.resultsHub;
}());

resultsHub is a reference to the hub we’ve been working on. The “connection” property comes from the SignalR jQuery library and creates a SignalR connection. Through the connection property you’ll be able to reference your hubs. There’s no IntelliSense for the hub names, so be careful with the spelling.

We need to stop for a second and go back to Index.cshtml. There’s one more JavaScript source we need to reference, but it’s not available in the Scripts folder. Recall that we used the MapSignalR OWIN extension in Startup.cs. That extension will map the SignalR hubs to the /signalr endpoint. Add the following script declaration to the scripts section below the jquery.signalR-2.x.x.js script reference:

<script src="~/SignalR/hubs"></script>

Start the application and navigate to http://localhost:xxxxx/SignalR/hubs. You should see some JavaScript related to SignalR in the browser, so the script reference is valid. Basically this code generates proxies for the hubs. If you scroll down you’ll see that it has found the ResultsHub and its two dynamic methods:

proxies.resultsHub = this.createHubProxy('resultsHub'); 
proxies.resultsHub.client = { };
proxies.resultsHub.server = {
   hello: function () {
    return proxies.resultsHub.invoke.apply(proxies.resultsHub, $.merge(["Hello"], $.makeArray(arguments)));
   },

   sendMessage: function (message) {
      return proxies.resultsHub.invoke.apply(proxies.resultsHub, $.merge(["SendMessage"], $.makeArray(arguments)));
             }
};

As you add other hubs and other dynamic methods they will be registered here in this script generated by SignalR using Reflection. Note that the hello and sendMessage functions have been registered on the server – proxies.resultsHub.server – which is expected.

Add the following code to results.js just below the resultsHub reference:

$.connection.hub.logging = true;
$.connection.hub.start();

We turn on logging so that we can see what SignalR is doing behind the scenes. Then we tell SignalR to start the communication. This method will go through the 4 ways of establishing a connection with the client and determine which one works best.

Next we need the JavaScript methods that will be invoked: hello and registerMessage. Add the following stubs just below the call to hub.start():

resultsHub.client.hello = function(){

}

resultsHub.client.registerMessage = function (message) {

};

We’ll concentrate on the registerMessage function, hello can remain empty. Next we need to show the responses on the screen. As mentioned before we’ll use knockout.js as it provides for a very responsive GUI. I in fact only know the basics of knockout.js, as client side programming is not really my cup of tea. If you don’t know anything about knockout.js then you might want to go through the first couple of tutorials here. It is very much based on view-models which are bound to HTML elements. As the properties change so do the values of those elements in a seamless fashion. We won’t go into any detail about the knockout specific details here. Add the following code below the resultsHub.client.registerMessage stub:

var messageModel = function () {
      this.registeredMessage = ko.observable(""),
      this.registeredMessageList = ko.observableArray()
};

The registeredMessage property will show a message sent by the client. registeredMessageList will hold all messages that have been sent from the server. Next add a model prototype:

messageModel.prototype = {

        newMessage: function () {
            resultsHub.server.sendMessage(this.registeredMessage());
            this.registeredMessage("");
        },
        addMessageToList: function (message) {
            this.registeredMessageList.push(message);
        }

    };

newMessage is meant to be a function that can be invoked upon a button click. It sends the message to the server and then clears it. Recall that we called our function in ResultsHub “SendMessage”. You can call it using the “server” property followed by the name of the function you’d like to invoke. addMessageToList does exactly what the function name implies. Then we create an instance of the view-model and instruct knockout to start binding it to our GUI elements:

var viewModel = new messageModel();
$(function () {
        ko.applyBindings(viewModel);
    });

We can now fill in the resultsHub.client.registerMessage stub:

resultsHub.client.registerMessage = function (message) {
        viewModel.addMessageToList(message);
};

It simply calls upon the view-model instance to add the new message to the message list.

Now we can create the corresponding HTML code on index.cshtml. Add the following right above the scripts section.

<div>
    <input type="text" placeholder="Your message..." data-bind="value:registeredMessage" />
    <button data-bind="click:newMessage">Register message</button>
</div>

This bit of markup will serve as the “register” section where the user enters a message in the text box and sends it to the server using the button. Note the knockout-related data-bind attributes. The text box is bound to the registeredMessage property and the click event of the button is bound to the newMessage function of the model, both defined in our results.js file.

Add the following HTML below the “register” section:

<div>
    <div data-bind="foreach:registeredMessageList">
        <div data-bind="text: $data"></div>
    </div>
</div>

This is a knockout foreach expression: for each message in the registeredMessageList array we print the message in a separate div. We bind the text property of the div to the message. The current value in the foreach loop can be accessed using “$data” in knockout.

Let’s go through the expected process step by step:

  1. The user enters a message in the text box and presses the register message button
  2. The button invokes the newMessage function of the knockout view-model ‘messageModel’
  3. The newMessage function will invoke the SendMessage(string input) method of the ResultsHub.cs Hub
  4. The SendMessage function constructs some return message and calls the registerMessage JavaScript function on each client, in our case defined in results.js
  5. The regiesterMessage function receives the string returned by the SendMessage function of ResultsHub
  6. regiesterMessage adds the message to the messages array of the view-model
  7. The view-model is updated and knockout magically updates the screen with the new list of messages

Set a breakpoint within SendMessage of ResultsHub.cs. Start the application in Chrome and press F12 to open the developer tools. You should see some SignalR related messages in the log:

Connecting to WebSockets in Devtools

It has found the ResultsHub and managed to open the web socket endpoint. Note the protocol of ‘ws’. Now insert a message in the text box and press register. Code execution should stop at the breakpoint in Visual Studio meaning that we’ve managed to wire up the components correctly. I encourage you to inspect the Context property and see what’s available in it. You should then see your message under the textbox as returned by the SendMessage:

Message collection by SignalR

In the meantime the DevTools log should fill up with interesting messages such as:

  • SignalR: Invoking resultshub.SendMessage
  • SignalR: Triggering client hub event ‘registerMessage’ on hub ‘ResultsHub’.
  • SignalR: webSockets reconnecting.

You’ll see this third message if you stop at the breakpoint to check out the available properties. As this artificially slows down the response time the web sockets connection is lost and then re-opened.

If you want to talk to yourself on two different screens then open up another browser window, Firefox or IE, and navigate to the same localhost address as in Chrome. Then start sending messages. You should see them in both windows:

Messages in two browser windows

So a message sent from one browser is immediately propagated to all listeners by SignalR with minimal code from the developer.

Read the next post in this series here.

View the list of posts on Messaging here.

Introduction to WebSockets with SignalR in .NET Part 2: code basics

Introduction

In the previous post of this series we looked at the foundations of WebSockets and SignalR. We’re now ready to look at some action.

Demo

I’ll build this demo on Visual Studio 2013 Express for Web. If you have the full suite of VS 2013 Pro then you’ll be fine too. The goal is to build two model applications with SignalR: a rudimentary chat site and an equally rudimentary stock ticker site where the current stock price is updated real-time based on what the server is reporting to it. Hopefully we’ll learn enough so that you can build your own scenario: show real-time data on performance data, sport scores, the number of people on Earth etc.

Open VS 2013 and select the ASP.NET Web Application template in the New Project window with .NET 4.5 as the underlying framework. Call it SignalRWeb, click OK and then pick the MVC template. On the same window click “Change Authentication” and select the No Authentication option:

Create Web Project

We don’t want to deal with authentication issues as it would only divert us from the main topic. Click OK to create the MVC app. SignalR is not added automatically to the project. Add the Microsoft.AspNet.SignalR NuGet package to the solution:

SignalR Nuget package

This will install a number of other NuGet packages and dependencies. You will be greeted with a readme.txt file in Visual Studio giving you hints about the initial steps. If you followed along the introductory posts on Owin then you’ll recognise the short sample code:

public class Startup
{
     public void Configuration(IAppBuilder app)
     {
         app.MapSignalR();
     }
}

We have the Startup class with the Configuration method that accepts an IAppBuilder object. We call an extension method on this app builder. If you don’t understand what this means then it’s best if you at least skim through the posts on OWIN first.

Normally if you create an MVC app with the default “Individual user Accounts” authentication option then the project starting point will already have Katana components in it that are related to authentication: OAuth – Facebook, Google, etc., or authentication using some other user store. However, we have no authentication at all in our project and there’s no OWIN Startup entry point class either. In fact, the Owin libraries were only added when we downloaded the SignalR NuGet package and its dependencies. This means we’ll need to create it ourselves, but that’s OK. Add a new class to the project called Startup.cs. Be sure to call it “Startup” and not “startup” or “StartUp” so that we follow the naming conventions. Let’s do exactly as it says in readme.txt and add the following code to Startup.cs:

public void Configuration(IAppBuilder app)
{
     app.MapSignalR();
}

You’ll need to import the Owin namespace. This extension will make sure that our app starts listening to requests. You’ll recall from the previous post that we’ll need to create at least one Hub that clients can connect to. Add a new folder called Hubs. In that folder add a new class. In the Add New Item window you’ll notice that there are some new template types under the Web/SignalR category:

SignalR hub class template

Select the Hub Class template. The Persistent Connection template is similar but you’ll need to deal with connections at a lower level whereas the Hub Class represents a higher level of abstraction. I’ve never used the Persistent Connection template but I believe it’s rather for experienced programmers who may want to control connections at a lower level for customisation purposes.

Call the class “ResultsHub.cs”. You’ll be provided a very short class implementation that derives from Hub:

public class ResultsHub : Hub
{
     public void Hello()
     {
         Clients.All.hello();
     }
}

Let’s explore this a little before we continue with our main goal. Clients.All represents all clients that have connected to this hub which has a simple hello() method. “All” is a dynamic property so you can attach any method name to it: elvisPresley(), mickeyMouse() etc., so don’t expect any IntelliSense there. hello() is therefore a dynamic method, you won’t find it through IntelliSense either. This bit of code means that each client should be contacted and a JavaScript function called “hello” should be invoked on each of them. Keep in mind that we’re programming a lot against JavaScript in SignalR hence the need for dynamic methods. IntelliSense cannot expect the exact JavaScript method names, right?

You don’t have to contact every caller. Start typing “Clients.” within the Hello function and you’ll see other options, e.g.:

  • Contact certain groups
  • Contact every client except some with certain connection IDs
  • One specific user

So you have some control over who will receive updates from this hub. We can send a greeting to the method if there’s a matching JavaScript method on the client side:

public class ResultsHub : Hub
{
     public void Hello()
     {
         Clients.All.hello("Welcome from SignalR!");
     }
}

Let’s see how this can be used in a view. Locate the Views/Index.cshtml view. Erase all code from it except:

@{
    ViewBag.Title = "Home Page";
}

We’ll need some JavaScript on this page. The SignalR NuGet package has installed a couple of jQuery libraries specific to SignalR. Insert the following script section stub to Index.cshtml:

@section scripts
{
<script src="~/Scripts/jquery.signalR-2.0.3.js"></script>
}

The easiest way to achieve this is to locate the jquery.signalR-2.x.x file in the Scripts folder which you can drag and drop within the curly braces of the scripts section. That will create the script tag for you automatically. This library has a dependency on jQuery but that’s already imported in Shared/_Layout.cshtml in a bundle. You’ll also find the scripts section declared in that common layout file which is why we can extend it in Index.cshtml.

We’ll also need some custom javascript. Add a new JS file into the Scripts folder called results.js. Reference it already now on the Index page:

@section scripts
{
    <script src="~/Scripts/jquery.signalR-2.0.3.js"></script>
    <script src="~/Scripts/results.js"></script>
}

We’ll also need knockout.js to make the updates on the page very responsive and fluent. It’s not currently available in our project so let’s add the following NuGet package:

knockout js NuGet package

Add it to the scripts section:

@section scripts
{
    <script src="~/Scripts/jquery.signalR-2.0.3.js"></script>
    <script src="~/Scripts/knockout-3.1.0.js"></script>
    <script src="~/Scripts/results.js"></script>
}

We’ve laid the foundations for our SignalR app. We’ll continue in the next post.

View the list of posts on Messaging here.

Introduction to WebSockets with SignalR in .NET Part 1: the basics

Introduction

The normal communication flow between a browser and a web app on a server is quite limited: the client sends a HTTP request to the server and receives a HTTP response back. If the client needs some new information then it will need to send another request to the server. Normally a web server will not just send out HTTP responses to a client without a HTTP request first to act upon.

This is true even for pages where you view the same type of data which is updated periodically. A typical example is a sports site where you can view the current standing of a game. You as the viewer would probably like to have real time updates so that you can be happy when your team scores – or smash your smart phone against the wall if it’s losing.

There are various ways to solve this problem on a web site:

  • Put a big “Refresh” button on the page which requests and updated set of objects from the server – very straightforward, but not too convenient for the client
  • Put some kind of JavaScript timer function on the web page which periodically requests an update from the server and refreshes the page
  • Same as above but use an Ajax call to only refresh the page partially

…and possibly others.

The underlying method with all three solutions is that the browser will need to keep sending the same request to the server over and over again. Imagine that this site is very popular so their server receives tens of thousands of essentially the same request. The company will need to invest in extra infrastructure, such as a web farm, a load balancer, CDN etc. Wouldn’t it be easier if the browser could tell the server: “hey, server, I need updates from you on the same set of data periodically, thanks.” And then the communication channel is magically kept open between the client and the server. The server will be able to send updates over that channel automatically without waiting for new requests. This can potentially result in an alleviated server load, a very responsive web UI and significant savings for the company in terms of reduced infrastructure.

Web Sockets

These communication channels through Web Sockets have been available for some years now, so it’s not some kind of a dream. A web socket is a TCP socket connection between the client and the server. This socket is maintained between two parties. It is a two-way full duplex communication channel: the client can send data to the server and the server can send data back to the client over the same channel at any time.

The protocol for a web socket is “ws”, such as “ws://mysite.com”. Similarly a secure web socket follows the “wss” scheme. Note that not all browsers support web sockets. Check out the table on this web site to see which browsers support it.

SignalR is a technology that alleviates the burden of setting up a web app which uses web sockets. There are many things you need to take care of with web sockets communication: serialising data, deserialising data, maintaining the connection, processing messages that arrive in no particular order. SignalR simplifies the construction of sockets-aware web apps by hiding a lot of the underlying complexity. You as a developer can then concentrate on the fun parts instead of worrying too much about low level details. SignalR can even help older browsers “understand” web sockets by emulating its behaviour.

So what’s SignalR?

As hinted on above SignalR is a Microsoft framework that makes working with web sockets easier for the programmer. You can make it available in your web project by downloading the Microsoft.AspNet.SignalR NuGet package. The most recent version at the time of writing this post is 2.0.3:

SignalR Nuget package

By the time you read this post there might be an updated package. If you see that some functionality described in this blog series is not compatible with a newer version then please comment about it and then I’ll update the posts.

As we said before Web Sockets can be quite challenging to work with if you try to do so using some low-level JavaScript package. WebSockets is not the only type of connection that enables real-time two-way communication between the client and the server. Here come some more:

SignalR will test all 4 of these until it finds one that’s available. It always tries WebSockets first as it is the the most efficient one of the 4 as far as overhead is concerned. Normally if the browser supports WebSockets then it can be used for communication. However, this is not always the case. In that case it will test the other three one after the other.

For WebSockets to succeed then even the web server will need to support this technology. You are presumably a .NET web developer so chances are high that you’ll deploy your web app on IIS. Only IIS8 and above will support WebSockets. I have Window8.1 on the PC I’m building the demo on but IIS8 should be available on Windows8 as well. The built-in IIS Express server of Visual Studio 2013 supports WebSockets. If you’d like to deploy and test your web app locally on your PC then search for IIS on your PC. If you don’t find it then you’ll need to enable it first:

Turn windows features on and off

Enable IIS

Also enable the WebSocket feature:

Enable WebSockets

Start IIS and check its version:

Check IIS version

If you’re deploying your app an Windows Server then you’ll need Windows Server 2012 and you’ll need to enable the WebSocket feature as shown above.

The SignalR NuGet package will enable us to work with both the client side and server side part of the communication. On the server side the most important component we’ll work with is called a Hub which is a class that hides the implementation details of the communication on the server side. On the client side we’ll need some JavaScript code that can be called by SignalR to connect to this Hub.

In the next post we’ll start our demo.

View the list of posts on Messaging here.

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: