Introduction
SignalR is a library for ASP.NET developers to simplify the process of adding real-time web functionality to applications. Real-time web functionality is the ability to have server code push content to connected clients instantly as it becomes available, rather than having the server wait for a client to request new data.
SignalR includes API for connection management (for instance, connect and disconnect events), and grouping connections. SignalR also provides a simple API for creating server-to-client remote procedure calls (RPC) that call JavaScript functions in the client browsers (and other client platforms) from server-side .NET code.
Create Database and Table in SQL Server
We will create an Employee application with all CRUD actions. We can create a new “Employees” table in the SQL database. If you don’t have an existing database, please create that also.
- CREATE TABLE [dbo].[Employees](
- [Id] [int] IDENTITY(1,1) NOT NULL,
- [Name] [nvarchar](50) NULL,
- [Company] [nvarchar](50) NULL,
- [Designation] [nvarchar](50) NULL,
- CONSTRAINT [PK_dbo.Employees] PRIMARY KEY CLUSTERED
- (
- [Id] ASC
- )
- )
Create MVC application in Visual Studio 2017
Since we are creating an Employee app, we can add an “Employee” class inside the “Models” folder.
- namespace MVCRealtimeSignalR.Models
- {
- public class Employee
- {
- public int Id { get; set; }
- public string Name { get; set; }
- public string Company { get; set; }
- public string Designation { get; set; }
- }
- }
We can build the application and add a new Employees controller class using scaffolding template. Right-click on Controllers folder and add new scaffolded item.



Click the “Add” button to create a new Employees controller.

- <?xml version="1.0" encoding="utf-8"?>
- <!--
- For more information on how to configure your ASP.NET application, please visit
- https://go.microsoft.com/fwlink/?LinkId=301880
- -->
- <configuration>
- <configSections>
- <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
- <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
- </configSections>
- <connectionStrings>
- <add name="SignalRDbContext" connectionString="Data Source=MURUGAN\SQL2017ML; Initial Catalog=SignalRDb; Integrated Security=True; MultipleActiveResultSets=True;" providerName="System.Data.SqlClient" />
- </connectionStrings>
- <appSettings>
- <add key="webpages:Version" value="3.0.0.0" />
- <add key="webpages:Enabled" value="false" />
- <add key="ClientValidationEnabled" value="true" />
- <add key="UnobtrusiveJavaScriptEnabled" value="true" />
- </appSettings>
- <system.web>
- <compilation debug="true" targetFramework="4.5" />
- <httpRuntime targetFramework="4.5" />
- </system.web>
- <runtime>
- <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
- <dependentAssembly>
- <assemblyIdentity name="Antlr3.Runtime" publicKeyToken="eb42632606e9261f" />
- <bindingRedirect oldVersion="0.0.0.0-3.5.0.2" newVersion="3.5.0.2" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" />
- <bindingRedirect oldVersion="0.0.0.0-4.0.2.1" newVersion="4.0.2.1" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" />
- <bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
- </dependentAssembly>
- <dependentAssembly>
- <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
- <bindingRedirect oldVersion="1.0.0.0-5.2.4.0" newVersion="5.2.4.0" />
- </dependentAssembly>
- </assemblyBinding>
- </runtime>
- <system.webServer>
- <modules>
- <remove name="TelemetryCorrelationHttpModule" />
- <add name="TelemetryCorrelationHttpModule" type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation" preCondition="integratedMode,managedHandler" />
- </modules>
- </system.webServer>
- <system.codedom>
- <compilers>
- <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
- <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+" />
- </compilers>
- </system.codedom>
- <entityFramework>
- <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
- <parameters>
- <parameter value="mssqllocaldb" />
- </parameters>
- </defaultConnectionFactory>
- <providers>
- <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
- </providers>
- </entityFramework>
- </configuration>
Now, modify the “_Layout.cshtml” partial view under “Shared” folder with the below changes.

- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>@ViewBag.Title - MVC SignalR Application</title>
- @Styles.Render("~/Content/css")
- @Scripts.Render("~/bundles/modernizr")
- </head>
- <body>
- <div class="navbar navbar-inverse navbar-fixed-top">
- <div class="container">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- @Html.ActionLink("MVC SignalR App", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
- </div>
- <div class="navbar-collapse collapse">
- <ul class="nav navbar-nav">
- <li>@Html.ActionLink("Home", "Index", "Home")</li>
- <li>@Html.ActionLink("Employees", "Index", "Employees")</li>
- <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
- </ul>
- </div>
- </div>
- </div>
- <div class="container body-content">
- @RenderBody()
- <hr />
- <footer>
- @{
- var WebBrowserName = HttpContext.Current.Request.Browser.Browser;
- <p>© @DateTime.Now.Year - MVC SignalR Application</p>
- <p style="color:blue; background-color:yellow; font-size:18px;">(Browser :@WebBrowserName)</p>
- }
- </footer>
- </div>
- @Scripts.Render("~/bundles/jquery")
- @Scripts.Render("~/bundles/bootstrap")
- @RenderSection("scripts", required: false)
- @RenderSection("JavaScript", required: false)
- </body>
- </html>
We have added an action link to the Index action in Employees controller. We have also added a RenderSection for JavaScript with required as false.
You can click the “Employees” menu and add/edit/delete employee records.


Owin middleware is used for establishing a persistent connection between server and client.

We can create a “Hubs” folder and create an “EmployeesHub” class inside this folder.
- using Microsoft.AspNet.SignalR;
- using Microsoft.AspNet.SignalR.Hubs;
- namespace MVCRealtimeSignalR.Hubs
- {
- [HubName("employeesHub")]
- public class EmployeesHub : Hub
- {
- public static void BroadcastData()
- {
- IHubContext context = GlobalHost.ConnectionManager.GetHubContext<EmployeesHub>();
- context.Clients.All.refreshEmployeeData();
- }
- }
- }
We have created a Hub context and invoked client method “refreshEmployeeData” from it. Whenever the Hub broadcast is called, this client method in all connected clients is automatically invoked.


- using MVCRealtimeSignalR.Hubs;
- using MVCRealtimeSignalR.Models;
- using System.Data.Entity;
- using System.Linq;
- using System.Net;
- using System.Web.Mvc;
- namespace MVCRealtimeSignalR.Controllers
- {
- public class EmployeesController : Controller
- {
- private SignalRDbContext db = new SignalRDbContext();
- // GET: Employees
- public ActionResult Index()
- {
- return View();
- }
- public ActionResult GetEmployeeData()
- {
- return PartialView("_EmployeeData", db.Employees.ToList());
- }
- // GET: Employees/Details/5
- public ActionResult Details(int? id)
- {
- if (id == null)
- {
- return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
- }
- Employee employee = db.Employees.Find(id);
- if (employee == null)
- {
- return HttpNotFound();
- }
- return View(employee);
- }
- // GET: Employees/Create
- public ActionResult Create()
- {
- return View();
- }
- // POST: Employees/Create
- // To protect from overposting attacks, please enable the specific properties you want to bind to, for
- // more details see https://go.microsoft.com/fwlink/?LinkId=317598.
- [HttpPost]
- [ValidateAntiForgeryToken]
- public ActionResult Create([Bind(Include = "Id,Name,Company,Designation")] Employee employee)
- {
- if (ModelState.IsValid)
- {
- db.Employees.Add(employee);
- db.SaveChanges();
- EmployeesHub.BroadcastData();
- return RedirectToAction("Index");
- }
- return View(employee);
- }
- // GET: Employees/Edit/5
- public ActionResult Edit(int? id)
- {
- if (id == null)
- {
- return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
- }
- Employee employee = db.Employees.Find(id);
- if (employee == null)
- {
- return HttpNotFound();
- }
- return View(employee);
- }
- // POST: Employees/Edit/5
- // To protect from overposting attacks, please enable the specific properties you want to bind to, for
- // more details see https://go.microsoft.com/fwlink/?LinkId=317598.
- [HttpPost]
- [ValidateAntiForgeryToken]
- public ActionResult Edit([Bind(Include = "Id,Name,Company,Designation")] Employee employee)
- {
- if (ModelState.IsValid)
- {
- db.Entry(employee).State = EntityState.Modified;
- db.SaveChanges();
- EmployeesHub.BroadcastData();
- return RedirectToAction("Index");
- }
- return View(employee);
- }
- // GET: Employees/Delete/5
- public ActionResult Delete(int? id)
- {
- if (id == null)
- {
- return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
- }
- Employee employee = db.Employees.Find(id);
- if (employee == null)
- {
- return HttpNotFound();
- }
- return View(employee);
- }
- // POST: Employees/Delete/5
- [HttpPost, ActionName("Delete")]
- [ValidateAntiForgeryToken]
- public ActionResult DeleteConfirmed(int id)
- {
- Employee employee = db.Employees.Find(id);
- db.Employees.Remove(employee);
- db.SaveChanges();
- EmployeesHub.BroadcastData();
- return RedirectToAction("Index");
- }
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- db.Dispose();
- }
- base.Dispose(disposing);
- }
- }
- }
We can create “EmployeeData” partial view now.
- @model IEnumerable<MVCRealtimeSignalR.Models.Employee>
- <h2>Index</h2>
- <p>
- @Html.ActionLink("Create New", "Create")
- </p>
- <table class="table">
- <tr>
- <th>
- @Html.DisplayNameFor(model => model.Name)
- </th>
- <th>
- @Html.DisplayNameFor(model => model.Company)
- </th>
- <th>
- @Html.DisplayNameFor(model => model.Designation)
- </th>
- <th></th>
- </tr>
- @foreach (var item in Model)
- {
- <tr>
- <td>
- @Html.DisplayFor(modelItem => item.Name)
- </td>
- <td>
- @Html.DisplayFor(modelItem => item.Company)
- </td>
- <td>
- @Html.DisplayFor(modelItem => item.Designation)
- </td>
- <td>
- @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
- @Html.ActionLink("Details", "Details", new { id = item.Id }) |
- @Html.ActionLink("Delete", "Delete", new { id = item.Id })
- </td>
- </tr>
- }
- </table>
Please note that we have just moved the entire code from the “Index” view to this partial view.
- @{
- ViewBag.Title = "Employee Details";
- }
- <div id="dataModel"></div>
- @section JavaScript{
- <script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
- <script src="/signalr/hubs"></script>
- <script type="text/javascript">
- $(function () {
- var hubNotify = $.connection.employeesHub;
- $.connection.hub.start().done(function () {
- getAll();
- });
- hubNotify.client.refreshEmployeeData = function () {
- getAll();
- };
- });
- function getAll() {
- var model = $('#dataModel');
- $.ajax({
- url: '/Employees/GetEmployeeData',
- contentType: 'application/html ; charset:utf-8',
- type: 'GET',
- dataType: 'html',
- success: function(result) { model.empty().append(result); }
- });
- }
- </script>
- }
Using SignalR jQuery library, we have created client-side hub connection in this file. Using this hub connection, we have invoked a function for getting data from Server. This client function will call the “GetEmployeeData” action method in Employees controller and will get the data as html. This html will be added to a div element. Whenever the broadcast event is invoked from server side, this client-side function is called, and new data is updated in the “Index” view.
We can add an Owin startup file and invoke “MapSignalR” method on project startup. This will establish a persistent connection between the server and connected clients.
- using Microsoft.Owin;
- using Owin;
- [assembly: OwinStartup(typeof(MVCRealtimeSignalR.Startup))]
- namespace MVCRealtimeSignalR
- {
- public class Startup
- {
- public void Configuration(IAppBuilder app)
- {
- app.MapSignalR();
- }
- }
- }
We have completed all the coding part. We can run the application on Google Chrome and Firefox at same time. So, that we can see the data is automatically refreshed real-time in both browsers.


