In topic we will focus on how to display real time updates from database with SignalR on existing ASP.NET MVC CRUD project.
The topic has two step:
- First step we will create a sample app to perform CRUD operations
- Second step we will make the app real-time with SignalR
Who are not familiar yet with SignalR Overview of SignalR from my previous post.
Step – 1
At first we need to create a database named CRUD_Sample. In sample db we have to create a table named Customers.
USE [CRUD_Sample] GO /****** Object: Table [dbo].[Customers] Script Date: 1/18/2016 11:42:45 AM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_PADDING ON GO CREATE TABLE [dbo].[Customers]( [Id] [bigint] IDENTITY(1,1) NOT NULL, [CustName] [varchar](100) NULL, [CustEmail] [varchar](150) NULL, CONSTRAINT [PK_Customers] 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
Stored Procedures:
USE [CRUD_Sample] GO /****** Object: StoredProcedure [dbo].[Delete_Customer] Script Date: 1/18/2016 11:42:16 AM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author:-- Create date: -- Description: -- ============================================= CREATE PROCEDURE [dbo].[Delete_Customer] -- Add the parameters for the stored procedure here @Id Bigint AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- Insert statements for procedure here DELETE FROM[dbo].[Customers] WHERE [Id] = @Id SELECT 1 END GO /****** Object: StoredProcedure [dbo].[Get_Customer] Script Date: 1/18/2016 11:42:16 AM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: -- Create date: -- Description: -- ============================================= CREATE PROCEDURE [dbo].[Get_Customer] -- Add the parameters for the stored procedure here BIGINT AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- Insert statements for procedure here SELECT top* FROM [dbo].[Customers] END GO /****** Object: StoredProcedure [dbo].[Get_CustomerbyID] Script Date: 1/18/2016 11:42:16 AM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: -- Create date: -- Description: -- ============================================= CREATE PROCEDURE [dbo].[Get_CustomerbyID] -- Add the parameters for the stored procedure here @Id BIGINT AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- Insert statements for procedure here SELECT * FROM [dbo].[Customers] WHERE Id=@Id END GO /****** Object: StoredProcedure [dbo].[Set_Customer] Script Date: 1/18/2016 11:42:16 AM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: -- Create date: -- Description: -- ============================================= CREATE PROCEDURE [dbo].[Set_Customer] -- Add the parameters for the stored procedure here Nvarchar(100) , Nvarchar(150) AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- Insert statements for procedure here INSERT INTO [dbo].[Customers] ([CustName],[CustEmail]) VALUES(,) SELECT 1 END GO /****** Object: StoredProcedure [dbo].[Update_Customer] Script Date: 1/18/2016 11:42:16 AM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: -- Create date: -- Description: -- ============================================= CREATE PROCEDURE [dbo].[Update_Customer] -- Add the parameters for the stored procedure here @Id Bigint , Nvarchar(100) , Nvarchar(150) AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- Insert statements for procedure here UPDATE [dbo].[Customers] SET[CustName] = ,[CustEmail]= WHERE [Id] = @Id SELECT 1 END GO
Getting Started with MVC Project:
To create the sample applications, we need to have Visual Studio 2012 or later installed and be able to run the server on a platform that supports .NET 4.5.
Step: 1
Step: 2
Step: 3
Click ok and the visual studio will create and load a new ASP.NET application.
Use of Generic Repository:
With generic feature, we can reduce the amount of code we need for common scenarios.
namespace WebApplication1.Repository { interface IRepository: IDisposable where T : class { IEnumerable ExecuteQuery(string spQuery, object[] parameters); T ExecuteQuerySingle(string spQuery, object[] parameters); int ExecuteCommand(string spQuery, object[] parameters); } }
interface IRepository
Show an interface of a generic repository of type T, which is a LINQ to SQL entity. It provides a basic interface with operations like Insert, Update, Delete, GetById and GetAll.
IDisposable
The IDisposable Interface, Provides a mechanism for releasing unmanaged resources.
where T : class
This is constraining the generic parameter to a class.
The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.
namespace WebApplication1.Repository { public class GenericRepository: IRepository where T : class { Customer_Entities context = null; private DbSet entities = null; public GenericRepository(Customer_Entities context) { this.context = context; entities = context.Set (); } /// /// Get Data From Database /// public IEnumerableUse it when to retive data through a stored procedure ///ExecuteQuery(string spQuery, object[] parameters) { using (context = new Customer_Entities()) { return context.Database.SqlQuery (spQuery, parameters).ToList(); } } /// /// Get Single Data From Database /// public T ExecuteQuerySingle(string spQuery, object[] parameters) { using (context = new Customer_Entities()) { return context.Database.SqlQueryUse it when to retive single data through a stored procedure ///(spQuery, parameters).FirstOrDefault(); } } /// /// Insert/Update/Delete Data To Database /// public int ExecuteCommand(string spQuery, object[] parameters) { int result = 0; try { using (context = new Customer_Entities()) { result = context.Database.SqlQueryUse it when to Insert/Update/Delete data through a stored procedure ///(spQuery, parameters).FirstOrDefault(); } } catch { } return result; } private bool disposed = false; protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { context.Dispose(); } } this.disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }
Use of Middle-tire:
namespace WebApplication1.Services { public partial class CustomerService { private GenericRepositoryCustRepository; public CustomerService() { this.CustRepository = new GenericRepository (new Customer_Entities()); } public IEnumerable GetAll(object[] parameters) { string spQuery = "[Get_Customer] {0}"; return CustRepository.ExecuteQuery(spQuery, parameters); } public Customer GetbyID(object[] parameters) { string spQuery = "[Get_CustomerbyID] {0}"; return CustRepository.ExecuteQuerySingle(spQuery, parameters); } public int Insert(object[] parameters) { string spQuery = "[Set_Customer] {0}, {1}"; return CustRepository.ExecuteCommand(spQuery, parameters); } public int Update(object[] parameters) { string spQuery = "[Update_Customer] {0}, {1}, {2}"; return CustRepository.ExecuteCommand(spQuery, parameters); } public int Delete(object[] parameters) { string spQuery = "[Delete_Customer] {0}"; return CustRepository.ExecuteCommand(spQuery, parameters); } } }
Use of Generic Repository in MVC-Application:
public class HomeController : Controller { private CustomerService objCust; public HomeController() { this.objCust = new CustomerService(); } // GET: Home public ActionResult Index() { int Count = 10; IEnumerable
Use of views in MVC-Application:
Index: IList@{ ViewBag.Title = "Index"; } Insert WebApplication1.Models.Customer @{ ViewBag.Title = "Insert"; }.ActionLink("New Customer", "Insert", "Home")
@if (Model != null) { foreach (var item in Model) { ID Name Email ID Delete Update } } .Id .CustName .CustEmail .ActionLink("Delete", "Delete", "Home", new { id = .Id }, null) .ActionLink("Update", "Update", "Home", new { id = .Id }, null) Update WebApplication1.Models.Customer @{ ViewBag.Title = "Update"; }(Html.BeginForm("Insert", "Home", FormMethod.Post)) { @*
*@ ID .TextBoxFor(m => m.Id) Name .TextBoxFor(m => m.CustName) Email ID .TextBoxFor(m => m.CustEmail) } .ActionLink("Home", "Index", "Home")
Name Email ID Update (Html.BeginForm("Update", "Home", FormMethod.Post)) { .TextBoxFor(m => m.CustName) .TextBoxFor(m => m.CustEmail) }
Step – 2
Getting Started with SignalR:
The first thing is getting reference from NuGet.
Get it on NuGet!
Install-Package Microsoft.AspNet.SignalR
Register SignalR middleware:
Once you have it installed. Let’s create OwinStartup Class.
The following code adds a simple piece of middleware to the OWIN pipeline, implemented as a function that receives a Microsoft.Owin.IOwinContext instance.
When the server receives an HTTP request, the OWIN pipeline invokes the middleware. The middleware sets the content type for the response and writes the response body.
Startup.cs
using System; using System.Threading.Tasks; using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(WebAppSignalR.Startup))] namespace WebAppSignalR { public class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } }
Create & Use Hub classes:
After finishing previous process, let’s create a Hub. A SignalR Hub make remote procedure calls (RPCs) from a server to connected clients and from clients to the server.
CustomerHub.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; namespace WebApplication1.Hubs { public class CustomerHub : Hub { [HubMethodName("broadcastData")] public static void BroadcastData() { IHubContext context = GlobalHost.ConnectionManager.GetHubContext(); context.Clients.All.updatedData(); } } }
Code Explanation:
IHubContext context = GlobalHost.ConnectionManager.GetHubContext();
It gets the CustomerHub context
context.Clients.All.updatedData();
It call the client part of SignalR and tell it to execute the JavaScript method updatedData().
Let’s Modify our Existing View:
Now we will modify part of Index view as following, and we will display data with a partial view.
Index:
IList@{ ViewBag.Title = "Index"; } JavaScript{ }.ActionLink("New Customer", "Insert", "Home")
Partial View:
ID | Name | Email ID | Delete | Update |
---|---|---|---|---|
.Id | .CustName | .CustEmail | .ActionLink("Delete", "Delete", "Home", new { id = .Id }, null) | .ActionLink("Update", "Update", "Home", new { id = .Id }, null) |
Let’s Modify our Existing Controller:
Home Controller:
In our home controller we will add a method named GetAllData(). Here the following method.
[HttpGet] public ActionResult GetAllData() { int Count = 10; IEnumerable
Here we are returning a partial view with returned data list, and just returning empty.
// GET: Home public ActionResult Index() { return View(); }
Finally Home Controller:
public class HomeController : Controller { private CustomerService objCust; //CustomerRepository CustRepository; public HomeController() { this.objCust = new CustomerService(); } // GET: Home public ActionResult Index() { return View(); } [HttpGet] public ActionResult GetAllData() { int Count = 10; IEnumerable
Finally Output:
Hope this will help someone 🙂
Source Code: I’ve uploaded the full source code to download/clone , Hope this will help 🙂
kshitij says:
Nice Artical. Keep posting..
Shashangka Shekhar says:
Thanks
durgesh says:
unable to download source code. please provide download link
Shashangka Shekhar says:
Please get it from here:
Vern says:
Great Article. Sir can you do it with angularjs?
Shashangka Shekhar says:
Thanks, Yap sure (y)
Mateusz Diiiii says:
Dear Shashangka,
I’ve downloaded your project, opened it in VS2015 and I’ve meet a problem. There is no errors, I have a possibility to add new customer, but the list of customers don’t display on the index. Customers are added to the SQL database, but there is no possibility to see the list on the index site. Can you help me?
Tai Nguyen says:
Hi Shashangka ,
Great Article. But I can’t change index site when update from sql server. Pls help. thanks you!