Quantcast
Channel: Balaji Ramesh
Viewing all articles
Browse latest Browse all 11

Real time server side push notifications using Microsoft SignalR

$
0
0

It’s been a few years since I wrote anything, but this one deserves a post.

SignalR

Ever wanted to have a real time communication with your connected clients on your web application? Well, Microsoft SignalR helps you achieve exactly that and more. SignalR is amazing. It’s so simple to get started with, you will wonder why you haven’t used it yet. There are a few gotchas, but once you get around them, you will know how easy it is to implement real time two-way communication in your own apps.

There are many articles online about SignalR and almost all of them demo a live chat application. What I would like to show is another use case where you just need to send notifications from the server to your connected clients.

For the sake of this demo, we will create a ASP.NET MVC application. All that is required is the free Visual Studio Community Edition 2015 to get started.

Setup

Create a new Web Application project. Right click on the MVC project and click Manage Nuget packages. Search for SignalR and click install on the Microsoft.AspNet.SignalR package. You can also run the following command from the package manager console.

Install-Package Microsoft.AspNet.SignalR

This will install SignalR and all it’s dependencies. Once installed, a readme file should open up. Do take the time to read through it.

Configuration

The next step is to enable SignalR in your application. First, check if there is a Startup.cs file in your application. If there is no Startup.cs file in your project, then right click your project, click on Add New Item and select OWIN Startup class. Leave the file name as Startup.cs. If the OWIN Startup class template is missing, you can just add a regular class and copy the code below into it.

Open the Startup class, and include the app.MapSignalR() call to the Startup.Configuration method:

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(SignalRDemo.Startup))]

namespace SignalRDemo
{
	public partial class Startup
	{
		public void Configuration(IAppBuilder app)
		{
			//Existing code if any goes here
			app.MapSignalR();
		}
	}
}

At this point, we just need to make sure that SignalR is working, so hit F5 to compile and view the app in the browser. Navigate to

http://<yourprojecturl>/signalr/hubs

This should open up the JavaScript proxy that SignalR has generated automatically for us. If the proxy script is visible, then SignalR is working as it should. If not, retrace the steps.

Send Notifications

Back on Visual Studio, create a new folder called Hubs under your project, and add a new SignalR Hub Class named NotificationHub.cs with the following code:

using Microsoft.AspNet.SignalR;

namespace SignalRDemo.Hubs
{
  public class NotificationHub : Hub
  {
    public void NotifyAll(string title, string message, string alertType)
    {
      Clients.All.displayNotification(title, message, alertType);
    }
  }
}

The above piece of code:

  1. By inheriting from the Hub class, instructs SignalR to work its magic and generate a JavaScript proxy automatically. This will allow JavaScript clients to communicate with the server and vice versa
  2. Creates a server method called NofifyAll that is available for calls from client
  3. Calls the JavaScript method displayNotification on the connected clients

Next, we would need a form to pass the notification info and call the NotifyAll method on the server.

For simplicity sake, I am going to use the route Home -> Notification and create a new view that will contain the form. Open Controllers -> HomeController.cs and add the following code to the HomeController class:

public ActionResult Notification()
{
    return View();
}

Next, we will need an associated View for the above route under Views -> Home -> Notification.cshtml. Because the default Asp.Net template uses Bootstrap, we will use it’s inbuilt styles to format our form elements.

@{
    ViewBag.Title = "Notification";
}
<h2>@ViewBag.Title.</h2>

<form role="form">
  <div class="form-group">
    <label for="title">Notification Title:</label>
    <input type="text" class="form-control" id="title">
  </div>
  <div class="form-group">
    <label for="message">Notification Message:</label>
    <input type="text" class="form-control" id="message">
  </div>
  <div class="form-group">
    <label for="alert-type">Notification Type:</label>
    <select class="form-control" id="alert-type">
      <option value="info" selected>Information</option>
      <option value="success">Success</option>
      <option value="warning">Warning</option>
      <option value="danger">Error</option>
    </select>
  </div>
  <button type="button" class="btn btn-primary" id="send-notification">Send to All</button>
</form>

Next, add the JavaScript code below to communicate with the SignalR autogenerated proxy and send the notification to the server when the user clicks the Send to All button.

