In this post we are going to explore how to implement user based notification using ASP.Net MVC & SignalR.
In case if you are new to SignalR the please get some basics here:
Why SignalR?
SignalR provides “real-time” web functionality in our application using Javascript function call in client browser from server (Server Sent Events). It has several connection management like
- connect/disconnect/reconnect events,
- grouping connections,
- authorization etc
Go to http://signalr.net for more.
We will focus on:
- Creating a new ASP.Net MVC Web Application
- Add SignalR
- Creating Hub
- Enable SignalR
- Database Modification
- Send specific user Notification using SignalR
Create ASP.Net MVC Web Application:
Open Visual Studio goto > File >New Project Choose ASP.Net MVC application
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 first time.
Add SignalR:
Get it on NuGet! Right click the project > Manage NuGet package > Browse to install
Browse package then install to application, it’ll automatically done the rest.
OR Install using package manager console
Install-Package Microsoft.AspNet.SignalR
Creating Hub:
Add New Hub Class, Name it NotificationHub.cs
public class NotificationHub : Hub { private static readonly ConcurrentDictionaryUsers = new ConcurrentDictionary (StringComparer.InvariantCultureIgnoreCase); public override Task OnConnected() { string userName = Context.User.Identity.Name; string connectionId = Context.ConnectionId; var user = Users.GetOrAdd(userName, _ => new UserHubModels { UserName = userName, ConnectionIds = new HashSet () }); lock (user.ConnectionIds) { user.ConnectionIds.Add(connectionId); if (user.ConnectionIds.Count == 1) { Clients.Others.userConnected(userName); } } return base.OnConnected(); } public override Task OnDisconnected(bool stopCalled) { string userName = Context.User.Identity.Name; string connectionId = Context.ConnectionId; UserHubModels user; Users.TryGetValue(userName, out user); if (user != null) { lock (user.ConnectionIds) { user.ConnectionIds.RemoveWhere(cid => cid.Equals(connectionId)); if (!user.ConnectionIds.Any()) { UserHubModels removedUser; Users.TryRemove(userName, out removedUser); Clients.Others.userDisconnected(userName); } } } return base.OnDisconnected(stopCalled); } }
Enable SignalR:
Startup.cs
using Microsoft.Owin; using Owin; [assembly: OwinStartupAttribute(typeof(NotifSystem.Web.Startup))] namespace NotifSystem.Web { public partial class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } }
Layout page
Test SignalR
Run the application go to url modify by /signalr/hubs. This will show the magic SignalR JavaScript Library with current version like below screenshot.
In Browser Console it’ll show message about Hub Connection.
Database Modification:
Create new database then modify connection string in web.config file. Restore database from attached script file in App_Folder. We need to create a table to store Notifications.
CREATE TABLE [dbo].[Notification]( [Id] [int] IDENTITY(1,1) NOT NULL, [Type] [int] NULL, [Details] [nvarchar](500) NULL, [Title] [nvarchar](50) NULL, [DetailsURL] [nvarchar](500) NULL, [SentTo] [nvarchar](50) NULL, [Date] [date] NULL, [IsRead] [bit] NULL, [IsDeleted] [bit] NULL, [IsReminder] [bit] NULL, [Code] [nvarchar](100) NULL, [NotificationType] [nvarchar](100) NULL, CONSTRAINT [PK_Notification] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
Send specific user Notification using SignalR:
In this section we will work with view to send notification to specific user.
Index.cshtml:
Say Hello
Javascript:
API:
public class ValuesController : ApiController { private NotifEntities context = new NotifEntities(); [HttpPost] public HttpResponseMessage SendNotification(NotifModels obj) { NotificationHub objNotifHub = new NotificationHub(); Notification objNotif = new Notification(); objNotif.SentTo = obj.UserID; context.Configuration.ProxyCreationEnabled = false; context.Notifications.Add(objNotif); context.SaveChanges(); objNotifHub.SendNotification(objNotif.SentTo); return Request.CreateResponse(HttpStatusCode.OK); } }
Modify Hub: We need to add additional methods in our Hub class.
private NotifEntities context = new NotifEntities(); //Logged Use Call public void GetNotification() { try { string loggedUser = Context.User.Identity.Name; //Get TotalNotification string totalNotif = LoadNotifData(loggedUser); //Send To UserHubModels receiver; if (Users.TryGetValue(loggedUser, out receiver)) { var cid = receiver.ConnectionIds.FirstOrDefault(); var context = GlobalHost.ConnectionManager.GetHubContext(); context.Clients.Client(cid).broadcaastNotif(totalNotif); } } catch (Exception ex) { ex.ToString(); } } //Specific User Call public void SendNotification(string SentTo) { try { //Get TotalNotification string totalNotif = LoadNotifData(SentTo); //Send To UserHubModels receiver; if (Users.TryGetValue(SentTo, out receiver)) { var cid = receiver.ConnectionIds.FirstOrDefault(); var context = GlobalHost.ConnectionManager.GetHubContext (); context.Clients.Client(cid).broadcaastNotif(totalNotif); } } catch (Exception ex) { ex.ToString(); } } private string LoadNotifData(string userId) { int total = 0; var query = (from t in context.Notifications where t.SentTo == userId select t) .ToList(); total = query.Count; return total.ToString(); }
Finally the Hub:
public class NotificationHub : Hub { private static readonly ConcurrentDictionaryUsers = new ConcurrentDictionary (StringComparer.InvariantCultureIgnoreCase); private NotifEntities context = new NotifEntities(); //Logged Use Call public void GetNotification() { try { string loggedUser = Context.User.Identity.Name; //Get TotalNotification string totalNotif = LoadNotifData(loggedUser); //Send To UserHubModels receiver; if (Users.TryGetValue(loggedUser, out receiver)) { var cid = receiver.ConnectionIds.FirstOrDefault(); var context = GlobalHost.ConnectionManager.GetHubContext (); context.Clients.Client(cid).broadcaastNotif(totalNotif); } } catch (Exception ex) { ex.ToString(); } } //Specific User Call public void SendNotification(string SentTo) { try { //Get TotalNotification string totalNotif = LoadNotifData(SentTo); //Send To UserHubModels receiver; if (Users.TryGetValue(SentTo, out receiver)) { var cid = receiver.ConnectionIds.FirstOrDefault(); var context = GlobalHost.ConnectionManager.GetHubContext (); context.Clients.Client(cid).broadcaastNotif(totalNotif); } } catch (Exception ex) { ex.ToString(); } } private string LoadNotifData(string userId) { int total = 0; var query = (from t in context.Notifications where t.SentTo == userId select t) .ToList(); total = query.Count; return total.ToString(); } public override Task OnConnected() { string userName = Context.User.Identity.Name; string connectionId = Context.ConnectionId; var user = Users.GetOrAdd(userName, _ => new UserHubModels { UserName = userName, ConnectionIds = new HashSet () }); lock (user.ConnectionIds) { user.ConnectionIds.Add(connectionId); if (user.ConnectionIds.Count == 1) { Clients.Others.userConnected(userName); } } return base.OnConnected(); } public override Task OnDisconnected(bool stopCalled) { string userName = Context.User.Identity.Name; string connectionId = Context.ConnectionId; UserHubModels user; Users.TryGetValue(userName, out user); if (user != null) { lock (user.ConnectionIds) { user.ConnectionIds.RemoveWhere(cid => cid.Equals(connectionId)); if (!user.ConnectionIds.Any()) { UserHubModels removedUser; Users.TryRemove(userName, out removedUser); Clients.Others.userDisconnected(userName); } } } return base.OnDisconnected(stopCalled); } }
Broadcast to Client
//Hub Method to Broadcast Notification to Specific User context.Clients.Client(cid).broadcaastNotif(totalNotif); //Server Sent Event hub.client.broadcaastNotif = function (totalNotif) { setTotalNotification(totalNotif) };
Call to Server
//Client Call to Server hub.server.getNotification(); //Hub Method public void GetNotification() { }
Finally Client Script:
Output:
Source Code: I’ve uploaded the full source code to download/clone , Hope this will help 🙂
MD. Ahsan Habib says:
Nice post!
Shashangka Shekhar says:
Thanks
Eduardo Rosales says:
muchas gracias excelente post, me encanto y era lo que necesitaba
Shashangka Shekhar says:
Thanks
teresko says:
terreno
Ghost says:
What is the UserHubModels shoud i generate that in vs
says:
hello shashangka bro i’m trying to implement signalr in asp.net web application but getting issue for specific user
please suggest me how to send message to specific user
Shashangka Shekhar says:
Share me what you prepared.
Connect Skype: shashangka
Svein says:
Where is UserHubModels defined?
assakr says:
Did you know where UserHubModels defined?
ahmed mehany says:
hello there can you explain to me how to send notification to all user’s
or group of user
Mehmet says:
I will use multilayered architecture model layer. Model Layer (models and controlers),Api layer(webapi) and Ui layer(Html5-Ajax) so I want to get notification if there are any changes in the tables
Pramod Kumar says:
Hi Shashangka,
Could you help us for memory management and performance issue using Signal R .
salaheddin says:
thanks for our efforts even it is not works
Shashangka Shekhar says:
Please follow instructions carefully. Why should i post that not worked! Thanks.