翼度科技»论坛 编程开发 .net 查看内容

ASP.NET Core SignalR 入门

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
本章将和大家分享使用 SignalR 生成实时应用的基础知识。通过本文您将学习如何:使用ASP.NET Core SignalR + MVC + Vue 2.x + require 最终创建一个正常运行的简易聊天应用。
废话不多说,我们直接来看一个Demo,Demo的目录结构如下所示:

本Demo的Web项目为ASP.NET Core Web 应用程序(目标框架为.NET 7.0) MVC项目。  
1、创建 SignalR 中心

中心是一个类,用作处理客户端 - 服务器通信的高级管道。
可通过已连接客户端调用 SendMessage,以向所有客户端发送消息。
  1. using Microsoft.AspNetCore.SignalR;
  2. namespace SignalRChat.Hubs
  3. {
  4.     /// <summary>
  5.     /// Hub 类管理连接、组和消息
  6.     /// </summary>
  7.     public class ChatHub : Hub
  8.     {
  9.         /// <summary>
  10.         /// 可通过已连接客户端调用 SendMessage,以向所有客户端发送消息
  11.         /// </summary>
  12.         public async Task SendMessage(string user, string message)
  13.         {
  14.             //Clients.All 向所有的客户端发送消息(服务端调用客户端)
  15.             //ReceiveMessage 是客户端监听的方法
  16.             await Clients.All.SendAsync("ReceiveMessage", user, message);
  17.             /*
  18.                 // 常用方法
  19.                 // 给所有人发送消息
  20.                 await Clients.All.SendAsync("ReceiveMessage", data);
  21.                 // 给组里所有人发消息
  22.                 await Clients.Group("Users").SendAsync("ReceiveMessage", data);
  23.                 // 给调用方法的那个人发消息
  24.                 await Clients.Caller.SendAsync("ReceiveMessage", data);
  25.                 // 给除了调用方法的以外所有人发消息
  26.                 await Clients.Others.SendAsync("ReceiveMessage", data);
  27.                 // 给指定connectionId的人发消息
  28.                 await Clients.User(connectionId).SendAsync("ReceiveMessage", data);
  29.                 // 给指定connectionId的人发消息
  30.                 await Clients.Client(connectionId).SendAsync("ReceiveMessage", data);
  31.                 // 给指定connectionId的人发消息,同时指定多个connectionId
  32.                 await Clients.Clients(IReadOnlyList<> connectionIds).SendAsync("ReceiveMessage", data);
  33.             */
  34.         }
  35.     }
  36. }
复制代码
2、配置 SignalR