@section Scripts{
  <script type="text/javascript">
    $(function () {     //execute on document ready

      //access the global hubConnector object created by master page
      window.notifyApp.hubConnector.done(function () {

        $('#send-notification').click(function () {

          var title = $('#title').val(),
              message = $('#message').val(),
              type = $('#alert-type').val();

          //Call the notifyAll method on the hub. Notice camelCasing on the method name.
          $.connection.notificationHub.server.notifyAll(title, message, type);

          //Clear values and reset focus for next comment.
          $('#title').val('').focus();
          $('#message').val('');

        });   //end send notification click handler

      });     //end hub started handler

    });       //end document ready event handler
  </script>
}


Let’s look at the code above:
Line 6: The SignalR hub must be started before we can send notifications. And because we will require a SignalR connection for receiving notifications too, we will start the connection in the master page (_Layout.cshtml). We will get to this in the Receive Notifications section below.

Line 15: The send-notification click handler requests the form values and calls the server method NotifyAll via the JavaScript hub proxy auto generated by SingalR. It’s important to note that the proxy automatically camelCases the hub and the server method names to conform to JavaScript conventions.

Receive Notifications

Now, we will include the html that will display the notification when the client receives it from the server. Like the form elements earlier, we will use Bootstrap’s inbuilt alert styles to display our notifications.

Here’s a sample of the notification HTML using Bootstrap alerts.

<div class="alert alert-info alert-dismissible" role="alert">
  <button type="button" class="close" data-dismiss="alert"><span>×</span></button>
  <strong>Title</strong> Message goes here
</div>

Ideally we would like the users to receive as many alerts and have them all visible until the user explicitly dismisses them. To achieve this, we will be creating the above HTML programatically and inject them into a container HTML element using a little bit of jQuery.

So open the Views->Shared->_Layout.cshtml file and add the following code where you would want the notification displayed:

<div id="alert-placeholder" style="padding: 5px;"></div>

I’ve used inline style to pad the container from the header, please use dedicated CSS classes for styling though. Now, add the following JavaScript below the jquery and bootstrap bundles.

Reference to the SignalR library and the auto-generated hub proxy

<script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
<script src="~/SignalR/Hubs"></script>

JavaScript to receive the notification and convert into a Bootstrap alert.

<script type="text/javascript">
  //a helper function to encode HTML values.
  function htmlEncode(value) {
    return $('<div />').text(value).html();
  }

  //execute on document ready
  $(function () {

    //function that the hub can call when it receives a notification.
    $.connection.notificationHub.client.displayNotification = function (title, message, alertType) {

      //Create the bootstrap alert html
      var alertHtml = '<div class="alert alert-' + htmlEncode(alertType) + ' alert-dismissible" role="alert"><button type="button" class="close" data-dismiss="alert"><span>×</span></button><strong>' + htmlEncode(title) + '</strong> ' + htmlEncode(message) + '</div>';

      $(alertHtml)
        .hide()                           //hide the newly created element (this is required for fadeIn to work)
        .appendTo('#alert-placeholder')   //add it to the palceholder in the page
        .fadeIn(500);                     //little flair to grab user attention
    };

    window.notifyApp = {
      hubConnector: $.connection.hub.start()  //start the connection and store object returned globally for access in child views
    };

  });

</script>


Lines 16 through 18 intiates the SignalR connection and stores the return object globally for use in child views. (Refer Send Notifications section on this)

This takes care of the code that is required to display the notification. Hit F5 to compile the application and view in browser. To test, leave multiple tabs/windows of your application in your browser open. Open a new tab and navigate to:

http://<yourprojecturl>/Home/Notification

Fill the form fields and hit Send to All. You should see the notification displayed on all open tabs/windows. Try sending another notification and check the behavior.

Next Steps

It’s important to understand that this article is just an introduction into the fascinating world of real time communications using SignalR. I would highly recommend reading the reference material available as SignalR does provide a lot of customizable options.

Also the article does not deal with security. It effectively allows anyone to send a notification to all connected clients. Refer to the Introduction to SignalR Security article for information on using the Authorize attribute to secure access.

You can fork a copy of this project from GitHub.



Viewing all articles
Browse latest Browse all 11

Latest Images

Trending Articles





Latest Images