欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SingalR的简单认识

程序员文章站 2024-03-05 14:53:14
...

SingalR的简单认识

什么是 SignalR?

ASP.NET Core SignalR 是一种开放源代码库,可简化将实时 web 功能添加到应用程序的功能。 实时 web 功能使服务器端代码可以立即将内容推送到客户端。

适用于 SignalR 的场景:
  1. 需要从服务器进行高频率更新的应用。 示例包括游戏、社交网络、投票、拍卖、地图和 GPS 应用。
  2. 仪表板和监视应用。 示例包括公司仪表板、即时销售更新或旅行警报。
  3. 协作应用。 协作应用的示例包括白板应用和团队会议软件。
  4. 需要通知的应用。 社交网络、电子邮件、聊天、游戏、旅行警报和很多其他应用都需使用通知。
    SingalR的简单认识
Asp.net SignalR 2 实现 服务端消息推送到Web端, 更加简单. 为了获取更好的可伸缩性, 我们引入消息队列, 看如下基本流程图:

SingalR的简单认识
消息队列MQ监听, 在Web site 服务端一收到消息,马上通过Signalr 推送广播到客户端.

使用步骤

具体操作步骤:

以实现消息推送为示例

步骤一:

安装

Install-Package Microsoft.AspNet.SignalR

步骤二:

UPDATE-Package Microsoft.AspNet.SignalR -Version 2.4.0
UPDATE-Package jQuery -Version 1.8.2

步骤三:

创建一个集线器

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
//先在Nuget上搜索Microsoft.AspNet.SignalR安装
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace SignalRDEMO
{
    /// <summary>
    /// 自定义SignalR集线器代理类名称
    /// </summary>
    [HubName("myChatHub")]
    public class MyChatHub : Hub
    {
        /// <summary>
        /// 推送至所有客户端
        /// </summary>
        /// <param name="message">消息</param>
        public void Send(string message)
        {
            //调用所有客户端的SendMessage方法
            Clients.All.SendMessage(message);
        }
    }
}

步骤四:

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>SignalR实时消息推送到客户端</title>
    <script src="Scripts/jquery-1.8.2.js"></script>
    <!--引用SignalR库-->
    <script src="Scripts/jquery.signalR-2.1.2.min.js"></script>
    <!--引用自动生成的SignalR集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到-->
    <script src="/signalr/hubs" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            //引用服务端的集线器代理类       
            var chat = $.connection.myChatHub;
            //定义服务器端调用的客户端SendMessage方法来显示新消息
            chat.client.SendMessage = function (message) {                
                ShowMessage(message);
            };
            //$.extend(chat.client, {
            //    SendMessage: function (message) {
            //        ShowMessage(message);
            //    }
            //});

            //设置焦点到输入框
            $('#message').focus();

            //开始连接服务器
            $.connection.hub.start().done(function () {
                $('#SendMessage').click(function () {
                    //调用服务器端定义的Send方法
                    chat.server.send($('#message').val());
                    //清空输入框信息并获取焦点
                    $('#message').val('').focus();
                });
            });    
        });
        //向页面添加消息
        function ShowMessage(message) {                 
            $('#list').append('<li>' + message + '</li>');
        }      
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <input type="text" id="message" />
        <input type="button" id="SendMessage" value="发送" />
        <ul id="list">
        </ul>
    </div>
    </form>
</body>
</html>

步骤五:

添加启动类StartUp

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(SignalRChat.Startup))]
namespace SignalRChat
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Any connection or hub wire up and configuration should go here
            app.MapSignalR();
        }
    }
}
说明:

每一个使用的OWin组件的Web框架都需要一个StartUp入口类,用来声明OWin组件:

  1. 项目会自动扫描程序集根下的名为StartUp的类作为入口类

  2. 通过添加 [assembly: OwinStartup(typeof(SignalRDEMO.Startup))] 标签标记入口类

SingalR常用的推送方式

以下列出其他推送方式:

  • 所有连接的客户端  
    Clients.All.show(content);

  • 仅调用的客户端
    Clients.Caller.show(content);

  • 除调用客户端之外的所有客户端
    Clients.Others.show(content);

  • 特定的客户端标识的连接 id
    Clients.Client(Context.ConnectionId).show(content);

  • 所有连接的客户端除外指定客户端,由连接 ID 标识
    Clients.AllExcept(connectionId1, connectionId2).show(content);

  • 指定组中的所有连接的客户端
    Clients.Group(groupName).show(content);

  • 指定组中的所有连接的客户端除外指定客户端,由连接 ID 标识。
    Clients.Group(groupName, connectionId1, connectionId2).show(content);

  • 所有连接的客户端指定组中除调用客户端
    Clients.OthersInGroup(groupName).show(content);

  • 所有客户端和组列表中的连接 Id
    Clients.Clients(ConnectionIds).show(content);

  • 组的列表。
    Clients.Groups(GroupIds).show(content);

  • 按名称的用户
    Clients.Client(username).show(content); //这里的username我还没理解是怎么创建的

  • (在 SignalR 2.1 中引入) 的用户名称的列表。
    Clients.Users(new string[] { “myUser”, “myUser2” }).show(content)

