在本文中管削,您將學(xué)到在現(xiàn)有 ASP.NET MVC 框架的 CRUD 項目中倒脓,如何使用 SignalR 類庫,顯示來自數(shù)據(jù)庫的實時更新佩谣。在這一主題中把还,我們將重點放在在現(xiàn)有 ASP.NET MVC 框架的 CRUD 項目中,如何使用 SignalR 類庫茸俭,顯示來自數(shù)據(jù)庫的實時更新吊履。 本文系國內(nèi) ITOM 管理平臺 OneAPM 工程師編譯整理。
本主題有以下兩個步驟:
我們將創(chuàng)建一個示例應(yīng)用程序來執(zhí)行 CRUD 操作调鬓。
我們將使用 SignalR 類庫讓應(yīng)用實時艇炎。
那些不熟悉 SignalR 的,請訪問我以前有關(guān) SignalR 概述 的文章腾窝。
第一步:
我們需要創(chuàng)建一個名為 CRUD_Sample 的數(shù)據(jù)庫缀踪。在示例數(shù)據(jù)庫中創(chuàng)建一個名為 Customer 的表。
CREATE TABLE [dbo].[Customer](
[Id] [bigint] IDENTITY(1,1)NOTNULL,
[CustName] [varchar](100)NULL,
[CustEmail] [varchar](150)NULL
)
存儲過程
USE [CRUD_Sample]
GO
/****** Object: StoredProcedure [dbo].[Delete_Customer] Script Date: 12/27/2015 1:44:05 PM ******/
SETANSI_NULLSON
GO
SETQUOTED_IDENTIFIERON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <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.
SETNOCOUNTON;
-- Insert statements for procedure here
DELETE FROM [dbo].[Customers] WHERE [Id] = @Id
RETURN 1
END
GO
/****** Object: StoredProcedure [dbo].[Get_Customer] Script Date: 12/27/2015 1:44:05 PM ******/
SETANSI_NULLSON
GO
SETQUOTED_IDENTIFIERON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[Get_Customer]
-- Add the parameters for the stored procedure here
@Count INT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SETNOCOUNTON;
-- Insert statements for procedure here
SELECT top(@Count)*FROM [dbo].[Customers]
END
GO
/****** Object: StoredProcedure [dbo].[Get_CustomerbyID] Script Date: 12/27/2015 1:44:05 PM ******/
SETANSI_NULLSON
GO
SETQUOTED_IDENTIFIERON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <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.
SETNOCOUNTON;
-- Insert statements for procedure here
SELECT*FROM [dbo].[Customers]
WHERE Id=@Id
END
GO
/****** Object: StoredProcedure [dbo].[Set_Customer] Script Date: 12/27/2015 1:44:05 PM ******/
SETANSI_NULLSON
GO
SETQUOTED_IDENTIFIERON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[Set_Customer]
-- Add the parameters for the stored procedure here
@CustNameNvarchar(100)
,@CustEmailNvarchar(150)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SETNOCOUNTON;
-- Insert statements for procedure here
INSERT INTO [dbo].[Customers]([CustName],[CustEmail])
VALUES(@CustName,@CustEmail)
RETURN 1
END
GO
/****** Object: StoredProcedure [dbo].[Update_Customer] Script Date: 12/27/2015 1:44:05 PM ******/
SETANSI_NULLSON
GO
SETQUOTED_IDENTIFIERON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[Update_Customer]
-- Add the parameters for the stored procedure here
@Id Bigint
,@CustNameNvarchar(100)
,@CustEmailNvarchar(150)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SETNOCOUNTON;
-- Insert statements for procedure here
UPDATE [dbo].[Customers] SET[CustName] = @CustName,[CustEmail]= @CustEmail
WHERE [Id] = @Id
RETURN 1
END
GO
啟動 MVC 項目
創(chuàng)建示例應(yīng)用程序虹脯,我們需要 Visual Studio 2012 或更高版本驴娃,并且該服務(wù)器平臺必須支持 .NET 4.5。
步驟 1:
Step 2:
Step 3:
點擊 OK循集,Visual Studio 將會創(chuàng)建一個新的 ASP.NET 工程唇敞。
使用通用類庫
使用通用功能,我們可以減少代碼數(shù)量咒彤。
namespace WebApplication1.Repository
{
interfaceIRepository < T > : IDisposablewhereT: class
{
IEnumerable < T > ExecuteQuery(stringspQuery, object[] parameters);
TExecuteQuerySingle(stringspQuery, object[] parameters);
intExecuteCommand(stringspQuery, object[] parameters);
}
}
接口 IRepository<T>
顯示一個通用類庫的 T 型接口疆柔,它是 SQL 實體的 LINQ。它提供了一個基本的界面操作镶柱,如 Insert, Update, Delete, GetById and GetAll旷档。
IDisposable
IDisposable接口提供了一種機制,釋放非托管資源歇拆。
where T : class
這是制約泛型參數(shù)的一類鞋屈。點擊查看更多范咨。
類型參數(shù)必須是引用類型;這也適用于任何類,接口谐区,委托或數(shù)組類型湖蜕。
namespace WebApplication1.Repository
{
public class GenericRepository < T > : IRepository < T > whereT: class
{
Customer_Entities context = null;
privateDbSet < T > entities = null;
public GenericRepository(Customer_Entities context)
{
this.context = context;
entities = context.Set < T > ();
}
///<summary>
/// Get Data From Database
///<para>Use it when to retive data through a stored procedure</para>
///</summary>
public IEnumerable < T > ExecuteQuery(stringspQuery, object[] parameters)
{
using(context = newCustomer_Entities())
{
returncontext.Database.SqlQuery < T > (spQuery, parameters).ToList();
}
}
///<summary>
/// Get Single Data From Database
///<para>Use it when to retive single data through a stored procedure</para>
///</summary>
public TExecuteQuerySingle(stringspQuery, object[] parameters)
{
using(context = newCustomer_Entities())
{
returncontext.Database.SqlQuery < T > (spQuery, parameters).FirstOrDefault();
}
}
///<summary>
/// Insert/Update/Delete Data To Database
///<para>Use it when to Insert/Update/Delete data through a stored procedure</para>
///</summary>
public intExecuteCommand(stringspQuery, object[] parameters)
{
int result = 0;
try
{
using(context = newCustomer_Entities())
{
result = context.Database.SqlQuery < int > (spQuery, parameters).FirstOrDefault();
}
}
catch
{}
return result;
}
private bool disposed = false;
protected virtualvoid Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
使用 middle-tire 結(jié)構(gòu)
namespace WebApplication1.Services
{
public partial class CustomerService
{
privateGenericRepository < Customer > CustRepository;
//CustomerRepositoryCustRepository;
public CustomerService()
{
this.CustRepository = newGenericRepository < Customer > (newCustomer_Entities());
}
public IEnumerable < Customer > GetAll(object[] parameters)
{
stringspQuery = "[Get_Customer] {0}";
returnCustRepository.ExecuteQuery(spQuery, parameters);
}
public CustomerGetbyID(object[] parameters)
{
stringspQuery = "[Get_CustomerbyID] {0}";
returnCustRepository.ExecuteQuerySingle(spQuery, parameters);
}
public int Insert(object[] parameters)
{
stringspQuery = "[Set_Customer] {0}, {1}";
returnCustRepository.ExecuteCommand(spQuery, parameters);
}
public int Update(object[] parameters)
{
stringspQuery = "[Update_Customer] {0}, {1}, {2}";
returnCustRepository.ExecuteCommand(spQuery, parameters);
}
public int Delete(object[] parameters)
{
stringspQuery = "[Delete_Customer] {0}";
returnCustRepository.ExecuteCommand(spQuery, parameters);
}
}
}
在 MVC 架構(gòu)應(yīng)用程序中使用通用庫
namespace WebApplication1.Controllers
{
public class HomeController: Controller
{
private CustomerServiceobjCust;
//CustomerRepositoryCustRepository;
public HomeController()
{
this.objCust = newCustomerService();
}
// GET: Home
public ActionResult Index()
{
int Count = 10;
object[] parameters = {
Count
};
var test = objCust.GetAll(parameters);
return View(test);
}
public ActionResult Insert()
{
return View();
}
[HttpPost]
public ActionResult Insert(Customer model)
{
if (ModelState.IsValid)
{
object[] parameters = {
model.CustName,
model.CustEmail
};
objCust.Insert(parameters);
}
return RedirectToAction("Index");
}
public ActionResult Delete(int id)
{
object[] parameters = {
id
};
this.objCust.Delete(parameters);
return RedirectToAction("Index");
}
public ActionResult Update(int id)
{
object[] parameters = {
id
};
return View(this.objCust.GetbyID(parameters));
}
[HttpPost]
public ActionResult Update(Customer model)
{
object[] parameters = {
model.Id,
model.CustName,
model.CustEmail
};
objCust.Update(parameters);
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
}
}
在 MVC 架構(gòu)應(yīng)用程序中使用視圖
Index
@model IList
<WebApplication1.Models.Customer>
@{
ViewBag.Title = "Index";
}
<linkhref="~/Content/bootstrap/css/bootstrap.min.css"rel="stylesheet"/>
<divclass="clearfix">
</div>
<divclass="clearfix">
</div>
<divclass="container">
<divclass="table-responsive">
@Html.ActionLink("New Customer", "Insert", "Home")
<tableclass="table table-bordered table-striped">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email ID</th>
<th>Delete</th>
<th>Update</th>
</tr>
</thead>
<tbody>
@if (Model != null)
{
foreach (var item in Model)
{
<tr>
<td>@item.Id</td>
<td>@item.CustName</td>
<td>@item.CustEmail</td>
<td>@Html.ActionLink("Delete", "Delete", "Home", new { id = @item.Id }, null)</td>
<td>@Html.ActionLink("Update", "Update", "Home", new { id = @item.Id }, null)</td>
</tr>
}
}
</tbody>
</table>
</div>
<divclass="clearfix">
</div>
</div>
Insert
@model WebApplication1.Models.Customer
@{
ViewBag.Title = "Insert";
}
<link href="~/Content/bootstrap/css/bootstrap.min.css"rel="stylesheet"/>
<div class="clearfix">
</div>
<div class="clearfix">
</div>
<div class="container">
<div class="table-responsive col-md-6 col-md-offset-3">
<table class="table table-bordered table-striped">
<tbody>
@using (Html.BeginForm("Insert", "Home", FormMethod.Post))
{
@*
<tr>
<td class="col-md-4">ID</td>
<td class="col-md-8">@Html.TextBoxFor(m =>m.Id)</td>
</tr>*@
<tr>
<td class="col-md-4">Name
</td>
<td class="col-md-8">@Html.TextBoxFor(m =>m.CustName)
</td>
</tr>
<tr>
<td class="col-md-4">Email ID
</td>
<td class="col-md-8">@Html.TextBoxFor(m =>m.CustEmail)
</td>
</tr>
<tr>
<td class="text-right"colspan="2">
<input type="submit"value="Save"class="btnbtn-primary"/>
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="clearfix">
</div>
@Html.ActionLink("Home", "Index", "Home")
</div>
Update
@model WebApplication1.Models.Customer
@{
ViewBag.Title = "Update";
}
<link href="~/Content/bootstrap/css/bootstrap.min.css"rel="stylesheet"/>
<div class="clearfix">
</div>
<div class="clearfix">
</div>
<div class="container">
<div class="table-responsive">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Name</th>
<th>Email ID</th>
<th>Update</th>
</tr>
</thead>
<tbody>
<tr>
@using (Html.BeginForm("Update", "Home", FormMethod.Post))
{
<td>@Html.TextBoxFor(m =>m.CustName)</td>
<td>@Html.TextBoxFor(m =>m.CustEmail)</td>
<td>
<inputtype="submit"value="Update"class="btnbtn-primary"/>
</td>
}
</tr>
</tbody>
</table>
</div>
</div>
步驟2:
啟動 SignalR
第一件事是獲得 NuGet 參照姿鸿。
在 NuGet 上獲得百新。
安裝 Microsoft.AspNet.SignalR 包
Microsoft.AspNet.SignalR
注冊 SignalR 中間件
安裝后需要創(chuàng)建 OwinStartup 類丘侠。
下面的代碼將一段簡單中間件向 OWIN 管道,實現(xiàn)接收 Microsoft.Owin.IOwinContext 實例的功能炼杖。
當(dāng)服務(wù)器收到一個 HTTP 請求,OWIN 管道調(diào)用中間件盗迟。中間件設(shè)置內(nèi)容類型的響應(yīng)和寫響應(yīng)體坤邪。
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();
}
}
}
創(chuàng)建使用 Hub 類
完成前面的過程之后,創(chuàng)建一個 Hub罚缕。一個SignalR Hub 讓從服務(wù)器到客戶端連接艇纺,并從客戶端到服務(wù)器的遠程過程調(diào)用(RPC)。
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 < CustomerHub > ();
context.Clients.All.updatedData();
}
}
}
代碼說明
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<CustomerHub>();
獲得 CustomerHub context:
context.Clients.All.updatedData();
它請求 SignalR 的客戶端部分邮弹,并告訴它執(zhí)行 JavaScript 的 updatedData()方法黔衡。
修改現(xiàn)有視圖 Let’s Modify our Existing View
修改一部分索引視圖,將通過局部視圖顯示數(shù)據(jù)腌乡。
Index
@model IList < WebApplication1.Models.Customer > @
{
ViewBag.Title = "Index";
} < linkhref = "~/Content/bootstrap/css/bootstrap.min.css"
rel = "stylesheet" / > < divclass = "clearfix" > & nbsp; < /div> < divclass = "clearfix" > & nbsp; < /div> < divclass = "container" > < divclass = "table-responsive" > @Html.ActionLink("New Customer", "Insert", "Home") < hr / > < divid = "dataTable" > < /div> < /div> < divclass = "clearfix" > & nbsp; < /div> < /div>
@section JavaScript
{ < scriptsrc = "~/Scripts/jquery.signalR-2.2.0.min.js" > < /script> < scriptsrc = "/signalr/hubs" > < /script> < scripttype = "text/javascript" > $(function ()
{
// Reference the hub.
var hubNotif = $.connection.customerHub;
// Start the connection.
$.connection.hub.start().done(function ()
{
getAll();
});
// Notify while anyChanges.
hubNotif.client.updatedData = function ()
{
getAll();
};
});
function getAll()
{
var model = $('#dataTable');
$.ajax(
{
url: '/home/GetAllData',
contentType: 'application/html ; charset:utf-8',
type: 'GET',
dataType: 'html'
}).success(function (result)
{
model.empty().append(result);
}).error(function (e)
{
alert(e);
});
} < /script>
}
局部視圖
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email ID</th>
<th>Delete</th>
<th>Update</th>
</tr>
</thead>
<tbody> @if (Model != null) { foreach (var item in Model) {
<tr>
<td>@item.Id</td>
<td>@item.CustName</td>
<td>@item.CustEmail</td>
<td>@Html.ActionLink("Delete", "Delete", "Home", new { id = @item.Id }, null)</td>
<td>@Html.ActionLink("Update", "Update", "Home", new { id = @item.Id }, null)</td>
</tr> } } </tbody>
</table>
修改現(xiàn)有 Controller
主 Controller:
在主 Controller盟劫,我們將添加一個名為 GetAllDaTa()的方法。這是方法与纽。
[HttpGet]
public ActionResult GetAllData()
{
int Count = 10;
object[] parameters = {
Count
};
var test = objCust.GetAll(parameters);
return PartialView("_DataList", test);
}
在這里侣签,返回局部視圖返回的數(shù)據(jù)列表,且只返回空急迂。
// GET: Home
public ActionResult Index()
{
return View();
}
主 Controller
public class HomeController: Controller
{
private CustomerService objCust;
//CustomerRepositoryCustRepository;
public HomeController()
{
this.objCust = newCustomerService();
}
// GET: Home
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult GetAllData()
{
int Count = 10;
object[] parameters = {
Count
};
var test = objCust.GetAll(parameters);
return PartialView("_DataList", test);
}
public ActionResult Insert()
{
return View();
}
[HttpPost]
public ActionResult Insert(Customer model)
{
if (ModelState.IsValid)
{
object[] parameters = {
model.CustName,
model.CustEmail
};
objCust.Insert(parameters);
}
//Notify to all
CustomerHub.BroadcastData();
return RedirectToAction("Index");
}
public ActionResult Delete(int id)
{
object[] parameters = {
id
};
this.objCust.Delete(parameters);
//Notify to all
CustomerHub.BroadcastData();
return RedirectToAction("Index");
}
public ActionResult Update(int id)
{
object[] parameters = {
id
};
return View(this.objCust.GetbyID(parameters));
}
[HttpPost]
public ActionResult Update(Customer model)
{
object[] parameters = {
model.Id,
model.CustName,
model.CustEmail
};
objCust.Update(parameters);
//Notify to all
CustomerHub.BroadcastData();
returnRedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
}
輸出
希望能夠幫助到您影所。
OneAPM 助您輕松鎖定 .NET 應(yīng)用性能瓶頸,通過強大的 Trace 記錄逐層分析僚碎,直至鎖定行級問題代碼猴娩。以用戶角度展示系統(tǒng)響應(yīng)速度,以地域和瀏覽器維度統(tǒng)計用戶使用情況听盖。想閱讀更多技術(shù)文章胀溺,請訪問 OneAPM 官方博客。
本文轉(zhuǎn)自 OneAPM 官方博客
原文地址: http://www.c-sharpcorner.com/UploadFile/302f8f/Asp-Net-mvc-real-time-app-with-signalr/