User Specific Notifications Using ASP.NET MVC And SignalR

In this post, we are going to explore how to implement user-based notification using ASP.NET MVC and SignalR. If you are new to SignalR, please get some basics here.

Why SignalR?

SignalR provides "real-time" web functionality in our application using Javascript function call in client browser from the server (Server-sent Events). It has several connections for management like

  • connect/disconnect/reconnect events,
  • grouping connections,
  • authorization etc

Go to http://signalr.net for more.

We will focus on

  1. Creating a new ASP.Net MVC Web Application
  2. Add SignalR
  3. Creating Hub
  4. Enable SignalR
  5. Database Modification
  6. Send specific user Notification using SignalR

Create ASP.Net MVC Web Application

Open Visual Studio go to > File >New Project Choose ASP.Net MVC application.

ASP.NET

Choose a template. In my case, I have used MVC. Check Web API reference then hit ok button, that’s it. Build & run the application for the first time.

Add SignalR

Get it on NuGet! Right click the project > Manage NuGet package > Browse to install.

ASP.NET

Browse package then install to application, it’ll automatically do the rest.

ASP.NET

OR Install using package manager console

Install-Package Microsoft.AspNet.SignalR.

ASP.NET

Creating Hub

Add a new Hub Class, name it NotificationHub.cs.

ASP.NET

  1. public class NotificationHub : Hub  
  2. {  
  3.     private static readonly ConcurrentDictionary<string, UserHubModels> Users =  
  4.         new ConcurrentDictionary<string, UserHubModels>(StringComparer.InvariantCultureIgnoreCase);  
  5.   
  6.   
  7.     public override Task OnConnected()  
  8.     {  
  9.         string userName = Context.User.Identity.Name;  
  10.         string connectionId = Context.ConnectionId;  
  11.   
  12.         var user = Users.GetOrAdd(userName, _ => new UserHubModels  
  13.         {  
  14.             UserName = userName,  
  15.             ConnectionIds = new HashSet<string>()  
  16.         });  
  17.   
  18.         lock (user.ConnectionIds)  
  19.         {  
  20.             user.ConnectionIds.Add(connectionId);  
  21.             if (user.ConnectionIds.Count == 1)  
  22.             {  
  23.                 Clients.Others.userConnected(userName);  
  24.             }  
  25.         }  
  26.   
  27.         return base.OnConnected();  
  28.     }  
  29.   
  30.     public override Task OnDisconnected(bool stopCalled)  
  31.     {  
  32.         string userName = Context.User.Identity.Name;  
  33.         string connectionId = Context.ConnectionId;  
  34.   
  35.         UserHubModels user;  
  36.         Users.TryGetValue(userName, out user);  
  37.   
  38.         if (user != null)  
  39.         {  
  40.             lock (user.ConnectionIds)  
  41.             {  
  42.                 user.ConnectionIds.RemoveWhere(cid => cid.Equals(connectionId));  
  43.                 if (!user.ConnectionIds.Any())  
  44.                 {  
  45.                     UserHubModels removedUser;  
  46.                     Users.TryRemove(userName, out removedUser);  
  47.                     Clients.Others.userDisconnected(userName);  
  48.                 }  
  49.             }  
  50.         }  
  51.   
  52.         return base.OnDisconnected(stopCalled);  
  53.     }  
  54. }  

Enable SignalR - Startup.cs
  1. using Microsoft.Owin;  
  2. using Owin;  
  3.   
  4. [assembly: OwinStartupAttribute(typeof(NotifSystem.Web.Startup))]  
  5. namespace NotifSystem.Web  
  6. {  
  7.     public partial class Startup  
  8.     {  
  9.         public void Configuration(IAppBuilder app)  
  10.         {  
  11.             app.MapSignalR();  
  12.         }  
  13.     }  
  14. }  

Layout page

  1. <script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script>  
  2. <script src="~/signalr/hubs"></script>  
  3. <script type="text/javascript">  
  4.     $(document).ready(function () {  
  5.         var hub = $.connection.notificationHub;  
  6.         $.connection.hub.start()  
  7.             .done(function () {  
  8.                 console.log("Hub Connected!");  
  9.   
  10.             })  
  11.             .fail(function () {  
  12.                 console.log("Could not Connect!");  
  13.             });  
  14.     });  
  15. </script>  

Test SignalR

Run the application go to url modify by /signalr/hubs. This will show the magic SignalR JavaScript Library with the current version like below screenshot.

ASP.NET

In Browser Console it’ll show message about Hub Connection.

ASP.NET

Database Modification

Create new database then modify connection string in web.config file. Restore database from attached script file in App_Data folder.

