Coding for the Real-time Web

Exclusive offer: get 50% off this eBook here
ASP.NET MVC 4 Mobile App Development

ASP.NET MVC 4 Mobile App Development — Save 50%

Create next-generation applications for smart phones, tablets, and mobile devices using the ASP.NET MVC development framework with this book and ebook

$26.99    $13.50
by Andy Meadows | July 2013 | .NET Enterprise Articles

The article by Andy Meadows, the author of ASP.NET MVC 4 Mobile App Development, talks about how we can use always-on connectivity to provide the illusion of a desktop application within BrewHow. He then talks about imposing SignalR to simulate push notifications from the server to BrewHow.

(For more resources related to this topic, see here.)

As the lines between web apps and traditional desktop apps blur, our users have come to expect real-time behavior in our web apps—something that is traditionally the domain of the desktop. One cannot really blame them. Real-time interaction with data, services, and even other users has driven the connected revolution, and we are now connected in more ways than ever before. However valid this desire to be always connected and immediately informed of an event, there are inherent challenges in real-time interactions within web apps.

The first challenge is that the Web is stateless. The Web is built on HTTP, a protocol that is request/response; for each request a browser makes, there is one and only one response. There are frameworks and techniques we can use to mask the statelessness of the Web, but there is no true state built into the Web or HTTP.

This is further complicated as the Web is client/server. As it's stateless, a server only knows of the clients connected at any one given moment, and clients can only display data to the user based upon the last interaction with the server. The only time the client and server have any knowledge of the other is during an active request/response, and this action may change the state of the client or the server. Any change to the server's state is not reflected to the other clients until they connect to the server with a new request. It's somewhat like the uncertainty principle in that the more one tries to pin down one data point of the relationship, the more uncertain one becomes about the other points.

All hope is not lost. There are several techniques that can be used to enable real-time (or near real-time) data exchange between the web server and any active client.

Simulating a connected state

In traditional web development, there has not been a way to maintain a persistent connection between a client browser and the web server. Web developers have gone to great lengths to try and simulate a connected world in the request/response world of HTTP.

Several developers have met with success using creative thinking and loopholes within the standard itself to develop techniques such as long polling and the forever frame. Now, thanks to the realization that such a technique is needed, the organizations overseeing the next generation of web standards are also heeding the call with server-sent events and web sockets.

Long polling

Long polling is the default fallback for any client and server content exchange. It is not reliant on anything but HTTP—no special standards checklists or other chicanery are required.

Long polling is like getting the silent treatment from your partner. You ask a question and you wait indefinitely for an answer. After some known period of time and what may seem like an eternity, you finally receive an answer or the request eventually times out. The process repeats again and again until the request is fully satisfied or the relationship terminates. So, yeah, it's exactly like the silent treatment.

Forever Frame

The Forever Frame technique relies on the HTTP 1.1 standard and a hidden iframe. When the page loads, it contains (or constructs) a hidden iframe used to make a request back to the server. The actual exchange between the client and the server leverages a feature of HTTP 1.1 known as Chunked Encoding. Chunked Encoding is identified by a value of chunked in the HTTP Transfer-Encoding header.

This method of data transfer is intended to allow the server to begin sending portions of data to the client before the entire length of the content is known. When simulating a real-time connection between a browser and web server, the server can dispatch messages to the client as individual chunks on the request made by the iframe.

Server-Sent Events

Server-Sent Events (SSE) provide a mechanism for a server to raise DOM events within a client web browser. This means to use SSE, the browser must support it. As of this writing, support for SSE is minimal but it has been submitted to W3C for inclusion into the HTML5 specification.

The use of SSE begins by declaring an EventSource variable:

var source = new EventSource('/my-data-source');

If you then want to listen to any and all messages sent by the source, you simply treat it as a DOM event and handle it in JavaScript.

source.onmessage = function(event) {
// Process the event.
}

SSE supports the raising of specific events and complex event messaging. The message format is a simple text-based format derivative of JSON. Two newline characters separate each message within the stream, and each message may have an id, data, and event property. SSE also supports setting the retry time using the retry keyword within a message.

:comment
:simple message
data:"this string is my message"
:complex message targeting an event
event:thatjusthappened
data:{ "who":"Professor Plum", "where":"Library", "with":"candlestick"
}

As of this writing, SSE is not supported in Internet Explorer and is partially implemented in a few mobile browsers.

WebSockets

The coup de grâce of real-time communication on the Web is WebSockets. WebSockets support a bidirectional stream between a web browser and web server and only leverage HTTP 1.1 to request a connection upgrade.

