.net, Asp.net, C#

Real time server side push notifications using Microsoft SignalR

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.

Advertisements
C#, Microsoft, Technical, Visual Studio

Visual Studio 2010 unable to resolve project reference

I created a new console application in VS 2010 and imported an existing class library project from the disc into the solution. When I tried to build the project VS was complaining that it was unable to resolve the reference to the project. I did ensure that the imported project was correctly referenced in the console app.

It was due to the fact that the console app was targeting the .net 4.0 client framework and the class library was targeting the full .net 4.0 framework. I changed the console app to target the full framework and voila I was able to build the solution successfully!

C#, Microsoft, Technical, Tips, XML

Case insensitive XPath query

I wanted to do a case insensitive xpath lookup in my C# .Net application. There was no direct way that i could find to get the job done, but fortunately the workaround ain’t that difficult. Lets consider the following example:

<xml>
<books>
<book id=”1″ name=”Book1″ type=”fiction” />
<book id=”2″ name=”Book2″ type=”nonfiction” />
<book id=”1″ name=”Book1″ type=”FICTION” />
</books>

To request for all fiction books here is the xpath query:

“books/book[translate(@type, ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’, ‘abcdefghijklmnopqrstuvwxyz’) =’fiction'”

.net, Ajax, C#, Code, Microsoft, Technical

‘Sys’ is undefined – ASP.Net Ajax error

I was using ASP.NET 2.0 along with Ajax Extensions 1.0. I received this error ‘Sys’ is undefined error message every time I used an Ajax control. I was pulling my hair out on it and decided to give the Control Toolkit’s web.config a glance. The following lines were not available in my web.config, so i copied them over:

<httpHandlers>
            <remove verb=”*” path=”*.asmx”/>
            <add verb=”*” path=”*.asmx” validate=”false” type=”System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″/>
            <add verb=”*” path=”*_AppService.axd” validate=”false” type=”System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″/>
            <add verb=”GET,HEAD” path=”ScriptResource.axd” type=”System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ validate=”false”/>
</httpHandlers>
<httpModules>
            <add name=”ScriptModule” type=”System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″/>
</httpModules>

P.S: These lines go inside the System.Web section of your web.config file

Bingo.. the error vanished and all my controls started to function as they should 🙂

 

Technorati Tags: ,,
.net, C#, Code, Microsoft, WPF

Hide a window instead of closing it in WPF

I wanted to give WPF a try and was creating a timer application which will pop up a window once a while. But what I wanted was for the application to keep running in the tray even when its closed. The following code does NOT work in WPF for some reason:

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            e.Cancel = true;
            Window.Visibility = !Window.Visibility;
        }

 

In order to hide a closing window in WPF, this is what needs to be done:

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {

            //Do some stuff here 

            //Hide Window
            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (DispatcherOperationCallback)delegate(object o)
            {
                Hide();
                return null;
            }, null);

            //Do not close application
            e.Cancel = true;

        }

.net, C#, Code, Microsoft, Technical

Using StreamReader without locking the file in C#

I was using the StreamReader class to read the contents of a text file. I was under the assumption (well I know its a bad

thing)  that because I am only reading the contents of the file, the file would be available for other applications to read or write. Guess what, i was wrong. The StreamReader class does maintain a lock on the file until you call the Close() method. So to not have the lock, we have to explicitly set up the sharing mode.

FileStream fs = new FileStream(@”c:\test.txt”, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
StreamReader sr = new StreamReader(fs);
txtContents.Text = sr.ReadToEnd();
sr.Close();

Technorati Tags: ,,
.net, C#, Microsoft, Technical

.Net CLR Windows Service and the ConfigurationManager class

I created a new windows service and attached a App.Config file to it. Then I went back to the code and tried this:

System.Configuration.ConfigurationManager.GetSection(“Extras”);

For some reason the compiler was not able to figure out the class and kept throwing an error. This does not happen with your standard EXE projects as well as ASP.NET projects. I also did not want to use the
ConfigurationSettings.GetConfig() method as it was obsolete. I fiddled around for a while and eventually ended up manually adding a reference to the
System.Configuration DLL. For those who don’t know, just right click on the References folder in your project, click on Add Reference. Select System.Configuration in the .NET tab and click OK. This should allow you to access the ConfigurationManager class. Back to work now..

I will some day write a post on how to implement custom configuration sections in the App.Config file.