Loading... ## <span style='color:#00BFFF'>前言</span> SignalR即时通讯在我们学校的"口袋刷题"中就有使用,使用场景是全服广播和1对1广播,当时写这个功能的时候查阅了很多资料,今天写的这篇文章即是对这个技术点的回顾,同时也是总结出来,以备不时之需。 ## <span style='color:#00BFFF'>创建MVC项目</span> 首先我们打开VS2019(当然其它的版本也可以。我只是赶了个时髦,有天心血来潮就给安装了),再依次点击[创建新项目] - [新建] - [项目] 后弹出如下界面: ![创建项目](http://www.jbea.cn/usr/uploads/2021/12/3077781135.png) 点击下一步之后,输入“项目名称”,“项目存放路径”,“解决方案名称”(全部均为自定义输入即可) ![配置新项目](http://www.jbea.cn/usr/uploads/2021/12/4231328103.png) 输入信息之后,点击“创建”按钮,然后再选择创建Web模板。 <div class="tip inlineBlock warning"> 模板选择空,当然也可以选择MVC 添加文件夹和核心引用勾选MVC即可 </div> ![选择创建模板](http://www.jbea.cn/usr/uploads/2021/12/1989588279.png) 选择好了之后,点击创建就可以进入到编辑界面了。 ![创建成功界面截图](http://www.jbea.cn/usr/uploads/2021/12/3392320228.png) ## <span style='color:#00BFFF'>添加Signal引用</span> 打开“项目资源管理器”,选择“引用”-“管理NuGet程序包”(电脑需要连接互联网)。 ![添加包引用](http://www.jbea.cn/usr/uploads/2021/12/520477916.png) 输入signal搜索关键字,选择对应的程序包和版本后,点击安装即可。【中途可能会有弹窗,按提示点击相关交互按钮即可完成安装】 ![查找SignalR](http://www.jbea.cn/usr/uploads/2021/12/1120081906.png) ## <span style='color:#00BFFF'>开始使用Signal</span> #### 创建Startup类 打开项目,找到“**App_Start**”文件夹,右键 - 【添加】-【新建项】。 ![添加新建项](http://www.jbea.cn/usr/uploads/2021/12/1624007702.png) 在弹出窗口中,选择,创建一个Startup类用于配置OWIN程序。(推荐使用搜索,更快的找到Startup类) ![创建Startup类](http://www.jbea.cn/usr/uploads/2021/12/2884743525.png) 编辑Startup类,在默认的代码中添加一行代码:`app.MapSignalR();` ``` using Microsoft.Owin; using Owin; using System; using System.Threading.Tasks; [assembly: OwinStartup(typeof(SignalRDemo.App_Start.Startup))] namespace SignalRDemo.App_Start { public class Startup { public void Configuration(IAppBuilder app) { // 有关如何配置应用程序的详细信息,请访问 https://go.microsoft.com/fwlink/?LinkID=316888 app.MapSignalR(); //此处添加一行代码即可 } } } ``` #### 创建集线器类 在项目环境中创建一个新的文件夹"Hubs",然后选择该文件夹,右键-【添加】-【新建项】- 选择【SignalR Hub Class (v2)】 (推荐使用搜索),输入集线器类名称(自定义输入即可)。 ![创建Hub Class](http://www.jbea.cn/usr/uploads/2021/12/820756922.png) 编写如下代码,用户类可以根据业务自由扩展: ``` using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; using System; using System.Collections.Generic; namespace SignalRDemo.Hubs { [HubName("messageHub")] //指定集线器名称 public class HubMessage : Hub { /// <summary> /// 静态用户列表 /// </summary> private IList<string> userList = UserInfo.userList; /// <summary> /// 用户的connectionID与用户名对照表 /// </summary> private readonly static Dictionary<string, string> _connections = new Dictionary<string, string>(); /// <summary> /// 用户上线函数,用户上线之后将用户姓名和ConnectionId绑定,实际使用中可以用唯一的标识来绑定ConnectionId /// </summary> /// <param name="name"></param> public void sendLogin(string name) { IHubContext chat = GlobalHost.ConnectionManager.GetHubContext<HubMessage>(); if (!userList.Contains(name)) { userList.Add(name); //这里便是将用户id和姓名联系起来 _connections.Add(name, Context.ConnectionId); } else { //每次登陆id会发生变化 _connections[name] = Context.ConnectionId; } //新用户上线,服务器广播该用户名 Clients.All.loginUser(userList); //通知用户上线 chat.Clients.All.senloginuser(name); } /// <summary> /// 发送给指定接受者 /// </summary> /// <param name="sendname">发送者唯一ID</param> /// <param name="toName">接受者唯一ID</param> /// <param name="content">发送内容</param> public void callOne(string sendname, string toName, string content) { try { IHubContext chat = GlobalHost.ConnectionManager.GetHubContext<HubMessage>(); //根据username获取对应的ConnectionId var connectionId = _connections[toName]; chat.Clients.Client(connectionId).callmessage(content); } catch (Exception) { } } /// <summary> /// 全员广播 /// </summary> /// <param name="message"></param> public void sendmessage(string message) { IHubContext chat = GlobalHost.ConnectionManager.GetHubContext<HubMessage>(); chat.Clients.All.sendallmessage(message); } /// <summary> /// 除了自己广播所有人 /// </summary> /// <param name="name"></param> /// <param name="message"></param> public void sendallother(string name, string message) { IHubContext chat = GlobalHost.ConnectionManager.GetHubContext<HubMessage>(); var connectionId = _connections[name]; chat.Clients.AllExcept(connectionId).addotherMessage(message); } } /// <summary> /// 用户列表 【根据需求自行扩展】 /// </summary> public class UserInfo { public static IList<string> userList = new List<string>(); } } ``` #### 客户端调用SignalR 因为我创建的是空模板,这里还需要添加控制器和页面视图。【操作步骤没有截图了,这个应该都会吧】 Index.cshtml代码如下: ``` @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>SignalR-Demo</title> <script src="~/Scripts/jquery-1.6.4.min.js"></script> <!--重点:此处需要引入SignalR的脚本文件,文件位于:Scripts中,直接扩拽过来即可--> <script src="~/Scripts/jquery.signalR-2.4.2.min.js"></script> <!--重点:注册脚本信息,必须这样写--> <script src="~/signalr/hubs"></script> <script type="text/javascript"> $(function () { //获取聊天内容显示模板 var $messageBox = $("#messageBox"); $.connection.hub.logging = true; //实例化通信组件 [首字母必须小写,与集线器中的别名一直] var work = $.connection.messageHub; var nickName; //输入昵称后,建立链接 $("#start").click(function () { nickName = $("input[name='nickname']").val(); if (nickName == "") return; //建立链接 $.connection.hub.start().done(function () { //发送上线信息 work.server.sendLogin(nickName); $(".check-nickname").hide(); $(".message-area").show(); }); //修改浏览器页面标题 $("title").text("欢迎你:" + nickName); }) //发送信息 $("#send-message").click(function () { var msg = $("#message").val(); //获取聊天文本 if (!msg) return; //拼接数据 var sendMsg = `[${nickName}]-[${new Date().toLocaleDateString() + " " + new Date().toLocaleTimeString()}]-[${msg}]`; //发送到服务器 work.server.sendmessage(sendMsg); //清空发送框 $("#message").val(""); }) //接收全频广播 work.client.sendallmessage = function (msg) { //msg为服务器发送过来的信息 var arr = msg.substring(1, msg.length - 1).split("]-["); var nickname = arr[0]; var time = arr[1]; var text = arr[2]; //处理msg $messageBox.find(".nick-name").text(nickname).end().find(".send-time").text(time).end().find(".content").text(text); $(".message-list").append($messageBox.html()); } //接收除自身之外的全频广播 work.client.addotherMessage = function (msg) { //msg为服务器发送过来的信息 } //接收1对1广播 work.client.callmessage = function (msg) { //msg为服务器发送过来的信息 } }) </script> <style type="text/css"> * { outline: none } #messageBox, .message-area { display: none; } .message-area, .check-nickname { width: 400px; margin: 0 auto; } .check-nickname { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); } #message { width: 400px; height: 80px; display: block; margin: 10px auto 0; border: 2px solid #0081ff; line-height: 28px; font-size: 14px; font-family: "Microsoft YaHei"; padding-left: 6px; } button { border-radius: 5px; border: none; color: #fff; width: 100px; height: 36px; line-height: 36px; background-image: linear-gradient(45deg,#0081ff,#1cbbb4); cursor: pointer; vertical-align: middle; float: right; display: block; margin: 10px 0; } label { line-height: 28px; } input[name='nickname'] { box-sizing: border-box; width: 400px; display: block; line-height: 28px; margin: 0 auto; padding-left: 6px; } .message-list { height: 300px; overflow: auto; } .nick-name { background-color: #cce6ff; padding: 2px 4px; border-radius: 6px; color: #0081ff; font-size: 14px; font-weight: 900; vertical-align: middle; } .send-time { padding: 2px 4px; color: #1cbbb4; font-size: 12px; font-weight: 200; vertical-align: middle; } .content { display: block; line-height: 26px; font-size: 16px; background: #f0f0f0; color: #333; padding: 5px 10px; border-radius: 5px; margin: 4px 0; } .msg-title { margin: 12px 0 5px; } </style> </head> <body> <!--验证昵称--> <div class="check-nickname"> <label>请先注册使用一个聊天用的昵称吧:</label> <input type="text" name="nickname" value="" placeholder="请输入您的聊天昵称" /> <button id="start">开启聊天</button> </div> <!--聊天内容[默认隐藏,输入昵称后显示]--> <section class="message-area"> <!--消息列表--> <div class="message-list"> </div> <!--发送区域--> <div> <label>聊天内容:</label> <textarea id="message" placeholder="请输入您的聊天内容"></textarea> <button id="send-message">立即发送</button> </div> </section> <!--信息模板--> <div id="messageBox"> <div class="msg-title"><span class="nick-name">发送人</span> <span class="send-time">发送时间</span></div> <div class="content">聊天内容</div> </div> </body> </html> ``` 编写完毕之后就可以Run起来了,经过测试,可以正常跑通。 代码已经上传,打开后需要还原NuGet程序包,还原NuGet程序包可以参与如下操作: > 从模板创建项目或生成项目时,是否自动执行程序包还原取决于[启用和禁用程序包还原](https://docs.microsoft.com/zh-cn/nuget/consume-packages/package-restore#enable-and-disable-package-restore-in-visual-studio)中的选项。 此外,在 NuGet 4.0+ 中,对 SDK 样式的项目(通常是 .NET Core 或 .NET Standard 项目)进行更改时还会自动进行还原。 > > 1. 通过选择 "工具选项" NuGet 程序包管理器 ,然后选择 "包还原" 下的 "在生成过程中自动检查是否缺少Visual Studio**包还原** 。 > 对于非 SDK 样式项目,首先需要选择“允许 NuGet 下载缺少的程序包”,以启动自动还原选项。 > 2. 生成项目。 > 如果仍未正确安装一个或多个单独的包,“解决方案资源管理器”会显示错误图标 。 右键单击并选择“管理 NuGet 包”,然后使用“包管理器”卸载并重新安装受影响的包 。 有关详细信息,请参阅[重新安装和更新包](https://docs.microsoft.com/zh-cn/nuget/consume-packages/reinstalling-and-updating-packages)。 > 如果看到错误“此项目引用此计算机上缺少的 NuGet 包”或者“一个或更多 NuGet 包需要还原但无法还原,因为未授予许可”,则[启用自动还原](https://docs.microsoft.com/zh-cn/nuget/consume-packages/package-restore#enable-and-disable-package-restore-in-visual-studio)。 对于旧项目,亦请参阅[迁移到自动程序包还原](https://docs.microsoft.com/zh-cn/nuget/consume-packages/package-restore#migrate-to-automatic-package-restore-visual-studio)。 另请参阅[程序包还原疑难解答](https://docs.microsoft.com/zh-cn/nuget/consume-packages/package-restore-troubleshooting)。 更多详情,请访问:https://docs.microsoft.com/zh-cn/nuget/consume-packages/package-restore#restore-using-visual-studio 案例下载:[SignalRDemo.zip](http://www.jbea.cn/usr/uploads/2021/12/2856326136.zip) 如有任何疑问,请留言让我知道~ 最后修改:2021 年 12 月 18 日 © 允许规范转载 赞 都滑到这里了,不点赞再走!?
3 条评论
我觉的蛮好的
这里面为了演示方便,样式采用了内部样式
有有有由于