Asp.NET MVC 中使用 SignalR 实现推送功能详细讲解

本文参考:https://www.cnblogs.com/aaaaq/p/5929104.html  本文客户端wpf没有给出详细代码,本文经过亲自修改完整的呈现了演示。

  • 简介

  • Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架。它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请求或使用轮询技术来获取消息。

  • 可访问其官方网站:https://github.com/SignalR/ 获取更多资讯。

  • 二.asp.net SignalR 是什么?

  • Asp.net SignalR是微软为实现实时通信的一个类库。一般情况下,SignalR会使用JavaScript的长轮询(long polling)的方式来实现客户端和服务器通信,随着Html5中WebSockets出现,SignalR也支持WebSockets通信。另外SignalR开发的程序不仅仅限制于宿主在IIS中,也可以宿主在任何应用程序,包括控制台,客户端程序和Windows服务等,另外还支持Mono,这意味着它可以实现跨平台部署在Linux环境下。

  • SignalR内部有两类对象:

  • Http持久连接(Persisten Connection)对象:用来解决长时间连接的功能。还可以由客户端主动向服务器要求数据,而服务器端不需要实现太多细节,只需要处理PersistentConnection 内所提供的五个事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 即可。

  • Hub(集线器)对象:用来解决实时(realtime)信息交换的功能,服务端可以利用URL来注册一个或多个Hub,只要连接到这个Hub,就能与所有的客户端共享发送到服务器上的信息,同时服务端可以调用客户端的脚本。

  • SignalR将整个信息的交换封装起来,客户端和服务器都是使用JSON来沟通的,在服务端声明的所有Hub信息,都会生成JavaScript输出到客户端,.NET则依赖Proxy来生成代理对象,而Proxy的内部则是将JSON转换成对象。

  • SignalR既然是为实时而生的,这样就决定了其使用场所。具体适用情景有如下几点:

  • 聊天室,如在线客服系统,IM系统等

  • 股票价格实时更新

  • 消息的推送服务

  • 游戏中人物位置的实时推送

  • 目前,我所在公司在开发的就是在线客服系统。

  • 三实现机制

  • SignalR 的实现机制与 .NET WCF 或 Remoting 是相似的,都是使用远程代理来实现。在具体使用上,有两种不同目的的接口:PersistentConnection 和 Hubs,其中 PersistentConnection 是实现了长时间的 Javascript 轮询(类似于 Comet),Hub 是用来解决实时信息交换问题,它是利用 Javascript 动态载入执行方法实现的。SignalR 将整个连接,信息交换过程封装得非常漂亮,客户端与服务器端全部使用 JSON 来交换数据。

 

  • 下面就 Hubs 接口的使用来讲讲整个流程:

  • 1,在服务器端定义对应的 hub class;

  • 2,在客户端定义 hub class 所对应的 proxy 类;

  • 3,在客户端与服务器端建立连接(connection);

  • 4,然后客户端就可以调用 proxy 对象的方法来调用服务器端的方法,也就是发送 request 给服务器端;

  • 5,服务器端接收到 request 之后,可以针对某个/组客户端或所有客户端(广播)发送消息。

 

  • 使用Asp.net SignalR在Web端实现广播消息

  •  通过第二部分的介绍,相信大家对Asp.net SignalR有了一个初步的了解,接下来通过两个例子来让大家加深对SignalR运行机制的理解。第一个例子就是在Web端如何使用SignalR来实现广播消息。

  • 使用Visual Studio 2013,创建一个MVC工程

  • 通过Nuget安装SignalR包。右键引用-》选择管理Nuget程序包-》在出现的窗口中输入SignalR来找到SignalR包进行安装。

  • 安装SignalR成功后,SignalR库的脚本将被添加进Scripts文件夹下。具体如下图所示:

  • Asp.NET MVC 中使用 SignalR 实现推送功能详细讲解

  • Asp.NET MVC 中使用 SignalR 实现推送功能详细讲解

  •  向项目中添加一个SignalR集线器(v2)并命名为ServerHub。

  将下面代码填充到刚刚创建的ServerHub类中。

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    using Microsoft.AspNet.SignalR;

    namespace SignalDemo

    {

        //public class ServerHub : Hub

        //{

        //    public void Hello()

        //    {

        //        Clients.All.hello();

        //    }

        //}

        public class ServerHub : Hub

        {

            private static readonly char[] Constant =

            {

                ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’,

                ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’, ‘i’, ‘j’, ‘k’, ‘l’, ‘m’, ‘n’, ‘o’, ‘p’, ‘q’, ‘r’, ‘s’, ‘t’, ‘u’, ‘v’,

                ‘w’, ‘x’, ‘y’, ‘z’,

                ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘I’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘O’, ‘P’, ‘Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’,

                ‘W’, ‘X’, ‘Y’, ‘Z’

            };

            /// <summary>

            /// 供客户端调用的服务器端代码

            /// </summary>

            /// <param name=”message”></param>

            public void Send(string message)

            {

                var name = GenerateRandomName(4);

                // 调用所有客户端的sendMessage方法

                Clients.All.sendMessage(name, message);

                //1.发送给所有客户端

                //Clients.All.onMsg

                //2.发送给单一客户端

                //Clients.Client(_clientID).onMsg

                //3.发送给其他客户端

                //Clients.AllExcept(_clientID).onMsg

                //Clients.Ohther.onMsg

                //4.发送给当前客户端

                //Clients.Caller.onMsg

            }

            /// <summary>

            /// 产生随机用户名函数

            /// </summary>

            /// <param name=”length”>用户名长度</param>

            /// <returns></returns>

            public static string GenerateRandomName(int length)

            {

                var newRandom = new System.Text.StringBuilder(62);

                var rd = new Random();

                for (var i = 0; i < length; i++)

                {

                    newRandom.Append(Constant[rd.Next(62)]);

                }

                return newRandom.ToString();

            }

        }

    }

    创建一个Startup类,如果开始创建MVC项目的时候没有更改身份验证的话,这个类会默认添加的,如果已有就不需要重复添加了。按照如下代码更新Startup类。

    using Microsoft.Owin;

    using Owin;

    [assembly: OwinStartupAttribute(typeof(SignalDemo.Startup))]

    namespace SignalDemo

    {

        public partial class Startup

        {

            public void Configuration(IAppBuilder app)

            {

                app.MapSignalR();

                ConfigureAuth(app);

                

            }

        }

    }

    在Home控制器中创建一个Chat Action方法

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    using System.Web.Mvc;

    namespace SignalDemo.Controllers

    {

        public class HomeController : Controller

        {

            public ActionResult Index()

            {

                return View();

            }

            public ActionResult About()

            {

                ViewBag.Message = “Your application description page.”;

                return View();

            }

            public ActionResult Contact()

            {

                ViewBag.Message = “Your contact page.”;

                return View();

            }

            public ActionResult Chat()

            {

                return View();

            }

        }

    }

    在Views文件中Home文件夹中创建一个Chat视图,视图代码如下所示:

    @{

        ViewBag.Title = “Chat”;

    }

    <h2>Chat</h2>

    <div class=”container”>

        <input type=”text” id=”message” />

        <input type=”button” id=”sendmessage” value=”Send” />

        <input type=”hidden” id=”displayname” />

        <ul id=”discussion”></ul>

    </div>

    @section scripts

    {

        <!–引用SignalR库. –>

        <script src=”~/Scripts/jquery.signalR-2.2.1.min.js”></script>

        <!–引用自动生成的SignalR 集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到 –>

        <script src=”~/signalr/hubs”></script>

        <script>

            $(function () {

                // 引用自动生成的集线器代理

                var chat = $.connection.serverHub;

                // 定义服务器端调用的客户端sendMessage来显示新消息

                chat.client.sendMessage = function (name, message) {

                    // 向页面添加消息

                    $(‘

                        + ‘</strong>: ‘ + htmlEncode(message) + ‘</li>’);

                };

                // 设置焦点到输入框

                $(‘

                // 开始连接服务器

                $.connection.hub.start().done(function () {

                    $(‘

                        // 调用服务器端集线器的Send方法

                        chat.server.send($(‘

                        // 清空输入框信息并获取焦点

                        $(‘

                    });

                });

            });

            // 为显示的消息进行Html编码

            function htmlEncode(value) {

                var encodedValue = $(‘<div />’).text(value).html();

                return encodedValue;

            }

        </script>

    }

     修改App_Start文件夹内的RoutConfig类,将Action方法默认设置为Chat

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    using System.Web.Mvc;

    using System.Web.Routing;

    namespace SignalDemo

    {

        public class RouteConfig

        {

            public static void RegisterRoutes(RouteCollection routes)

            {

                routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”);

                routes.MapRoute(

                    name: “Default”,

                    url: “{controller}/{action}/{id}”,

                    defaults: new { controller = “Home”, action = “Chat”, id = UrlParameter.Optional }

                );

            }

        }

    }

    到此,我们的例子就实现完成了,接下来我们先来看看运行效果,之后再来解释到底SignalR是如何来完成广播消息的。运行的运行结果如下

    从运行结果,你可以发现,在任何一个窗口输入信息并发送,所有客户端将收到该消息。这样的效果在实际应用中很多,如QQ,一登录QQ的时候都会推送腾讯广告消息。

      看完了运行结果,接下来我们来分析下代码,进而来剖析下SignalR到底是如何工作的。

      按照B/S模式来看,运行程序的时候,Web页面就与SignalR的服务建立了连接,具体的建立连接的代码就是:$.connection.hub.start()。这句代码的作用就是与SignalR服务建立连接,后面的done函数表明建立连接成功后为发送按钮注册了一个click事件,当客户端输入内容点击发送按钮后,该Click事件将会触发,触发执行的操作为: chat.server.send($(‘

      看到这里,有人是否会有疑问,前面的实现都只用到了集线器对象,而没有用到持久连接对象。其实并不是如此,$.connection这句代码就是使用持久连接对象,当然你也可以在重新OnConnected方法来查看监控客户端的连接情况,更新的代码如下所示:

    1  public class ServerHub : Hub 2     { 3         private static readonly char[] Constant = 4         { 5             ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, 6             ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’, ‘i’, ‘j’, ‘k’, ‘l’, ‘m’, ‘n’, ‘o’, ‘p’, ‘q’, ‘r’, ‘s’, ‘t’, ‘u’, ‘v’, 7             ‘w’, ‘x’, ‘y’, ‘z’, 8             ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘I’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘O’, ‘P’, ‘Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, 9             ‘W’, ‘X’, ‘Y’, ‘Z’ 10         }; 11 12         /// <summary> 13         /// 供客户端调用的服务器端代码 14         /// </summary> 15         /// <param name=”message”></param> 16         public void Send(string message) 17         { 18             var name = GenerateRandomName(4); 19 20             // 调用所有客户端的sendMessage方法 21             Clients.All.sendMessage(name, message); 22         } 23 24         /// <summary> 25         /// 客户端连接的时候调用 26         /// </summary> 27         /// <returns></returns> 28         public override Task OnConnected() 29         { 30             Trace.WriteLine(“客户端连接成功”); 31             return base.OnConnected(); 32         } 33 34         /// <summary> 35         /// 产生随机用户名函数 36         /// </summary> 37         /// <param name=”length”>用户名长度</param> 38         /// <returns></returns> 39         public static string GenerateRandomName(int length) 40         { 41             var newRandom = new System.Text.StringBuilder(62); 42             var rd = new Random(); 43             for (var i = 0; i < length; i++) 44             { 45                 newRandom.Append(Constant[rd.Next(62)]); 46             } 47             return newRandom.ToString(); 48         } 49     }

     

      

    在第二部分介绍的时候说道,在服务端声明的所有Hub信息,都会生成JavaScript输出到客户端,为了验证这一点,可以在Chrome中F12来查看源码就明白了,具体如下图所示:

     看到上图,你也就明白了为什么Chat.cshtml页面需要引入”signalr/hubs”脚本库了吧。

      <!–引用SignalR库. –>

        <script src=”~/Scripts/jquery.signalR-2.2.1.min.js”></script>

        <!–引用自动生成的SignalR 集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到 –>

        <script src=”~/signalr/hubs”></script>

    五在桌面程序中如何使用Asp.net SignalR

       上面部分介绍了SignalR在Asp.net MVC 中的实现,这部分将通过一个例子来看看SignalR在WinForm是如何使用的。

    下面让我们看看SignalR客户端的实现。

    using System;

    using System.Collections.Generic;

    using System.ComponentModel;

    using System.Data;

    using System.Drawing;

    using System.Linq;

    using System.Net.Http;

    using System.Text;

    using System.Threading.Tasks;

    using System.Windows.Forms;

    using Microsoft.AspNet.SignalR.Client;

    namespace SignalRClient

    {

        public partial class Form1 : Form

        {

            const string ServerUri = “http://localhost:53094/signalr”;

            HubConnection _conn = new HubConnection(ServerUri, true);

            public IHubProxy _proxy { get; set; } //声明代理

            //界面

            public Form1()

            {

                InitializeComponent();

                // 窗口启动时开始连接服务

                ConnectAsync();

            }

            //启动服务

            private void ConnectAsync()

            {

                _proxy = _conn.CreateHubProxy(“ServerHub”); // 创建一个集线器代理对象

                try

                {

                    _conn.Start();

                    _proxy.On<string, string>(“sendMessage”, (name, message) =>

                    {

                        MessageBox.Show(name + message);

                        //  RichTextBoxConsole.AppendText(“” + name + message);

                    });

                }

                catch (HttpRequestException)

                {

                    // 连接失败

                    return;

                }

                TextBoxMessage.Focus();

                RichTextBoxConsole.AppendText(“连上服务:” + ServerUri + “\r”);

            }

            //发送

            private void ButtonSend_Click(object sender, EventArgs e)

            {

                // 通过代理来调用服务端的Send方法

                // 服务端Send方法再调用客户端的AddMessage方法将消息输出到消息框中

                //HubProxy.Invoke(“Send”, GenerateRandomName(4), TextBoxMessage.Text.Trim());

                //_conn.StateChanged += new Action<StateChange>(tgt =>

                //{

                //    if (((StateChange)tgt).NewState == Microsoft.AspNet.SignalR.Client.ConnectionState.Connected)

                //    {

                //        // t1 = Environment.TickCount;

                //        //客户端调用服务端的 Send() 方法,传入参数”Hello”         

                //        _proxy.Invoke(“send”, TextBoxMessage.Text.Trim());

                //    }

                //});

                _proxy.Invoke(“send”, TextBoxMessage.Text.Trim());

                //定义客户端的方法sendMessage()(有两个string类型的参数,当服务端调用sendMessage,需要传入2个string类型参数),

                //以这种格式定义方法服务端才能去调用

                TextBoxMessage.Text = String.Empty;

                TextBoxMessage.Focus();

            }

        }

    }

    更多技术关注

Asp.NET MVC 中使用 SignalR 实现推送功能详细讲解》来自互联网,仅为收藏学习,如侵权请联系删除。本文URL:http://www.hashtobe.com/205.html