这里关于ConnectionId做一下解释

每个连接的页面都会产生不同的连接id,并且这个连接id是随机产生,不能自定义的
集线器中为我们提供了Context对象可以获取到这个连接id,这里的id也就相当于用于验证身份的t唯一token一样。

        /// <summary>
        /// 返回每个连接的id
        /// </summary>
        public void ReturnConnectionId()
        {
            Clients.Caller.show(Context.ConnectionId);
        }
  //定义推送,返回各个客户端连接
        $.connection.hub.start()
            .done(function () {
                $("#btn_sendConnectionId").click(function () {
                    chat.server.returnConnectionId();  //将客户端的content内容发送到服务端
                });
        });
下面简单举一个应用SingalR的例子:

这里假设张三发送消息到服务器:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <script src="Scripts/jquery-3.4.1.min.js"></script>
    <script src="Scripts/jquery.signalR-2.2.2.min.js"></script>
    <script src="/signalr/hub/hubs"></script>
    <meta charset="utf-8" />
    <style type="text/css">
        body {
            margin: 20px;
        }

        .input {
            padding-left: 5px;
        }
    </style>
</head>
<body>
    <div>
        <h4>我是张三</h4>
        <p>
            <input type="text" id="content" placeholder="" class="input" />   <input type="button" value="发送给李四" class="btn btn-sm btn-info" id="btn_send" />
        </p>

        <div>
            <h4>接收到的信息:</h4>
            <ul id="dataContainer">
            </ul>
        </div>
    </div>

    <script language="javascript">
    $(function() {
        var chat = $.connection.myChatHub; //连接服务端集线器,de*b为服务端集线器名称,js上首字母须改为小写(系统默认)
        //定义客户端方法,此客户端方法必须与服务端集线器中的方法名称、参数均一致。
        //实际上是服务端调用了前端的js方法(订阅)

        $.connection.hub.qs = { 'userName': '张三' }
        chat.client.show=function(content) {
            var html = '<li>' + htmlEncode(content) + "</li>";
            $("#dataContainer").append(html);
        }

        //定义推送
        $.connection.hub.start()
            .done(function() {
                $("#btn_send").click(function() {
                    chat.server.callOne("李四",$("#content").val());  //将客户端的content内容发送到服务端
                    $("#content").val("");
                });
            });
    });
    //编码
    function htmlEncode(value) {
        var encodedValue = $('<div />').text(value).html();
        return encodedValue;
    }
    </script>
</body>
</html>

这里是李四发送消息:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <script src="Scripts/jquery-3.4.1.min.js"></script>
    <script src="Scripts/jquery.signalR-2.2.2.min.js"></script>
    <script src="/signalr/hub/hubs"></script>
    <meta charset="utf-8" />
    <style type="text/css">
        body {
            margin: 20px;
        }

        .input {
            padding-left: 5px;
        }
    </style>
</head>
<body>
    <div>
        <h4>我是李四</h4>
        <p>
            <input type="text" id="content" placeholder="" class="input" />   <input type="button" value="发送给张三" class="btn btn-sm btn-info" id="btn_send" />
        </p>

        <div>
            <h4>接收到的信息:</h4>
            <ul id="dataContainer"></ul>
        </div>
    </div>

    <script language="javascript">
    $(function() {
        var chat = $.connection.myChatHub; //连接服务端集线器,de*b为服务端集线器名称,js上首字母须改为小写(系统默认)
        //定义客户端方法,此客户端方法必须与服务端集线器中的方法名称、参数均一致。
        //实际上是服务端调用了前端的js方法(订阅)
        $.connection.hub.qs = { 'userName': '李四' }
        chat.client.show=function(content) {
            var html = '<li>' + htmlEncode(content) + "</li>";
            $("#dataContainer").append(html);
        }

        //定义推送
        $.connection.hub.start()
            .done(function() {
                $("#btn_send").click(function() {
                    chat.server.callOne("张三", $("#content").val());  //将客户端的content内容发送到服务端
                    $("#content").val("");
                });
            });
    });
    //编码
    function htmlEncode(value) {
        var encodedValue = $('<div />').text(value).html();
        return encodedValue;
    }
    </script>
</body>
</html>

这里是服务端代码:

/// <summary>
        /// 发送给指定连接
        /// </summary>
        /// <param name="toName"></param>
        /// <param name="content"></param>
        public void CallOne(string toName, string content)
        {
            //根据username获取对应的ConnectionId
            var connectionId = HttpContext.Current.Application[toName].ToString();
            Clients.Client(connectionId).show(content);
        }

        /// <summary>
        /// 初次连接
        /// </summary>
        /// <returns></returns>
        public override Task OnConnected()
        {
            string username = Context.QueryString["userName"]; //获取客户端发送过来的用户名
            string connectionId = Context.ConnectionId;
            HttpContext.Current.Application.Add(username, connectionId); //存储关系
            return base.OnConnected();
        }

简单实现了张三和李四两个人的实时通讯,可以看出,利用了SingalR,比使用WebSocket来说要简单很多。

乾坤未定,你我皆是黑马!!!