必须将 SignalR 服务器配置为将 SignalR 请求传递给 SignalR。 将以下突出显示(标红)的代码添加到 Program.cs 文件。
  1. using SignalRChat.Hubs;
  2. namespace SignalRChat
  3. {
  4.     public class Program
  5.     {
  6.         public static void Main(string[] args)
  7.         {
  8.             var builder = WebApplication.CreateBuilder(args);
  9.             //服务注册(往容器中添加服务)
  10.             // Add services to the container.
  11.             builder.Services.AddControllersWithViews();
  12.             builder.Services.AddSignalR(); //SignalR
  13.             var app = builder.Build();
  14.             //配置Http请求处理管道
  15.             // Configure the HTTP request pipeline.
  16.             if (!app.Environment.IsDevelopment())
  17.             {
  18.                 app.UseExceptionHandler("/Home/Error");
  19.             }
  20.             app.UseStaticFiles();
  21.             app.UseRouting();
  22.             app.UseAuthorization();
  23.             //配置MVC路由
  24.             app.MapControllerRoute(
  25.                 name: "areas",
  26.                 pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
  27.             app.MapControllerRoute(
  28.                 name: "default",
  29.                 pattern: "{controller=Home}/{action=Index}/{id?}");
  30.             app.MapHub<ChatHub>("/chatHub"); //SignalR
  31.             app.Run();
  32.         }
  33.     }
  34. }
复制代码
以上突出显示(标红)的代码将 SignalR 添加到 ASP.NET Core 依赖关系注入和路由系统。
3、添加 SignalR 客户端代码

chat.js 文件,核心 JavaScript 代码如下:
  1. //第一个参数:加载依赖模块,可以是require_config中定义的短模块名,也可以是完整的模块路径(去掉.js后缀名,根目录为require_config中设置的baseUrl)
  2. //第二个参数:执行加载完后的回调函数
  3. require(['../common/base', 'jquery', 'signalr'], function (base, $, signalR) {
  4.     let axios = base.axios;
  5.     var vm = new base.vue({
  6.         el: '#app', //挂载点
  7.         mixins: [base.mixin], //混入,类似基类的概念
  8.         data: {
  9.             connectionSignalR: '', //SignalR连接
  10.             user: '',
  11.             message: '',
  12.             msgList: []
  13.         },
  14.         //created钩子函数
  15.         created: function () {
  16.             this.initSignalR(); //初始化SignalR
  17.         },
  18.         //mounted钩子函数
  19.         mounted: function () {
  20.             //console.log('This is index mounted');
  21.         },
  22.         //方法
  23.         methods: {
  24.             //初始化SignalR
  25.             initSignalR: function () {
  26.                 var _this = this;
  27.                 //创建连接
  28.                 _this.connectionSignalR = new signalR.HubConnectionBuilder()
  29.                     .withUrl("/chatHub")
  30.                     .configureLogging(signalR.LogLevel.Error)
  31.                     .build();
  32.                 /*
  33.                     日志等级:
  34.                     signalR.LogLevel.Error:错误消息。 Error仅记录消息。
  35.                     signalR.LogLevel.Warning:有关潜在错误的警告消息。 日志 Warning 和 Error 消息。
  36.                     signalR.LogLevel.Information:无错误的状态消息。 日志 Information 、 Warning 和 Error 消息。
  37.                     signalR.LogLevel.Trace:跟踪消息。 记录所有内容,包括中心和客户端之间传输的数据。
  38.                 */
  39.                 //监听中心(服务端)发送的消息(服务端调用客户端)
  40.                 //ReceiveMessage 是服务端调用客户端的方法名
  41.                 _this.connectionSignalR.on("ReceiveMessage", function (user, message) {
  42.                     _this.msgList.push({
  43.                         user: user,
  44.                         message: message
  45.                     });
  46.                 });
  47.                 //启动连接
  48.                 _this.connectionSignalR.start().then(function () {
  49.                     //启动连接后需要立即执行的逻辑
  50.                     //document.getElementById("sendButton").disabled = false;
  51.                 }).catch(function (err) {
  52.                     return console.error(err.toString());
  53.                 });
  54.             },
  55.             //发送消息
  56.             sendMsg: function () {
  57.                 var _this = this;
  58.                 if (_this.message) {
  59.                     //向中心(服务端)发送消息(客户端调用服务端)
  60.                     //SendMessage 是服务端定义的的方法
  61.                     _this.connectionSignalR.invoke("SendMessage", _this.user, _this.message).catch(function (err) {
  62.                         return console.error(err.toString());
  63.                     });
  64.                     _this.message = ''; //发送完清空消息
  65.                 }
  66.             },
  67.         }
  68.     });
  69. });
复制代码
公共脚本文件代码如下:
其中 require_config.js 文件代码如下:
  1. //主要用来配置模块的加载位置(设置短模块名)
  2. require.config({
  3.     baseUrl: '/js/lib', //设置根目录
  4.     paths: { //如果没有设置根目录则需要填写完整路径
  5.         'vue': 'vue',
  6.         'axios': 'axios',
  7.         'jquery': 'jquery-3.6.3',
  8.         'signalr': 'signalr',
  9.         //paths还有一个重要的功能,就是可以配置多个路径,如果远程cdn库没有加载成功,可以加载本地的库,如下:
  10.         //'jquery': ['http://libs.baidu.com/jquery/2.0.3/jquery', '/js/lib/jquery-3.6.3'],
  11.     }
  12. });
复制代码
其中 base.js 文件代码如下:
  1. //define用来自定义模块
  2. //第一个参数:加载依赖模块,可以是require_config中定义的短模块名,也可以是完整的模块路径(去掉.js后缀名)
  3. //第二个参数:执行加载完后的回调函数
  4. define(['vue', 'axios', '../components/buttonCounter'], function (vue, axios, buttonCounter) {
  5.     //TODO 此处可以处理一些公共的逻辑
  6.     //vue.component('component-a', { /* ... */ }); //全局注册组件
  7.     //vue.mixin({...}); //全局混入
  8.     /*
  9.         定义组件名的方式有两种:
  10.         1、使用 kebab-case (短横线分隔命名)
  11.             当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如 <my-component-name>
  12.         
  13.         2、使用 PascalCase (首字母大写命名)
  14.             当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。
  15.             也就是说 <my-component-name> 和 <MyComponentName> 都是可接受的。
  16.             注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。   
  17.     */
  18.     //Vue.component(...) 的第一个参数为组件名。      
  19.     vue.component('button-counter', buttonCounter); //全局注册
  20.     return {
  21.         vue: vue,
  22.         axios: axios,
  23.         //Vue混入
  24.         mixin: {
  25.             //数据
  26.             data: function () {
  27.                 return {
  28.                     domain: '', //域名
  29.                 }
  30.             },
  31.             //组件
  32.             components: {
  33.             },
  34.             //created钩子函数
  35.             created: function () {
  36.                 //console.log('This is base created');
  37.                 var _this = this;
  38.                 _this.getDomain();
  39.             },
  40.             //mounted钩子函数
  41.             mounted: function () {
  42.                 console.log('This is base mounted');
  43.             },
  44.             //方法
  45.             methods: {
  46.                 //测试
  47.                 doTest: function () {
  48.                     console.log('This is base doTest');
  49.                 },
  50.                 //获取域名
  51.                 getDomain: function () {
  52.                     var _this = this;
  53.                     _this.domain = 'http://localhost:5296';
  54.                 },
  55.             }
  56.         },
  57.     };
  58. });
复制代码
控制器和视图文件代码如下:
其中 HomeController 控制器代码如下:
  1. using Microsoft.AspNetCore.Mvc;
  2. using SignalRChat.Models;
  3. using System.Diagnostics;
  4. namespace SignalRChat.Controllers
  5. {
  6.     public class HomeController : Controller
  7.     {
  8.         private readonly ILogger<HomeController> _logger;
  9.         public HomeController(ILogger<HomeController> logger)
  10.         {
  11.             _logger = logger;
  12.         }
  13.         public IActionResult Index()
  14.         {
  15.             return View();
  16.         }
  17.     }
  18. }
复制代码
其中布局页 _Layout.cshtml 视图文件代码如下:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="utf-8" />
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6.     <title>@ViewData["Title"] - SignalRChat</title>
  7.    
  8.    
  9.     @await RenderSectionAsync("header", required: false)
  10. </head>
  11. <body>
  12.    
  13.         @RenderBody()
  14.    
  15.     @await RenderSectionAsync("footer", required: false)
  16. </body>
  17. </html>
复制代码
其中 Index.cshtml 视图文件代码如下:
  1. @{
  2.     ViewData["Title"] = "Home Page";
  3. }
  4.     <template>
  5.         <p>
  6.             User:<input v-model="user" type="text" />
  7.         </p>
  8.         <p>
  9.             Message: <input v-model="message" type="text" />
  10.         </p>
  11.         <p>
  12.             <button v-on:click="sendMsg">发送</button>
  13.         </p>
  14.         <hr />
  15.         <ul>
  16.             <li v-for="(item, index) in msgList" :key="index">
  17.                 {{ item.user }} says {{ item.message }}
  18.             </li>
  19.         </ul>
  20.     </template>
  21. @section footer{
  22.    
  23. }
复制代码
4、运行应用

此处我使用的是 .NET Core CLI  命令行的方式来运行应用,如下所示:

打开两个浏览器实例,分别访问:http://localhost:5296/ , 运行结果如下:

选择任一浏览器,输入名称和消息,然后点击“发送”按钮:

可以发现,两个页面上会立即显示名称和消息。 
更多关于 ASP.NET Core SignalR 的相关知识可参考微软官方文档:https://learn.microsoft.com/zh-cn/aspnet/core/tutorials/signalr?view=aspnetcore-7.0&tabs=visual-studio
至此本文就全部介绍完了,如果觉得对您有所启发请记得点个赞哦!!!
 
Demo源码:
  1. 链接:https://pan.baidu.com/s/13ppUjr0h2dse5vnw5uiZ9Q
  2. 提取码:qm2a
复制代码
此文由博主精心撰写转载请保留此原文链接:https://www.cnblogs.com/xyh9039/p/17520659.html
版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!

来源:https://www.cnblogs.com/xyh9039/archive/2023/07/02/17520659.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具