We need to create a table to store Notifications.

  1. CREATE TABLE [dbo].[Notification](  
  2.     [Id] [int] IDENTITY(1,1) NOT NULL,  
  3.     [Type] [intNULL,  
  4.     [Details] [nvarchar](500) NULL,  
  5.     [Title] [nvarchar](50) NULL,  
  6.     [DetailsURL] [nvarchar](500) NULL,  
  7.     [SentTo] [nvarchar](50) NULL,  
  8.     [Date] [dateNULL,  
  9.     [IsRead] [bitNULL,  
  10.     [IsDeleted] [bitNULL,  
  11.     [IsReminder] [bitNULL,  
  12.     [Code] [nvarchar](100) NULL,  
  13.     [NotificationType] [nvarchar](100) NULL,  
  14.  CONSTRAINT [PK_Notification] PRIMARY KEY CLUSTERED   
  15. (  
  16.     [Id] ASC  
  17. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]  
  18. ON [PRIMARY]  
  19. GO  

Send specific user Notification using SignalR

In this section we will work with view to send notification to specific user.

Index.cshtml

  1. <div class="col-md-12">  
  2.     <h2>Say Hello</h2>  
  3.     <div id="messages"></div>  
  4.     <hr />  
  5.   
  6.     <div class="form-group">  
  7.         <label for="email">User Email:</label>  
  8.         <input type="email" class="form-control" id="toUser" value="" placeholder="shashangka@gmail.com"/>  
  9.     </div>  
  10.     <div class="form-group">  
  11.         <label for="pwd">Message:</label>  
  12.         <input type="password" class="form-control" id="myMessage" value="" placeholder="message"/>  
  13.     </div>  
  14.   
  15.     <button type="submit" class="btn btn-default" id="submit">Submit</button>  
  16.   
  17. </div>  

Javascript

  1. <script type="text/javascript">  
  2. $("#submit").click(function (e) {  
  3.     e.preventDefault();  
  4.   
  5.     var message = $("#myMessage").val();  
  6.     var sendtouser = $("#toUser").val();  
  7.   
  8.     var Notification = { UserID: sendtouser, Message: message };  
  9.   
  10.     $.ajax({  
  11.         type: "POST",  
  12.         url: "/api/Values/SendNotification",  
  13.         data: JSON.stringify(Notification),  
  14.         contentType: 'application/json; charset=utf-8',  
  15.         success: function (data) {  
  16.             //reset field  
  17.             $("#myMessage").val("");  
  18.         },  
  19.         error: function () {  
  20.             alert("Error occured!!")  
  21.         }  
  22.     });  
  23.   
  24. });  
  25. </script>  

API

  1. public class ValuesController : ApiController  
  2. {  
  3.     private NotifEntities context = new NotifEntities();  
  4.   
  5.     [HttpPost]  
  6.     public HttpResponseMessage SendNotification(NotifModels obj)  
  7.     {  
  8.         NotificationHub objNotifHub = new NotificationHub();  
  9.         Notification objNotif = new Notification();  
  10.         objNotif.SentTo = obj.UserID;  
  11.   
  12.         context.Configuration.ProxyCreationEnabled = false;  
  13.         context.Notifications.Add(objNotif);  
  14.         context.SaveChanges();  
  15.   
  16.         objNotifHub.SendNotification(objNotif.SentTo);  
  17.   
  18.         //var query = (from t in context.Notifications  
  19.         //             select t).ToList();  
  20.   
  21.         return Request.CreateResponse(HttpStatusCode.OK);  
  22.     }  
  23. }  

Modify Hub

We need to add additional methods in our Hub class.

  1. private NotifEntities context = new NotifEntities();  
  2.   
  3. //Logged Use Call  
  4. public void GetNotification()  
  5. {  
  6.     try  
  7.     {  
  8.         string loggedUser = Context.User.Identity.Name;  
  9.   
  10.         //Get TotalNotification  
  11.         string totalNotif = LoadNotifData(loggedUser);  
  12.   
  13.         //Send To  
  14.         UserHubModels receiver;  
  15.         if (Users.TryGetValue(loggedUser, out receiver))  
  16.         {  
  17.             var cid = receiver.ConnectionIds.FirstOrDefault();  
  18.             var context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();  
  19.             context.Clients.Client(cid).broadcaastNotif(totalNotif);  
  20.         }  
  21.     }  
  22.     catch (Exception ex)  
  23.     {  
  24.         ex.ToString();  
  25.     }  
  26. }  
  27.   
  28. //Specific User Call  
  29. public void SendNotification(string SentTo)  
  30. {  
  31.     try  
  32.     {  
  33.         //Get TotalNotification  
  34.         string totalNotif = LoadNotifData(SentTo);  
  35.   
  36.         //Send To  
  37.         UserHubModels receiver;  
  38.         if (Users.TryGetValue(SentTo, out receiver))  
  39.         {  
  40.             var cid = receiver.ConnectionIds.FirstOrDefault();  
  41.             var context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();  
  42.             context.Clients.Client(cid).broadcaastNotif(totalNotif);  
  43.         }  
  44.     }  
  45.     catch (Exception ex)  
  46.     {  
  47.         ex.ToString();  
  48.     }  
  49. }  
  50.   
  51. private string LoadNotifData(string userId)  
  52. {  
  53.     int total = 0;  
  54.     var query = (from t in context.Notifications  
  55.                     where t.SentTo == userId  
  56.                     select t)  
  57.                 .ToList();  
  58.     total = query.Count;  
  59.     return total.ToString();  
  60. }  

Finally the Hub

  1. public class NotificationHub : Hub  
  2. {  
  3.     private static readonly ConcurrentDictionary<string, UserHubModels> Users =  
  4.         new ConcurrentDictionary<string, UserHubModels>(StringComparer.InvariantCultureIgnoreCase);  
  5.   
  6.     private NotifEntities context = new NotifEntities();  
  7.   
  8.     //Logged Use Call  
  9.     public void GetNotification()  
  10.     {  
  11.         try  
  12.         {  
  13.             string loggedUser = Context.User.Identity.Name;  
  14.   
  15.             //Get TotalNotification  
  16.             string totalNotif = LoadNotifData(loggedUser);  
  17.   
  18.             //Send To  
  19.             UserHubModels receiver;  
  20.             if (Users.TryGetValue(loggedUser, out receiver))  
  21.             {  
  22.                 var cid = receiver.ConnectionIds.FirstOrDefault();  
  23.                 var context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();  
  24.                 context.Clients.Client(cid).broadcaastNotif(totalNotif);  
  25.             }  
  26.         }  
  27.         catch (Exception ex)  
  28.         {  
  29.             ex.ToString();  
  30.         }  
  31.     }  
  32.   
  33.     //Specific User Call  
  34.     public void SendNotification(string SentTo)  
  35.     {  
  36.         try  
  37.         {  
  38.             //Get TotalNotification  
  39.             string totalNotif = LoadNotifData(SentTo);  
  40.   
  41.             //Send To  
  42.             UserHubModels receiver;  
  43.             if (Users.TryGetValue(SentTo, out receiver))  
  44.             {  
  45.                 var cid = receiver.ConnectionIds.FirstOrDefault();  
  46.                 var context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();  
  47.                 context.Clients.Client(cid).broadcaastNotif(totalNotif);  
  48.             }  
  49.         }  
  50.         catch (Exception ex)  
  51.         {  
  52.             ex.ToString();  
  53.         }  
  54.     }  
  55.   
  56.     private string LoadNotifData(string userId)  
  57.     {  
  58.         int total = 0;  
  59.         var query = (from t in context.Notifications  
  60.                         where t.SentTo == userId  
  61.                         select t)  
  62.                     .ToList();  
  63.         total = query.Count;  
  64.         return total.ToString();  
  65.     }  
  66.   
  67.     public override Task OnConnected()  
  68.     {  
  69.         string userName = Context.User.Identity.Name;  
  70.         string connectionId = Context.ConnectionId;  
  71.   
  72.         var user = Users.GetOrAdd(userName, _ => new UserHubModels  
  73.         {  
  74.             UserName = userName,  
  75.             ConnectionIds = new HashSet<string>()  
  76.         });  
  77.   
  78.         lock (user.ConnectionIds)  
  79.         {  
  80.             user.ConnectionIds.Add(connectionId);  
  81.             if (user.ConnectionIds.Count == 1)  
  82.             {  
  83.                 Clients.Others.userConnected(userName);  
  84.             }  
  85.         }  
  86.   
  87.         return base.OnConnected();  
  88.     }  
  89.   
  90.     public override Task OnDisconnected(bool stopCalled)  
  91.     {  
  92.         string userName = Context.User.Identity.Name;  
  93.         string connectionId = Context.ConnectionId;  
  94.   
  95.         UserHubModels user;  
  96.         Users.TryGetValue(userName, out user);  
  97.   
  98.         if (user != null)  
  99.         {  
  100.             lock (user.ConnectionIds)  
  101.             {  
  102.                 user.ConnectionIds.RemoveWhere(cid => cid.Equals(connectionId));  
  103.                 if (!user.ConnectionIds.Any())  
  104.                 {  
  105.                     UserHubModels removedUser;  
  106.                     Users.TryRemove(userName, out removedUser);  
  107.                     Clients.Others.userDisconnected(userName);  
  108.                 }  
  109.             }  
  110.         }  
  111.   
  112.         return base.OnDisconnected(stopCalled);  
  113.     }  
  114. }  

Output

ASP.NET

Hope this will help.

X

Build smarter apps with Machine Learning, Bots, Cognitive Services - Start free.

Start Learning Now