Introduction
SignalR is a library for ASP.NET developers that simplifies the process of adding real-time web functionality to applications. Real-time web functionality is the ability to make server code push the content to connected clients instantly as it becomes available, rather than having the server wait for a client to request the new data.
To Know more about SignalR, you can visit my blogs and articles.
Description
SignalR can be used to add any sort of "real-time" web functionality to your MVC application. While Chat is often used as an example, you can do a whole lot more; examples include dashboards and monitoring applications, collaborative applications such as simultaneous editing of documents, job progress updates, and real-time forms. We must have a way to notify all the connected clients if there are any changes on the server, without a refresh or update the web page. This is the scenario in which ASP.NET SignalR comes handy.
Here, I have created two Views - for home and for Notification entry details. After that, the notifiation message will come with counting the no. of notifications arrived.
Link to download my project
Steps to be followed
Step 1
Create one MVC application named "SignalRDemo".
Step 2
Create a table named "tblEmployee". Paste the following code in that.
- SET ANSI_NULLS ON
- GO
-
- SET QUOTED_IDENTIFIER ON
- GO
-
- SET ANSI_PADDING ON
- GO
-
- CREATE TABLE [dbo].[tblEmployee](
- [ID] [int] IDENTITY(1,1) NOT NULL,
- [Name] [varchar](50) NULL,
- [AddedOn] [datetime] NULL,
- 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
-
- SET ANSI_PADDING OFF
- GO
Step 3
Enable Service Broker on the database.
- ALTER DATABASE Your_DB_Name SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE ;
Enable Service Broker on the database
Service Broker is a feature introduced for the first time in SQL Server 2005. By using this feature, external or internal processes can send and receive asynchronous messages reliably by using extensions of Transact-SQL Data Manipulation Language (DML). It is a queued and reliable messaging mechanism used for asynchronous programming model.We need this feature to be enabled since, whenever a change in the table will happen such as Insert/Update/Delete/Truncate, then the SQLDependency should be able to identify that.
It (Service Broker) rather implements a Broker Architecture which publishes the events while the SQL Dependency acts as a subscriber and detects the changes. Using the SqlDependency object, the application can create and register to receive notifications via the OnChangeEventHandler event handler.
How To Check Service Broker on the database Is Enabled Or Not?
- SELECT NAME, IS_BROKER_ENABLED FROM SYS.DATABASES
- WHERE NAME='Your_db_name'
Here I ennabled so IS_BROKER_ENABLED column shows "1" , else will show "0".
Step4
Add Ado.Net Entity Data Model named "SignalRDataModel.edmx".
Go to Solution Explorer (Visual studio) > Right Click on Project name form Solution Explorer > Add > New item > Select ADO.net Entity Data Model under data > Enter model name > Add.
A popup window will come (Entity Data Model Wizard) > Select Generate from database > Next > Chose your data connection > select your database > next > Select tables > enter Model Namespace > Finish.
Step5
Install SignalR NuGet Package.
Solution Explorer > Right Click on References > Manage NuGetPackages > Search for "SignalR"> Install > Close.
Or you can also install from package manager console.
Go to Tools (top menu) > Library Package Manager > Open "Package Manager Console" and Type below command .
- PM> Install-Package Microsoft.AspNet.SignalR
Step6
Add an Owin startup file.
Add an Owin startup class in your application for enabling the SignalR in our application. Add a new class in the project named "Startup.cs"
Code Ref
- using Microsoft.Owin;
- using Owin;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- [assembly: OwinStartup(typeof(SignalRDemo.Startup))]
-
- namespace SignalRDemo
- {
- public class Startup
- {
- public void Configuration(IAppBuilder app)
- {
- app.MapSignalR();
- }
- }
- }
Step7
Add a SignalR hub class.
Now, you need to create a SignalR Hub class, this makes possible to invoke the client side JavaScript method from the server side. In this application, we will use this for showing notification.SignalR uses ‘Hub’ objects to communicate between the client and the server.
Add a new class named "NotificationHub.cs".
Code Ref
- using Microsoft.AspNet.SignalR;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
-
- namespace SignalRDemo
- {
- public class NotificationHub : Hub
- {
-
-
-
-
-
- }
- }
The NotificationHub.cs class is empty. I will use the class later from another place.
Step8
Add connection string into the web.config file.
Open the application root Web.config file and find the element. Add the following connection string to the element in the Web.config file.
Code Ref
- <add name="sqlConString" connectionString="Your_Connection_String" />
Step9
Add another class file named "NotificationComponent.cs" for register notification for data changes in the database In this class, you need to create a SQL dependency which allows your application to be notified when a data has changed in the database (Microsoft SQL Server).
Write the following in this class...
- RegisterNotification- void method for register notification
- SqlDependency_OnChange- SqlDependency onchnage event, get fired when assigned SQL command produced a different
- GetContacts- This is a method for return the changes happened on the server, here our new inserted contact data
Code Ref
- using Microsoft.AspNet.SignalR;
- using System;
- using System.Collections.Generic;
- using System.Configuration;
- using System.Data.SqlClient;
- using System.Linq;
- using System.Web;
-
- namespace SignalRDemo
- {
- public class NotificationComponent
- {
-
- public void RegisterNotification(DateTime currentTime)
- {
- string conStr = ConfigurationManager.ConnectionStrings["sqlConString"].ConnectionString;
- string sqlCommand = @"SELECT [ID],[Name] from [dbo].[tblEmployee] where [AddedOn] > @AddedOn";
-
- using (SqlConnection con = new SqlConnection(conStr))
- {
- SqlCommand cmd = new SqlCommand(sqlCommand, con);
- cmd.Parameters.AddWithValue("@AddedOn", currentTime);
- if (con.State != System.Data.ConnectionState.Open)
- {
- con.Open();
- }
- cmd.Notification = null;
- SqlDependency sqlDep = new SqlDependency(cmd);
- sqlDep.OnChange += sqlDep_OnChange;
-
- using (SqlDataReader reader = cmd.ExecuteReader())
- {
-
- }
- }
- }
-
- void sqlDep_OnChange(object sender, SqlNotificationEventArgs e)
- {
-
- if (e.Type == SqlNotificationType.Change)
- {
- SqlDependency sqlDep = sender as SqlDependency;
- sqlDep.OnChange -= sqlDep_OnChange;
-
-
- var notificationHub = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
- notificationHub.Clients.All.notify("added");
-
- RegisterNotification(DateTime.Now);
- }
- }
-
- public List<tblEmployee> GetData(DateTime afterDate)
- {
- using (SignalRDBEntities dc = new SignalRDBEntities())
- {
- return dc.tblEmployees.Where(a => a.AddedOn > afterDate).OrderByDescending(a => a.AddedOn).ToList();
- }
- }
- }
- }
Code Description
The details code is explained using comment lines.
Step10
Add a new Controller named "HomeController.cs". Here I have added "Index" Action into "Home" Controller.
Code Ref
- public ActionResult Index()
- {
- return View();
- }
Step11
Then create one view for home controller.
Code Ref
- @{
- ViewBag.Title = "Home";
- }
-
- <h2>Index</h2>
-
-
- <a target="_blank" href="Add/">Go To Notification page>></a>
Code Description
This View is only for home page.
Step12
Add another action in HomeController to fetch Employee data.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
-
- namespace SignalRDemo.Controllers
- {
- public class HomeController : Controller
- {
-
-
- public ActionResult Index()
- {
- return View();
- }
-
- public JsonResult GetNotifications()
- {
- var notificationRegisterTime = Session["LastUpdated"] != null ? Convert.ToDateTime(Session["LastUpdated"]) : DateTime.Now;
- NotificationComponent NC = new NotificationComponent();
- var list = NC.GetData(notificationRegisterTime);
-
-
- Session["LastUpdate"] = DateTime.Now;
- return new JsonResult { Data = list, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
- }
-
- }
- }
Code Description
The details code is explained using comment lines.
Step13
Add and update _Layout.cshtml for showing notification.
Code Ref
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>@ViewBag.Title - Satyaprakash Jquery and SignalR Intro</title>
- <link href="~/Content/bootstrap.css" rel="stylesheet" />
- <script src="~/Scripts/modernizr-2.6.2.js"></script>
- </head>
- <body>
- <div class="navbar navbar-inverse navbar-fixed-top">
- <div class="container">
- <div class="navbar-header">
-
- <span class="noti glyphicon glyphicon-globe"><span class="count"> </span></span>
- <div class="noti-content">
- <div class="noti-top-arrow"></div>
- <ul id="notiContent"></ul>
- </div>
- @Html.ActionLink("Satyaprakash Jquery and SignalR", "Index", "Home", null, new { @class = "navbar-brand" })
- </div>
- </div>
- </div>
- <div class="container body-content">
- @RenderBody()
- <hr />
- </div>
- @* Add Jquery Library *@
- <script src="~/Scripts/jquery-2.2.3.min.js"></script>
- <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
- <script src="/signalr/hubs"></script>
- <script src="~/Scripts/bootstrap.min.js"></script>
- @* Add css *@
- <link href="~/Content/bootstrap.css" rel="stylesheet" />
-
- <style type="text/css">
-
-
- .noti-content{
- position:fixed;
- right:100px;
- background:yellow;
- color:blue;
- font-size:medium;
- font-style:oblique;
- font-family:Arial;
- border-radius:4px;
- top:47px;
- width:440px;
- display:none;
- border: 1px solid #9E988B;
- }
- ul#notiContent{
- max-height:200px;
- overflow:auto;
- padding:0px;
- margin:0px;
- padding-left:20px;
- }
- ul#notiContent li {
- margin: 3px;
- padding: 6px;
- background: #FF6600;
- }
- .noti-top-arrow{
- border-color:transparent;
- border-bottom-color:#F5DEB3;
- border-style:dashed dashed solid;
- border-width: 0 8.5px 8.5px;
- position:absolute;
- right:32px;
- top:-8px;
- }
- span.noti {
- color:lightgreen;
- margin: 15px;
- position: fixed;
- right: 100px;
- font-size: 30px;
- cursor: pointer;
- }
- span.count {
- position:fixed;
- top: -1px;
-
- }
-
-
-
- </style>
-
- @* Add jquery code for Get Notification & setup signalr *@
- <script type="text/javascript">
- $(function () {
-
- $('span.noti').click(function (e) {
- debugger;
- e.stopPropagation();
- $('span.noti').css("color", "lightgreen");
- $('span.count').hide();
- $('.noti-content').show();
- var count = 0;
- count = parseInt($('span.count').html()) || 0;
- count++;
-
- if (count > 0) {
- updateNotification();
- }
- $('span.count', this).html(' ');
- })
-
- $('html').click(function () {
- $('.noti-content').hide();
- })
-
- function updateNotification() {
- $('#notiContent').empty();
- $('#notiContent').append($('<li>Loading...</li>'));
- $.ajax({
- type: 'GET',
- url: '/home/GetNotifications',
- success: function (response) {
- debugger;
- $('#notiContent').empty();
- if (response.length == 0) {
- $('#notiContent').append($('<li>Currently You Have No New Notifications.</li>'));
- }
- $.each(response, function (index, value) {
- $('#notiContent').append($('<li>The User , ' + value.Name+' ' +'Of ID' + ' (' + value.ID + ') Is Written
-
- Something.</li>'));
- });
- },
- error: function (error) {
- console.log(error);
- }
- })
- }
-
- function updateNotificationCount() {
- $('span.count').show();
- var count = 0;
- count = parseInt($('span.count').html()) || 0;
- count++;
- $('span.noti').css("color", "white");
- $('span.count').css({ "background-color": "red", "color": "white" });
- $('span.count').html(count);
-
- }
-
- var notificationHub = $.connection.notificationHub;
- $.connection.hub.start().done(function () {
- console.log('Notification hub started');
- });
-
- notificationHub.client.notify = function (message) {
- if (message && message.toLowerCase() == "added") {
- updateNotificationCount();
- }
- }
- })
- </script>
-
- </body>
- </html>
Code Description
The details code is explained using comment lines.
Step14
Update global.asax.cs to start, stop SQL dependency
Code Ref
- using System;
- using System.Collections.Generic;
- using System.Configuration;
- using System.Data.SqlClient;
- using System.Linq;
- using System.Web;
- using System.Web.Http;
- using System.Web.Mvc;
- using System.Web.Routing;
-
- namespace SignalRDemo
- {
-
-
- public class MvcApplication : System.Web.HttpApplication
- {
- string con = ConfigurationManager.ConnectionStrings["sqlConString"].ConnectionString;
- protected void Application_Start()
- {
- AreaRegistration.RegisterAllAreas();
-
-
-
- RouteConfig.RegisterRoutes(RouteTable.Routes);
-
- SqlDependency.Start(con);
- }
-
- protected void Session_Start(object sender, EventArgs e)
- {
- NotificationComponent NC = new NotificationComponent();
- var currentTime = DateTime.Now;
- HttpContext.Current.Session["LastUpdated"] = currentTime;
- NC.RegisterNotification(currentTime);
- }
-
-
- protected void Application_End()
- {
-
- SqlDependency.Stop(con);
- }
- }
- }
Code Description
The details code is explained using comment lines.
Step15
Now add a new Controller/Action To add Notification Data.
- I have created AddController.cs in Controller directory.
- Add action named "Index"
Code Ref:
- public ActionResult Index()
- {
- return View();
- }
Step16
Create View for Index action to add Employee Notification Details.
Code Ref
- @model SignalRDemo.tblEmployee
-
- @{
- ViewBag.Title = "Add Notification";
- }
-
- <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
-
- <link href="~/App_Content/CSS/bootstrap.min.css" rel="stylesheet" />
- <link href="~/App_Content/CSS/font-awesome.min.css" rel="stylesheet" />
-
- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js">
-
- </script>
-
- <style>
- .button {
- background-color: #4CAF50;
- border: none;
- color: white;
- padding: 15px 32px;
- text-align: center;
- text-decoration: none;
- display: inline-block;
- font-size: 16px;
- margin: 4px 2px;
- cursor: pointer;
- }
-
- .button4 {
- border-radius: 9px;
- }
- .control{
- width:459px;
- height:145px;
- }
- </style>
-
- <h2>Notification</h2>
-
- @using (Html.BeginForm(FormMethod.Post))
- {
- @Html.ValidationSummary(true)
-
- <fieldset>
- <legend>Notification</legend>
-
- <div class="editor-label">
- @Html.LabelFor(model => model.Name)
- </div>
- <div class="editor-field">
- @Html.TextAreaFor(model => model.Name, new { id = "ValidateNametextbox", @class = "form-control" })
- @Html.ValidationMessageFor(model => model.Name)
- </div>
-
-
- <p>
- <input id="SubmitProject" class="button button4" type="submit" value="Notify" onclick="saveToFile()" />
- </p>
- </fieldset>
- }
- <script type="text/javascript">
- function saveToFile() {
- if ($("#ValidateNametextbox").val() == "") {
- alert("Comment Section should not be empty!!");
- }
- else {
- alert("Go To Home Page of Client Browser.");
- }
- };
- </script>
Code Description
Here I have added some mvc controls like textarea and button.
- @using (Html.BeginForm(FormMethod.Post))
- {
- @Html.ValidationSummary(true)
-
- <fieldset>
- <legend>Notification</legend>
-
- <div class="editor-label">
- @Html.LabelFor(model => model.Name)
- </div>
- <div class="editor-field">
- @Html.TextAreaFor(model => model.Name, new { id = "ValidateNametextbox", @class = "form-control" })
- @Html.ValidationMessageFor(model => model.Name)
- </div>
-
-
- <p>
- <input id="SubmitProject" class="button button4" type="submit" value="Notify" onclick="saveToFile()" />
- </p>
- </fieldset>
- }
Step17
Add Post action for Index and add code to insert Employee.
Code Ref
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
-
- namespace SignalRDemo.Controllers
- {
- public class AddController : Controller
- {
-
-
-
- public ActionResult Index()
- {
- return View();
- }
-
- [HttpPost]
- public ActionResult Index(tblEmployee model)
- {
- SignalRDBEntities entity = new SignalRDBEntities();
- model.AddedOn = DateTime.Now;
- entity.tblEmployees.Add(model);
- entity.SaveChanges();
- return View();
- }
-
- }
- }
Code Description
Here I have added entityname "SignalRDBEntities" and using autogenerated class tblEmployee object model we added data on datetime when you insert data and for entity class object we inserted data on remaining table columns.
- SignalRDBEntities entity = new SignalRDBEntities();
The below two line has the main role to insert records.
- entity.tblEmployees.Add(model);
- entity.SaveChanges();
Step18
Here I configured my text area heading with "Add Comments." So, we should do an auto-generated class "tblEmployee.cs".
Code Ref
-
-
-
-
-
-
-
-
-
- namespace SignalRDemo
- {
- using System;
- using System.Collections.Generic;
- using System.ComponentModel.DataAnnotations;
-
- public partial class tblEmployee
- {
- public int ID { get; set; }
- [Display(Name = "Add Comments")]
- public string Name { get; set; }
- public Nullable<System.DateTime> AddedOn { get; set; }
- }
- }
Code Description
I added Display attribute to configure. So, you should add the namespace.
- using System.ComponentModel.DataAnnotations;
-
- [Display(Name = "Add Comments")]
- public string Name { get; set; }
Note
Sometimes due to more temporary and cache files the count will be a bit off. So, You should clean the solution and clean the project then Run....
OUTPUT
Home Page,
Then Notification insert page,
Add some notification text In Notification insert page
Then, it will show u a popup to go to home page to see the notification count as well as notification text.
You can see when there is no new notifiation, then the notification color is light green but when any new notification comes, the notification color is changed to white. Then, after clicking on the notification, the details will be shown and notification color is changed to light green.
You can see some features are the same as Facebook Notification.
You can insert the data via one browser and get the updated notification on the homepage in the other browser also. The result will be shown in the same instance and different instance of same browser or different browser.
You can check the data inserted in the table.
In GIF -