Once a connection upgrade has been granted, WebSockets communicate in full-duplex using the WebSocket protocol over a TCP connection, literally creating a client-server connection within the browser that can be used for real-time messaging.

All major desktop browsers and almost all mobile browsers support WebSockets. However, WebSocket usage requires support from the web server, and a WebSocket connection may have trouble working successfully behind a proxy.

With all the tools and techniques available to enable real-time connections between our mobile web app and the web server, how does one make the choice? We could write our code to support long polling, but that would obviously use up resources on the server and require us to do some pretty extensive plumbing on our end. We could try and use WebSockets, but for browsers lacking support or for users behind proxies, we might be introducing more problems than we would solve. If only there was a framework to handle all of this for us, try the best option available and degrade to the almost guaranteed functionality of long polling when required.

Wait. There is. It's called SignalR.

SignalR

provides a framework that abstracts all the previously mentioned real-time connection options into one cohesive communication platform supporting both web development and traditional desktop development.

When establishing a connection between the client and server, SignalR will negotiate the best connection technique/technology possible based upon client and server capability. The actual transport used is hidden beneath a higher-level communication framework that exposes endpoints on the server and allows those endpoints to be invoked by the client. Clients, in turn, may register with the server and have messages pushed to them.

Each client is uniquely identified to the server via a connection ID. This connection ID can be used to send messages explicitly to a client or away from a client. In addition, SignalR supports the concept of groups, each group being a collection of connection IDs. These groups, just like individual connections, can be specifically included or excluded from a communication exchange.

All of these capabilities in SignalR are provided to us by two client/server communication mechanisms: persistent connections and hubs

Persistent connections

Persistent connections are the low-level connections of SignalR. That's not to say they provide access to the actual communication technique being used by SignalR, but to illustrate their primary usage as raw communication between client and server.

Persistent connections behave much as sockets do in traditional network application development. They provide an abstraction above the lower-level communication mechanisms and protocols, but offer little more than that.

When creating an endpoint to handle persistent connection requests over HTTP, the class for handling the connection requests must reside within the Controllers folder (or any other folder containing controllers) and extend the PersistentConnection class.

public class MyPersistentConnection: PersistentConnection
{
}

The PersistentConnection class manages connections from the client to the server by way of events. To handle these connection events, any class that is derived from PersistentConnection may override the methods defined within the PersistentConnection class.

Client interactions with the server raise the following events:

  • OnConnected: This is invoked by the framework when a new connection to the server is made.
  • OnReconnected: This is invoked when a client connection that has been terminated has reestablished a connection to the server.
  • OnRejoiningGroups: This is invoked when a client connection that has timed out is being reestablished so that the connection may be rejoined to the appropriate groups.
  • OnReceived: This method is invoked when data is received from the client
  • OnDisconnected: This is invoked when the connection between the client and server has been terminated.

Interaction with the client occurs through the Connection property of the PersistentConnection class. When an event is raised, the implementing class can determine if it wishes to broadcast a message using Connection.Broadcast, respond to a specific client using Connection.Send, or add the client that triggered the message to a group using Connection.Groups.

Hubs

Hubs provide us an abstraction over the PersistentConnection class by masking some of the overhead involved in managing raw connections between client and server.

Similar to a persistent connection, a hub is contained within the Controllers folder of your project but instead, extends the Hub base class.

public class MyHub : Hub
{
}

While a hub supports the ability to be notified of connection, reconnection, and disconnection events, unlike the event-driven persistent connection a hub handles the event dispatching for us. Any publicly available method on the Hub class is treated as an endpoint and is addressable by any client by name.

public class MyHub : Hub
{
public void SendMeAMessage(string message)
{ /* ... */ }
}

A hub can communicate with any of its clients using the Clients property of the Hub base class. This property supports methods, just like the Connection property of PersistentConnection, to communicate with specific clients, all clients, or groups of clients.

Rather than break down all the functionality available to us in the Hub class, we will instead learn from an example.

ASP.NET MVC 4 Mobile App Development Create next-generation applications for smart phones, tablets, and mobile devices using the ASP.NET MVC development framework with this book and ebook
Published: July 2013
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

Real-time recipe updates

Within our BrewHow mobile app, it would be nice to receive notifications of new recipe additions when we are looking at the recipe list. To accomplish this, we will use the Hub mechanism provided by the SignalR framework to accomplish real-time notification of additions to the BrewHow recipe collection.

Installing and configuring SignalR

