Business Problem

Recently for a research project, we had to design a solution for a check-in process for a company who specializes in organizing big conferences. For the longest time, these conferences where lacking an automated system. This meant that attendees would line up in multiple queues at the venue, and organizers would manually register and check in each person. This process was very slow and time consuming, so the company was seeking a smart and cost-effective solution that would automate the registration and check-in process at the venue.

Approach

To create this solution, we used a unique device called a Beacon, which is one of the latest communications tools that takes advantage of both mobile technology and proximity. Beacons are small transmitting devices that communicate using Bluetooth Low Energy (BLE), an upgraded version of the Bluetooth technology. Every Beacon transmits a unique identifier signal at regular intervals, which can then be picked up by a compatible app running on a device.

The idea was to install multiple Beacons near the entry gates to the conference and have all of the conference attendees download a compatible mobile app that would be able to recognize the Beacon signals. As the attendees approached the entry gates, the mobile app would discover the nearest Beacon around them and send the unique identifier signal of it to a centralized Identity System (IS). Based on the unique details received, the IS then resolves the identity of the Beacon and generates a unique one time password (OTP) which is sent back to both the mobile app and a machine (laptop/desktop/tablet) at the check-in counter. Once the attendee reaches the check-in counter, s/he locates her/his name on the screen and enters their unique OTP on their mobile, which then prints their entry pass for the conference.

How does SignalR fit in?

In a traditional client-server communication, a client always initiates a request to the server and server in turn sends a response back to the client. But when it comes to real-time updates, this communication chain is ineffective because the client won't know whether the server has the data needed to be requested, and therefore doesn't know when to send in a request.

To combat this, the server should push the data to a client whenever its available to be sent across, which can be accomplished using SignalR. In the scenario given above, the IS automatically sends the OTP to the machine at the check-in counter as soon as it receives a request from the mobile app. The mobile app initiates the request to the IS, and the IS in turn sends the OTP to both the mobile app and the machine at the check-in counter. This is a perfect contender for using SignalR to send real-time data from the IS (the server with the information bank) to the mobile app and check-in counter machine (the client requesting information).

What is SignalR?

SignalR is an open-source API provided for ASP.NET web applications and used to add "real-time" web functionality to ASP.NET applications. "Real-time" web functionality is the ability to have a server code push contents to connected clients.

SignalR supports this "server push" or "broadcasting" functionality because it handles connection management automatically. In classic HTTP connections for client-server communication, the connection must be re-established for each request; with SignalR, there is persistent connection between the client and the server. In these SignalR functions, the server code calls out to a client code in the browser using Remote Procedure Calls (RPC), rather than using the request-response model.

This diagram depicts how communication happens between the client and the server when using SignalR.

SignalR
SignalR

Connection and Hubs

The SignalR API contains two models for communicating between clients and servers: Persistent Connections and Hubs.

A Connection represents a simple endpoint for sending single-recipient, grouped, or broadcast messages. The Persistent Connection API gives the developer direct access to the low-level communication protocol that SignalR exposes. This API uses the specified format of the actual message sent as well as the preferred model (messaging and dispatching versus remote invocation) of the developer.

A Hub is a more high-level pipeline built upon the Connection API that allows the client and server to call methods on each other directly. SignalR handles the dispatching across machine boundaries as if by magic, allowing clients to call methods on the server as easily as local methods, and vice versa. Using a Hub also allows the passage of strongly typed parameters to methods, enabling model binding.

In our implementation, we chose Hub as the communicating model.

Implementation

To build this app, we used Microsoft Visual Studio 2013 and C#.

  1. To start with, add a reference of the Microsoft.AspNet.SignalR library from the NuGet package. This will add references of SignalR to your application
  2. Create a Hub class: [HubName("beacon")]//Represents client side name of our hub public class BeaconHub : Hub { //To store list of registered clients. You can have your own custom logic. public static Hashtable htUsers_ConIds = new Hashtable(); //Server method to be called from client side public void RegisterConId(string machineId) { //Implementation to add clients with their ConnectionId in hashtable when they get connected to server at start. //We are storing mapping of machineId and unique connectionId of that machine. htUsers_ConIds.Add(machineId, Context.ConnectionId); } }Here, the RegisterConld method is defined for the client-side code to make an RPC call to the server. By using HubNameAttribute, we can specify any client-side names for the Hub. Each client connecting to a Hub passes a unique connection ID. This value can be retrieved in the Context.ConnectionId property of the hub context. There are no restrictions, so there can be as many Hub classes in the project as necessary
  3. We then need to map the SignalR hubs to the app builder pipeline at "/signalr". We can do that in either Global.asax with RouteTable.Routes. MapHubs(); or in Startup.cs with public void Configuration(IAppBuilder app) { //Any connection or hub wire up and configuration should go here app.MapSignalR(new HubConfiguration()); }
  4. Then, we must write a code to call the client method from outside the Hub class (the APIController in this case). Here, the controller gets the context object and uses the context to call the updateData method on all the clients that are connected to the Hub named BeaconHub. public class POSApiController : ApiController { protected readonly Lazy<IHubContext> beaconHub = new Lazy<IHubContext>(() => GlobalHost.ConnectionManager.GetHubContext<BeaconHub>()); [HttpPost] public void Index(dynamic parameters) { string machineId = Convert.ToString(parameters.machineId); //Send otp to client application if (BeaconHub.htUsers_ConIds != null && BeaconHub.htUsers_ConIds[machineId] != null) { //updateData is the client function being called from server beaconHub.Value.Clients.Client(Convert.ToString(BeaconHub.htUsers_ConIds[machineId])).updateData(new UserProfileVM()); } } }In the above code, the BeaconHub.htUsers_ConIds[machineId] line actually returns the unique ConnectionId of the client based on a variable machineId from hashtable.htUsers_ConIds (See step #2 above for where the client's unique ConnectionId is stored for every machineId). The function above is calling the updateData method of only the client whose machineId is being received in the function parameter. If we wanted to broadcast this message to all of the registered clients, we would use beaconHub.Value.Clients.ALL.updateData(new UserProfileVM()). This statement will call the updateData function of all the registered client machines from the server.
  5. Finally, we move to the client side. Add the JavaScript code given below into a JavaScript file and refer it on your HTML page. <script type="text/javascript"> $(document).ready(function () { $.connection.hub.url = 'http://ndi-lap-151.3pillar.corp:83/'+'signalr'; hub = $.connection.beacon; hub.client.updateData = function (msg) { //Implementation }; $.connection.hub.start({ jsonp: true }).done(function () { var machineId = ‘myMachineId’; //Calling server method registerConId from client side hub.server.registerConId(machineId); }); }); <script>This code first creates a client (hub) of the Beaconhub class in JavaScript, which is referred to as "beacon." The URL should be where the application is deployed with the /signalr appended, because this is where all the signalr hubs are available (refer to step #3). Next, there is a method named updateData on the client side to be called by the server. This is the same function found in step #4 that is called by the server on the client side. Finally, when the connection with the server begins, the communication is initiated by calling the registerConID method of the server from the client side, which is the same function written into the BeaconHub class in step #2. The registerConId method then maps the machinId passed in parameter with the unique client ConnectoinId and adds it in a hashtable for further use.

Conclusion

This demonstration shows how SignalR can be used to build real time web applications. A client needs not poll the server continuously; instead, the server will push the data to the client whenever it is available for them. The SignalR library is easy to use and works on reliable persisted connections to send across the data. It allows both the client and the server to call each other's local functions as if they are their own.