jyothi swaroopPosted Mar 26, 2025, 2:59 PM
These methods are not hititng
jyothi swaroopPosted Mar 26, 2025, 2:58 PM
$(function () { var hubNotify = $.connection.employeesHub; $.connection.hub.start().done(function () { getAll(); }); hubNotify.client.refreshEmployeeData = function () { getAll(); }; }); function getAll() { var model = $('#dataModel'); $.ajax({
jyothi swaroopPosted Mar 26, 2025, 2:58 PM
I did not find in the source code
jyothi swaroopPosted Mar 26, 2025, 2:57 PM
<script src="/signalr/hubs"></script> where is this located?
Jaime StuardoPosted Sep 28, 2022, 5:20 PM
Hello.. I am using SignalR 2.4.3 and it worked with jquery 3.6.0
Ahmed AbdiPosted Apr 25, 2020, 12:50 PM
Good article. Thanks for the share
Mikiyas ShemsuPosted Feb 4, 2020, 11:09 AM
Hello sir how can i use this example for real-time car tracking which i fetch data and integrate with google map. i want my system to show the movement of the cars. my application is developed using asp.net mvc and for real-time i prefer to use SignalR but i don't know how. please help me.
Ali SufianPosted Oct 12, 2019, 10:26 PM
Hi, I am getting the issue with signalr, some of the clients are updating and some of them are not updating using signal r until i have to refresh that page. I also changed the jquery version to 2.2.4. but still getting the issue. can you please help me
zainalabdin ibrahimPosted Oct 1, 2019, 4:38 AM
I have problem wen create or delete or edit no something happing in other browser data update wen refresh page only
Michael Durand-ChorelPosted Aug 13, 2019, 11:48 AM
I can't get the hub to work in .net core. Would you have any suggestion on how to modify it?
NTQ CáoPosted Aug 10, 2019, 12:10 PM
Hello ser. <script src="/signalr/hubs"></script> ???? where it?
Johnson HPosted Jul 8, 2019, 12:24 PM
Thanks a lot for this wonderful article. I have a question: I want to apply this example to my Angular 8 + ASP.NET MVC project. What modifications should be made? I think I just need to change View sections in my TypeScript components. If you would not mind, could you please post an Angular version of this example. And if you know there is please suggest me (with ASP.NET MVC, not Core version. Because there is no MVC + Angular 4+ version on the web). Any help would be appreciated. Thanks...
Pete HurfordPosted Jul 3, 2019, 11:11 AM
This is a really good intro to the subject, especially since there is very little out there. My only suggestion would be to hardwire model data rather than database/EF, just so it doesn't divert attention from the SignalR stuff, but....a tiny thing. Well done.
carlos colettiPosted Jun 6, 2019, 3:36 PM
Very good article! how to send a push/message to all clients ?
mohamed tammamPosted May 23, 2019, 6:28 AM
Thanks alot for your code ,i have a question , is it the same code if i'm going to use mvc api or their is any changes ,a nd what about i want to show notification for each specific user
Arkadeep DePosted May 20, 2019, 9:32 AM
Nice one. (y)
shanthan rubanPosted May 15, 2019, 5:17 AM
Nice article.
nik bamnePosted May 15, 2019, 4:11 AM
That's amazing but how could i start with signalR ?