SignalR, like most modern .NET frameworks, is available as a NuGet package: Microsoft.AspNet.SignalR. We can install the package by entering the following into the Package Manager console:

Install-Package Microsoft.AspNet.SignalR

In addition to several assembly references to our project, the SignalR package also adds a new JavaScript file: jquery.signalR-1.1.2.min.js—your version may vary depending upon when you're actually reading this. This JavaScript file contains all the abstractions needed by the client web browser to communicate with both types of SignalR endpoints: persistent connections and hubs.

The SignalR JavaScript file is only one part of the client puzzle. To enable SignalR support in our app, we need to add references to the SignalR JavaScript library as well as to invoke the handler, /signalr/hubs, used to create a JavaScript proxy for any hubs within our project. These references will be placed in _Layout.cshtml.

@Scripts.Render("~/bundles/jquery")
<script
src = "~/Scripts/jquery.signalR-1.1.2.min.js"
type="text/javascript"></script>
<script
src = "~/signalr/hubs"
type="text/javascript"></script>

@RenderSection("scripts", required: false)

We must also register the /signalr/hubs route with the runtime. We can do this by simply invoking the MapHubs extension method for the route collection where we register the other routes for our app.

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHubs();
routes.MapRoute(
name: "BeerByStyle",

Note that the hub route is placed before all other MapRoute calls or other methods we may use to register routes. We do this because route selection is made on first match, and we don't want to inadvertently register something before SignalR within our route table.

Creating the recipe hub

We need to provide a hub to which clients can connect to receive notifications about new recipe additions.

Right-click on the Controllers folder of our project and select Add New Item….

In the Add New Item dialog box, search for SignalR and choose the SignalR Hub Class. Name the class RecipeHub.cs and click on Add.

We need to modify the RecipeHub class generated by Visual Studio. As stated earlier, clients are going to receive notifications about new recipes, but no client is ever going to post directly to this hub to communicate with the server. As such, we simply need to create an empty hub.

namespace BrewHow.Controllers
{
public class RecipeHub : Hub
{
}
}

An empty class may appear rather meaningless at first glance, but SignalR cannot create a proxy for clients to interact with the server without a class declaration.

Modifying the recipe list view

The recipe list view needs to be modified to connect to the recipe hub. The first order of business is to supply the recipe list with an ID. The ID will be used to locate and modify the list using jQuery. Assign the recipe list an ID of recipe-list.

<table id ="recipe-list">

We can now add some JavaScript that will connect to the recipe hub and upon the notification of a new recipe, append new recipes at the bottom of our table with a background color of yellow.

$(function () {
$.connection.hub.start();
var recipeHub = $.connection.recipeHub;
recipeHub.client.recipeAdded = function (recipe) {
var tr = $("#recipe-list").find('tbody')
.append(
$('<tr>').css('background-color', '#ff0')
.append($('<td>')
.append($('<a>')
.attr('href', '/Recipe/Details/'
+ recipe.RecipeId
+ "/" + recipe.Slug)
.text(recipe.Name))
)
.append($('<td>')
.append($('<a>')
.attr('href', '/Recipe/'
+recipe.StyleSlug)
.text(recipe.Style))
)
.append($('<td>'
+ recipe
.OriginalGravity
.toFixed(3)
+ '</td>'))
.append($('<td>'
+ recipe
.FinalGravity
.toFixed(3)
+ '</td>'))
@if (Request.IsAuthenticated) {
@: .append($('<td>'
@: + 'Add to Library'
@: + '</td>'))
}
);
}
});

The JavaScript code is contained within a closure, ensuring it is only invoked once and cannot be invoked by any outside source. The very first line of code starts the hub connections on the client:

$.connection.hub.start();

The connection object is an object added to jQuery by the SignalR JavaScript. The hub property of the connection object provides a reference to the hub infrastructure of the SignalR client library. The call to the start method initializes the SignalR client and prepares the proxy code generated by the /signalr/hubs call in our _Layout.cshtml page to receive notifications from the server.

Next, the JavaScript establishes a connection to our recipe hub:

var recipeHub = $.connection.recipeHub;

On examining this code carefully, you will see that the connection to our RecipeHub class is identified in the connection class as recipeHub. The /signalr/hubs call that generates the proxy classes for the hubs within our app adds each hub it finds to the connection object using a camel-cased version of the hub class name: RecipeHub becomes recipeHub, MyHub becomes myHub, and so on.

The next line of code registers a method on the client to be invoked by the server when a new recipe is added.

recipeHub.client.recipeAdded = function (recipe) {

We could call this method anything we wanted—well anything except a name that matches a server-side method within the hub. It is the act of declaring a function on the client and assigning it to the client property of the hub that makes the method available to the server.

The rest of the code simply takes the RecipeDisplayViewModel object it receives and appends it to the table with a yellow highlight.

Publishing event notifications

We have talked about responding to clients from within a Hub or PersistentConnection based class. However, our RecipeHub class is empty and we have no other hub. Not to fret. We can notify other users of our app that this event occurred by placing code into the Create method of the RecipeController class after a recipe is saved to the repository.

var context = Microsoft.AspNet.SignalR.
GlobalHost
.ConnectionManager
.GetHubContext<RecipeHub>();
context
.Clients
.All
.recipeAdded(
_displayViewModelMapper
.EntityToViewModel(recipeEntity)
);

This code begins with retrieving the context of our RecipeHub class. We do this using the GetHubContext() method of the SignalR ConnectionManager. We then prepare to make a broadcast to all clients of the RecipeHub class using the context's Clients.All property.

Sir Arthur C Clarke said:

"Any sufficiently advanced technology is indistinguishable from magic."

I will let you be the judge as to whether or not it's magic, but to invoke the recipeAdded method we defined and assigned to the client in JavaScript, we simply invoke it here passing the data we wish to return. The runtime handles the event dispatching for us and informs all clients of the RecipeHub class that we are invoking the recipeAdded method. If there is such a method on the client it will be invoked by the SignalR client code.

There is one more change required to make this work. Our repository currently doesn't set the RecipeId property of a recipeEntity class when it has been created. As we use the recipe's ID to provide links to the details from the list, we need to make sure it's available to all clients to which the broadcast is sent. This change is fairly simple. Just modify the repository to set RecipeId after changes to the Entity Framework context have been made.

recipeEntity.RecipeId = newRecipeModel.RecipeId;

Everything should work now. We just need two clients simultaneously connected to test it.

Upon adding the recipe in Google Chrome, it magically appears within Opera Mobile in the recipe list.

Summary

In this article we took a look at SignalR. The SignalR framework gives us unprecedented control of the communication between the browser and web server enabling real-time communication. This technology can be leveraged in games, real-time status updates, or to mimic push communications within a mobile web app.

Resources for Article :


Further resources on this subject:


ASP.NET MVC 4 Mobile App Development Create next-generation applications for smart phones, tablets, and mobile devices using the ASP.NET MVC development framework with this book and ebook
Published: July 2013
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Andy Meadows

Andy Meadows has been in a love affair with technology since his third-grade teacher introduced him to her TRS-80 Model III in 1981. After several months of typing "Go North" on the keyboard, he began his foray into BASIC programming. The TRS-80 Model III begat a Commodore 64 and an introduction to Pascal. By 1988, he was spending his summers earning money by writing software in C for local small businesses.

While attending college at the University of Georgia, Andy developed his passion for web development and, of course, beer. His first web application was a series of CGI scripts that output content for NCSA Mosaic and by 1994, he was designing web interfaces for global information systems.

After college, Andy wandered listlessly through the IT world spending time in several verticals using several different languages, but he always returned home to web development. In 2002, he began his foray into mobile development beginning with native Java development, and quickly moving into the mobile web space where he began marrying his two passions: mobile web development and .NET.

Since then, Andy has worked on several projects involving mobile development, web development, or both. He is extremely excited about the future of the mobile web made possible by the newest generation of mobile devices. He is currently working at a startup in Atlanta, where he lives with his wife and two children.

Books From Packt


PhoneGap 2.x Mobile Application Development Hotshot
PhoneGap 2.x Mobile Application Development Hotshot

Appcelerator Titanium: Patterns and Best Practices
Appcelerator Titanium: Patterns and Best Practices

PhoneGap Mobile Application Development Cookbook
PhoneGap Mobile Application Development Cookbook

Socket.IO Real-time Web Application Development
Socket.IO Real-time Web Application Development

PhoneGap Beginner's Guide
PhoneGap Beginner's Guide

Instant PhoneGap Social App Development [Instant]
Instant PhoneGap Social App Development [Instant]

WordPress Mobile Applications with PhoneGap
WordPress Mobile Applications with PhoneGap

Appcelerator Titanium Smartphone App Development Cookbook
Appcelerator Titanium Smartphone App Development Cookbook


Your rating: None Average: 1.3 (3 votes)

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
P
f
4
1
n
3
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software