zoukankan      html  css  js  c++  java
  • 通过 SignalR 类库,实现 ASP.NET MVC 的实时通信

    在本文中,您将学到在现有 ASP.NET MVC 框架的 CRUD 项目中,如何使用 SignalR 类库,显示来自数据库的实时更新。在这一主题中,我们将重点放在在现有 ASP.NET MVC 框架的 CRUD 项目中,如何使用 SignalR 类库,显示来自数据库的实时更新。 本文系国内 ITOM 管理平台 OneAPM 工程师编译整理。

    本主题有以下两个步骤:

    1. 我们将创建一个示例应用程序来执行 CRUD 操作。

    2. 我们将使用 SignalR 类库让应用实时。

    那些不熟悉 SignalR 的,请访问我以前有关 SignalR 概述 的文章。

    第一步:

    我们需要创建一个名为 CRUD_Sample 的数据库。在示例数据库中创建一个名为 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 项目

    创建示例应用程序,我们需要 Visual Studio 2012 或更高版本,并且该服务器平台必须支持 .NET 4.5。

    步骤 1:

    Getting Started with MVC

    Step 2:

    Web application

    Step 3:

    select template

    点击 OK,Visual Studio 将会创建一个新的 ASP.NET 工程。

    使用通用类库

    使用通用功能,我们可以减少代码数量。

    namespace WebApplication1.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。

    IDisposable

    IDisposable接口提供了一种机制,释放非托管资源。

    where T : class

    这是制约泛型参数的一类。点击查看更多

    类型参数必须是引用类型;这也适用于任何类,接口,委托或数组类型。

    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 结构

    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 架构应用程序中使用通用库

    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 架构应用程序中使用视图

    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 中间件

    安装后需要创建 OwinStartup 类。

    下面的代码将一段简单中间件向 OWIN 管道,实现接收 Microsoft.Owin.IOwinContext 实例的功能。

    当服务器收到一个 HTTP 请求,OWIN 管道调用中间件。中间件设置内容类型的响应和写响应体。

    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();  
            }  
        }  
    }  
    

    创建使用 Hub 类

    完成前面的过程之后,创建一个 Hub。一个SignalR Hub 让从服务器到客户端连接,并从客户端到服务器的远程过程调用(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 的客户端部分,并告诉它执行 JavaScript 的 updatedData()方法。

    修改现有视图 Let’s Modify our Existing View

    修改一部分索引视图,将通过局部视图显示数据。

    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> 
    

    修改现有 Controller

    主 Controller:

    在主 Controller,我们将添加一个名为 GetAllDaTa()的方法。这是方法。

    [HttpGet]  
    public ActionResult GetAllData()  
    {  
        int Count = 10;  
        object[] parameters = {  
            Count  
        };  
        var test = objCust.GetAll(parameters);  
        return PartialView("_DataList", test);  
    }  
    

    在这里,返回局部视图返回的数据列表,且只返回空。

    // 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);  
        }  
    }  
    

    输出

    output

    希望能够帮助到您。

    OneAPM 助您轻松锁定 .NET 应用性能瓶颈,通过强大的 Trace 记录逐层分析,直至锁定行级问题代码。以用户角度展示系统响应速度,以地域和浏览器维度统计用户使用情况。想阅读更多技术文章,请访问 OneAPM 官方博客
    本文转自 OneAPM 官方博客

    原文地址: http://www.c-sharpcorner.com/UploadFile/302f8f/Asp-Net-mvc-real-time-app-with-signalr/

  • 相关阅读:
    怎样运用Oracle的BFILE
    第一个博客
    返回引用的函数
    c++之SQLite的增删改查
    sqlite命令行程序说明
    CreateProcess函数详解
    注册窗口类
    radio button的用法
    跨线程使用CSocket
    关于socket的connect超时的问题
  • 原文地址:https://www.cnblogs.com/oneapm/p/5238813.html
Copyright © 2011-2022 走看看