通过 SignalR 类库,实现 ASP.NET MVC 的实时通信
在本文中,您将学到在现有 ASP.NET MVC 框架的 CRUD 项目中,如何使用 SignalR 类库,显示来自数据库的实时更新。在这一主题中,我们将重点放在在现有 ASP.NET MVC 框架的 CRUD 项目中,如何使用 SignalR 类库,显示来自数据库的实时更新。 本文系国内 ITOM 管理平台OneAPM工程师编译整理。
本主题有以下两个步骤:
我们将创建一个示例应用程序来执行 CRUD 操作。
我们将使用 SignalR 类库让应用实时。
那些不熟悉 SignalR 的,请访问我以前有关SignalR 概述的文章。
第一步:我们需要创建一个名为 CRUD_Sample 的数据库。在示例数据库中创建一个名为 Customer 的表。
CREATETABLE[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]ScriptDate:12/27/20151:44:05PM******/SETANSI_NULLSONGOSETQUOTED_IDENTIFIERONGO--=============================================--Author:<Author,,Name>--Createdate:<CreateDate,,>--Description:<Description,,>--=============================================CREATEPROCEDURE[dbo].[Delete_Customer]--Addtheparametersforthestoredprocedurehere@IdBigintASBEGIN--SETNOCOUNTONaddedtopreventextraresultsetsfrom--interferingwithSELECTstatements.SETNOCOUNTON;--InsertstatementsforprocedurehereDELETEFROM[dbo].[Customers]WHERE[Id]=@IdRETURN1ENDGO/******Object:StoredProcedure[dbo].[Get_Customer]ScriptDate:12/27/20151:44:05PM******/SETANSI_NULLSONGOSETQUOTED_IDENTIFIERONGO--=============================================--Author:<Author,,Name>--Createdate:<CreateDate,,>--Description:<Description,,>--=============================================CREATEPROCEDURE[dbo].[Get_Customer]--Addtheparametersforthestoredprocedurehere@CountINTASBEGIN--SETNOCOUNTONaddedtopreventextraresultsetsfrom--interferingwithSELECTstatements.SETNOCOUNTON;--InsertstatementsforprocedurehereSELECTtop(@Count)*FROM[dbo].[Customers]ENDGO/******Object:StoredProcedure[dbo].[Get_CustomerbyID]ScriptDate:12/27/20151:44:05PM******/SETANSI_NULLSONGOSETQUOTED_IDENTIFIERONGO--=============================================--Author:<Author,,Name>--Createdate:<CreateDate,,>--Description:<Description,,>--=============================================CREATEPROCEDURE[dbo].[Get_CustomerbyID]--Addtheparametersforthestoredprocedurehere@IdBIGINTASBEGIN--SETNOCOUNTONaddedtopreventextraresultsetsfrom--interferingwithSELECTstatements.SETNOCOUNTON;--InsertstatementsforprocedurehereSELECT*FROM[dbo].[Customers]WHEREId=@IdENDGO/******Object:StoredProcedure[dbo].[Set_Customer]ScriptDate:12/27/20151:44:05PM******/SETANSI_NULLSONGOSETQUOTED_IDENTIFIERONGO--=============================================--Author:<Author,,Name>--Createdate:<CreateDate,,>--Description:<Description,,>--=============================================CREATEPROCEDURE[dbo].[Set_Customer]--Addtheparametersforthestoredprocedurehere@CustNameNvarchar(100),@CustEmailNvarchar(150)ASBEGIN--SETNOCOUNTONaddedtopreventextraresultsetsfrom--interferingwithSELECTstatements.SETNOCOUNTON;--InsertstatementsforprocedurehereINSERTINTO[dbo].[Customers]([CustName],[CustEmail])VALUES(@CustName,@CustEmail)RETURN1ENDGO/******Object:StoredProcedure[dbo].[Update_Customer]ScriptDate:12/27/20151:44:05PM******/SETANSI_NULLSONGOSETQUOTED_IDENTIFIERONGO--=============================================--Author:<Author,,Name>--Createdate:<CreateDate,,>--Description:<Description,,>--=============================================CREATEPROCEDURE[dbo].[Update_Customer]--Addtheparametersforthestoredprocedurehere@IdBigint,@CustNameNvarchar(100),@CustEmailNvarchar(150)ASBEGIN--SETNOCOUNTONaddedtopreventextraresultsetsfrom--interferingwithSELECTstatements.SETNOCOUNTON;--InsertstatementsforprocedurehereUPDATE[dbo].[Customers]SET[CustName]=@CustName,[CustEmail]=@CustEmailWHERE[Id]=@IdRETURN1ENDGO启动 MVC 项目
创建示例应用程序,我们需要 Visual Studio 2012 或更高版本,并且该服务器平台必须支持 .NET 4.5。
步骤 1:
Step 2:
Step 3:
点击 OK,Visual Studio 将会创建一个新的 ASP.NET 工程。
使用通用类库使用通用功能,我们可以减少代码数量。
namespaceWebApplication1.Repository{interfaceIRepository<T>:IDisposablewhereT:class{IEnumerable<T>ExecuteQuery(stringspQuery,object[]parameters);TExecuteQuerySingle(stringspQuery,object[]parameters);intExecuteCommand(stringspQuery,object[]parameters);}}接口 IRepository
显示一个通用类库的 T 型接口,它是 SQL 实体的 LINQ。它提供了一个基本的界面操作,如 Insert, Update, Delete, GetById and GetAll。
IDisposableIDisposable接口提供了一种机制,释放非托管资源。
where T : class这是制约泛型参数的一类。点击查看更多。
类型参数必须是引用类型;这也适用于任何类,接口,委托或数组类型。
namespaceWebApplication1.Repository{publicclassGenericRepository<T>:IRepository<T>whereT:class{Customer_Entitiescontext=null;privateDbSet<T>entities=null;publicGenericRepository(Customer_Entitiescontext){this.context=context;entities=context.Set<T>();}///<summary>///GetDataFromDatabase///<para>Useitwhentoretivedatathroughastoredprocedure</para>///</summary>publicIEnumerable<T>ExecuteQuery(stringspQuery,object[]parameters){using(context=newCustomer_Entities()){returncontext.Database.SqlQuery<T>(spQuery,parameters).ToList();}}///<summary>///GetSingleDataFromDatabase///<para>Useitwhentoretivesingledatathroughastoredprocedure</para>///</summary>publicTExecuteQuerySingle(stringspQuery,object[]parameters){using(context=newCustomer_Entities()){returncontext.Database.SqlQuery<T>(spQuery,parameters).FirstOrDefault();}}///<summary>///Insert/Update/DeleteDataToDatabase///<para>UseitwhentoInsert/Update/Deletedatathroughastoredprocedure</para>///</summary>publicintExecuteCommand(stringspQuery,object[]parameters){intresult=0;try{using(context=newCustomer_Entities()){result=context.Database.SqlQuery<int>(spQuery,parameters).FirstOrDefault();}}catch{}returnresult;}privatebooldisposed=false;protectedvirtualvoidDispose(booldisposing){if(!this.disposed){if(disposing){context.Dispose();}}this.disposed=true;}publicvoidDispose(){Dispose(true);GC.SuppressFinalize(this);}}}使用 middle-tire 结构
namespaceWebApplication1.Services{publicpartialclassCustomerService{privateGenericRepository<Customer>CustRepository;//CustomerRepositoryCustRepository;publicCustomerService(){this.CustRepository=newGenericRepository<Customer>(newCustomer_Entities());}publicIEnumerable<Customer>GetAll(object[]parameters){stringspQuery="[Get_Customer]{0}";returnCustRepository.ExecuteQuery(spQuery,parameters);}publicCustomerGetbyID(object[]parameters){stringspQuery="[Get_CustomerbyID]{0}";returnCustRepository.ExecuteQuerySingle(spQuery,parameters);}publicintInsert(object[]parameters){stringspQuery="[Set_Customer]{0},{1}";returnCustRepository.ExecuteCommand(spQuery,parameters);}publicintUpdate(object[]parameters){stringspQuery="[Update_Customer]{0},{1},{2}";returnCustRepository.ExecuteCommand(spQuery,parameters);}publicintDelete(object[]parameters){stringspQuery="[Delete_Customer]{0}";returnCustRepository.ExecuteCommand(spQuery,parameters);}}}在 MVC 架构应用程序中使用通用库
namespaceWebApplication1.Controllers{publicclassHomeController:Controller{privateCustomerServiceobjCust;//CustomerRepositoryCustRepository;publicHomeController(){this.objCust=newCustomerService();}//GET:HomepublicActionResultIndex(){intCount=10;object[]parameters={Count};vartest=objCust.GetAll(parameters);returnView(test);}publicActionResultInsert(){returnView();}[HttpPost]publicActionResultInsert(Customermodel){if(ModelState.IsValid){object[]parameters={model.CustName,model.CustEmail};objCust.Insert(parameters);}returnRedirectToAction("Index");}publicActionResultDelete(intid){object[]parameters={id};this.objCust.Delete(parameters);returnRedirectToAction("Index");}publicActionResultUpdate(intid){object[]parameters={id};returnView(this.objCust.GetbyID(parameters));}[HttpPost]publicActionResultUpdate(Customermodel){object[]parameters={model.Id,model.CustName,model.CustEmail};objCust.Update(parameters);returnRedirectToAction("Index");}protectedoverridevoidDispose(booldisposing){base.Dispose(disposing);}}}在 MVC 架构应用程序中使用视图Index
@modelIList<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("NewCustomer","Insert","Home")<tableclass="tabletable-borderedtable-striped"><thead><tr><th>ID</th><th>Name</th><th>EmailID</th><th>Delete</th><th>Update</th></tr></thead><tbody>@if(Model!=null){foreach(variteminModel){<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
@modelWebApplication1.Models.Customer@{ViewBag.Title="Insert";}<linkhref="~/Content/bootstrap/css/bootstrap.min.css"rel="stylesheet"/><divclass="clearfix"></div><divclass="clearfix"></div><divclass="container"><divclass="table-responsivecol-md-6col-md-offset-3"><tableclass="tabletable-borderedtable-striped"><tbody>@using(Html.BeginForm("Insert","Home",FormMethod.Post)){@*<tr><tdclass="col-md-4">ID</td><tdclass="col-md-8">@Html.TextBoxFor(m=>m.Id)</td></tr>*@<tr><tdclass="col-md-4">Name</td><tdclass="col-md-8">@Html.TextBoxFor(m=>m.CustName)</td></tr><tr><tdclass="col-md-4">EmailID</td><tdclass="col-md-8">@Html.TextBoxFor(m=>m.CustEmail)</td></tr><tr><tdclass="text-right"colspan="2"><inputtype="submit"value="Save"class="btnbtn-primary"/></td></tr>}</tbody></table></div><divclass="clearfix"></div>@Html.ActionLink("Home","Index","Home")</div>Update
@modelWebApplication1.Models.Customer@{ViewBag.Title="Update";}<linkhref="~/Content/bootstrap/css/bootstrap.min.css"rel="stylesheet"/><divclass="clearfix"></div><divclass="clearfix"></div><divclass="container"><divclass="table-responsive"><tableclass="tabletable-borderedtable-striped"><thead><tr><th>Name</th><th>EmailID</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
安装后需要创建 OwinStartup 类。
下面的代码将一段简单中间件向 OWIN 管道,实现接收 Microsoft.Owin.IOwinContext 实例的功能。
当服务器收到一个 HTTP 请求,OWIN 管道调用中间件。中间件设置内容类型的响应和写响应体。
Startup.csusingSystem;usingSystem.Threading.Tasks;usingMicrosoft.Owin;usingOwin;[assembly:OwinStartup(typeof(WebAppSignalR.Startup))]namespaceWebAppSignalR{publicclassStartup{publicvoidConfiguration(IAppBuilderapp){app.MapSignalR();}}}创建使用 Hub 类
完成前面的过程之后,创建一个 Hub。一个SignalR Hub 让从服务器到客户端连接,并从客户端到服务器的远程过程调用(RPC)。
CustomerHub.csusingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Web;usingMicrosoft.AspNet.SignalR;usingMicrosoft.AspNet.SignalR.Hubs;namespaceWebApplication1.Hubs{publicclassCustomerHub:Hub{[HubMethodName("broadcastData")]publicstaticvoidBroadcastData(){IHubContextcontext=GlobalHost.ConnectionManager.GetHubContext<CustomerHub>();context.Clients.All.updatedData();}}}代码说明
IHubContextcontext=GlobalHost.ConnectionManager.GetHubContext<CustomerHub>();获得 CustomerHub context:
context.Clients.All.updatedData();
它请求 SignalR 的客户端部分,并告诉它执行 JavaScript 的 updatedData()方法。
修改现有视图 Let’s Modify our Existing View修改一部分索引视图,将通过局部视图显示数据。
Index@modelIList<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("NewCustomer","Insert","Home")<hr/><divid="dataTable"></div></div><divclass="clearfix"> </div></div>@sectionJavaScript{<scriptsrc="~/Scripts/jquery.signalR-2.2.0.min.js"></script><scriptsrc="/signalr/hubs"></script><scripttype="text/javascript">$(function(){//Referencethehub.varhubNotif=$.connection.customerHub;//Starttheconnection.$.connection.hub.start().done(function(){getAll();});//NotifywhileanyChanges.hubNotif.client.updatedData=function(){getAll();};});functiongetAll(){varmodel=$('#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>}局部视图
<tableclass="tabletable-borderedtable-striped"><thead><tr><th>ID</th><th>Name</th><th>EmailID</th><th>Delete</th><th>Update</th></tr></thead><tbody>@if(Model!=null){foreach(variteminModel){<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>修改现有 Controller主 Controller:
在主 Controller,我们将添加一个名为 GetAllDaTa()的方法。这是方法。
[HttpGet]publicActionResultGetAllData(){intCount=10;object[]parameters={Count};vartest=objCust.GetAll(parameters);returnPartialView("_DataList",test);}
在这里,返回局部视图返回的数据列表,且只返回空。
//GET:HomepublicActionResultIndex(){returnView();}主 Controller
publicclassHomeController:Controller{privateCustomerServiceobjCust;//CustomerRepositoryCustRepository;publicHomeController(){this.objCust=newCustomerService();}//GET:HomepublicActionResultIndex(){returnView();}[HttpGet]publicActionResultGetAllData(){intCount=10;object[]parameters={Count};vartest=objCust.GetAll(parameters);returnPartialView("_DataList",test);}publicActionResultInsert(){returnView();}[HttpPost]publicActionResultInsert(Customermodel){if(ModelState.IsValid){object[]parameters={model.CustName,model.CustEmail};objCust.Insert(parameters);}//NotifytoallCustomerHub.BroadcastData();returnRedirectToAction("Index");}publicActionResultDelete(intid){object[]parameters={id};this.objCust.Delete(parameters);//NotifytoallCustomerHub.BroadcastData();returnRedirectToAction("Index");}publicActionResultUpdate(intid){object[]parameters={id};returnView(this.objCust.GetbyID(parameters));}[HttpPost]publicActionResultUpdate(Customermodel){object[]parameters={model.Id,model.CustName,model.CustEmail};objCust.Update(parameters);//NotifytoallCustomerHub.BroadcastData();returnRedirectToAction("Index");}protectedoverridevoidDispose(booldisposing){base.Dispose(disposing);}}输出
希望能够帮助到您。
OneAPM 助您轻松锁定.NET 应用性能瓶颈,通过强大的 Trace 记录逐层分析,直至锁定行级问题代码。以用户角度展示系统响应速度,以地域和浏览器维度统计用户使用情况。想阅读更多技术文章,请访问OneAPM 官方博客。
本文转自OneAPM 官方博客
原文地址:http://www.c-sharpcorner.com/UploadFile/302f8f/Asp-Net-mvc-real-time-app-with-signalr/
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。