Push notification with SignalR across session state

Using SignalR is pretty simple for implemeting push notification service. One thing to keep in mind is: SignalR connections (including the connection underlying all Hub operations for a client) do not support Session state. So it's not possible to access session data from signalr hub.

Now let's assume one scenario, where we need to perform a database operation on postback (e.g. post action in an mvc controller) based on a user action and after that we need to redirect to a listing/default page. But we want to let user know if the operation succeeded or not.

Here is a Hub implemented to send client notification:
public class NotificationHub : Hub
{
private readonly INotifier _notificationService;
public NotificationHub(INotifier notificationService)
{
_notificationService = notificationService;
}
public void Notify()
{
_notificationService.ShowNotification();
}
}

Here is how it is initialized:
[assembly: OwinStartup(typeof(Client.Notification.HubInitializer))]
namespace Client.Notification
{
public class HubInitializer
{
public void Configuration(IAppBuilder app)
{
GlobalHost.DependencyResolver.Register(
typeof(NotificationHub),
() => new NotificationHub(new ClientNotification()));
app.MapSignalR();
}
}
}
And here is the client side script:
var notificationHub = $.connection.notificationHub;
notificationHub.client.showNotification = function (message, status) {
$(".notification").removeClass("alert-danger").addClass("alert-info");
if (status && status == "Failure") {
$(".notification").removeClass("alert-info").addClass("alert-danger");
}
$(".notification").html(message);
$(".notification").fadeIn('slow').delay(2000).fadeOut("slow");
};
$.connection.hub.start();
view raw notification.js hosted with ❤ by GitHub
The final thing is to invoke the client side  showNotification() function when the redirected view page is loaded.

But problem is: the calling page and the redirected page are two different views and the session state is changed in the meantime. After redirection client hub in the calling page is closed and we must init the hub again before we can send notification. So, even if we re-open the hub on page load we must know few notification data (e.g. message) that should actually come from previous page.

Since signalr doesn't allow session data, these piece of data must persist somewhere else while the state change is taking place. 

Here is how it is done using static variable:
public class ClientNotification : INotifier
{
private static PushNotification _notification;
public void SendMessage(string message, NotificationStatus status)
{
GlobalHost
.ConnectionManager
.GetHubContext<NotificationHub>().Clients.All.showNotification(message, status.ToString());
}
public void PushNotification(string message, NotificationStatus status)
{
var notification = new PushNotification() { Message = message, Status = status};
_notification = notification;
}
public void ShowNotification()
{
if (_notification != null)
{
SendMessage(_notification.Message, _notification.Status);
_notification = null;
}
}
}

So remaining is to push the notification on completion of database operation and then show the push notification on page load.

Pushing notification to hub:
[HttpPost]
public ActionResult Save(Employee employee)
{
string successMessage = "Employee information updated successfully.";
_employeeService.Update(employee);
_notificationService.PushNotification(successMessage, NotificationStatus.Success);
return RedirectToAction("Index", "Home");
}
Displaying push notification:
var notificationHub = $.connection.notificationHub;
$.connection.hub.start().done(function () {
notificationHub.server.notify();
});
view raw global.js hosted with ❤ by GitHub
That's all! Now the push notification will be displyed when redirected page is loaded.

Comments

Popular posts from this blog

Adding security headers to prevent XSS and MiTM attacks in .Net Core

Microsoft.IdentityModel.Protocols.OpenIdConnectProtocolInvalidNonceException

Executing synchronous methods asynchronously