如何在 Asp.Net.Core Mvc Signalr 中制作一对一聊天系统?

如何解决如何在 Asp.Net.Core Mvc Signalr 中制作一对一聊天系统?

我想用 Mssql 数据库实现私人聊天系统。当我发送消息时,此代码公开工作,消息出现在所有客户端。但是我想要一对一的聊天系统。一位用户输入存储在数据库中的接收者 ID 和消息文本,然后将消息发送到 Receiver 。然后该消息出现在具有该接收者 ID 的接收者消息区域中。

这是我的js代码

"use strict";

var connection = new signalR.HubConnectionBuilder().withUrl("/chathub").build();

//Disable send button until connection is established
document.getElementById("sendButton").disabled = true;

connection.start().then(function () {
    document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
    return console.error(err.toString());
});

document.getElementById("sendButton").addEventListener("click",function (event) {
    var user = document.getElementById("userInput").value;
    var message = document.getElementById("messageInput").value;
    connection.invoke("SendMessage",user,message).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});
connection.on("ReceiveMessage",function (user,message) {
    var msg = message.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
    var encodedMsg = user + ":" + msg;
    var li = document.createElement("li");
    li.textContent = encodedMsg;
    document.getElementById("messagesList").appendChild(li);
});

这是我的枢纽班

using MentorShip.Models;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;

using System.Threading.Tasks;

namespace MentorShip.Hubs
{
    public class SignalRChat:Hub
    {
        Context c = new Context();
        
        public async Task SendMessage(string user,string message)
        {
           
            await  Clients.All.SendAsync("ReceiveMessage",message);
        }

    }
}

这是我的html代码

            <div class="container">
            <div class="row">&nbsp;</div>
            <div class="row">
                <div id="connectionId"></div>
                <div class="col-2">Receiver Id</div>
                <div class="col-4"><input type="text" id="userInput" /></div>
            </div>
            <div class="row">
                <div class="col-2">Message</div>
                <div class="col-4"><input type="text" id="messageInput" /></div>
            </div>
            <div class="row">&nbsp;</div>
            <div class="row">
                <div class="col-6">
                    <input type="button" id="sendButton" value="Send Message" />
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col-12">
                <hr />
            </div>
        </div>
        <div class="row">
            <div class="col-6">
                <ul id="messagesList"></ul>
            </div>
        </div>
    </div>

解决方法

要将消息发送给特定用户,您可以使用以下方法:

  1. 使用单用户组

    您可以为每个用户创建一个群组,然后在您只想联系该用户时向该群组发送消息。每个组的名称是用户的名称。如果一个用户有多个连接,每个连接 id 都会被添加到用户的组中。

    例如,基于 getting start document,我创建了一个 SignalR 应用程序,它将向所有用户发送消息。然后,在 ChatHub 类中,添加 Authorize 属性并覆盖 OnConnectedAsync() 方法,在 OnConnectedAsync 方法中,我们可以基于身份用户创建一个组。然后,添加一个 SendMessageToGroup 方法将消息发送到组。

     [Authorize]
     public class ChatHub : Hub
     {  
         public override Task OnConnectedAsync()
         { 
             Groups.AddToGroupAsync(Context.ConnectionId,Context.User.Identity.Name);
             return base.OnConnectedAsync();
         }
         public async Task SendMessage(string user,string message)
         {
             await Clients.All.SendAsync("ReceiveMessage",user,message);
         }
    
         public Task SendMessageToGroup(string sender,string receiver,string message)
         {
             return Clients.Group(receiver).SendAsync("ReceiveMessage",sender,message);
         }  
     }
    

    在Index.cshtml页面添加Receiver input元素,输入接收者名称(与组名相同)。

     <div class="container">
         <div class="row">&nbsp;</div>
         <div class="row">
             <div class="col-2">Sender</div>
             <div class="col-4"><input type="text" id="senderInput" /></div>
         </div>
         <div class="row">
             <div class="col-2">Receiver</div>
             <div class="col-4"><input type="text" id="receiverInput" /></div>
         </div>
         <div class="row">
             <div class="col-2">Message</div>
             <div class="col-4"><input type="text" id="messageInput" /></div>
         </div>
         <div class="row">&nbsp;</div>
         <div class="row">
             <div class="col-6">
                 <input type="button" id="sendButton" value="Send Message" />
             </div>
         </div>
     </div>
    

    然后,更新chat.js文件中的sendButton点击事件:

     document.getElementById("sendButton").addEventListener("click",function (event) {
         var sender = document.getElementById("senderInput").value;
         var receiver = document.getElementById("receiverInput").value;
         var message = document.getElementById("messageInput").value;
    
         if (receiver !="") {
    
             connection.invoke("SendMessageToGroup",receiver,message).catch(function (err) {
                 return console.error(err.toString());
             });
         }
         else { 
             connection.invoke("SendMessage",message).catch(function (err) {
                 return console.error(err.toString());
             });
         }
         event.preventDefault();
     });
    

    之后,我们就可以向特定用户发送消息,截图如下(如果接收者为空,它将向所有用户发送消息,否则将向特定用户发送消息):

    enter image description here

  2. 通过 ConnectionID 发送消息。

    从上面的示例代码中,在 OnConnectedAsyc 方法中,我们可以获取 ConnectId 和用户名,然后,您可以将它们存储在数据库中。然后,您可以在 ChatHub.cs 中添加 SendMessageToUser 方法。在此方法中,您可以查询数据库并根据接收者名称找到 connectionId,然后使用 Clients.Client("connectionId").SendAsync() 方法将消息发送给特定用户。

     public Task SendMessageToUser(string sender,string message)
     {
         //based on the receiver name to query the database and get the connection id
    
         return Clients.Client("connectionId").SendAsync("ReceiveMessage",message);
     }
    

这里有一些相关的文章,你可以参考:

Use hubs in SignalR for ASP.NET Core

Mapping SignalR Users to Connections

更新

详细步骤:

  1. 打开 Visual Studio 2019(最新版本),创建一个 Asp.net Core Web 应用程序(命名为 SignalRApp,使用 .net core 3.1 版本):

    选择 MVC 模板并将身份验证更改为“个人用户帐户”。

    enter image description here

  2. 在包管理器控制台工具中使用以下命令。更多详细信息,请查看EF Core Migrations

    add-migration InitialCreate
    update-database

  3. 之后,我们可以运行应用程序并注册用户。登录截图如下:

    enter image description here

  4. 添加 SignalR 客户端库

    • 在解决方案资源管理器中,右键单击项目,然后选择添加 > 客户端库
    • 添加客户端库对话框中,为提供商选择unpkg
    • 对于库,输入 @microsoft/signalr@latest
    • 选择选择特定文件,展开 dist/browser 文件夹,然后选择 signalr.js 和 signalr.min.js。
    • 将目标位置设置为 wwwroot/js/signalr/,然后选择安装。 LibMan 创建一个 wwwroot/js/signalr 文件夹并将选定的文件复制到其中。
  5. 创建 SignalR 中心。

    在项目文件夹中,创建一个 Hubs 文件夹并添加一个 ChatHub.cs 文件,代码如下:

     namespace SignalRApp.Hubs
     {
         //require using Microsoft.AspNetCore.SignalR;
         //require using Microsoft.AspNetCore.Authorization;
         [Authorize]
         public class ChatHub : Hub
         {
             public override Task OnConnectedAsync()
             {
                 Groups.AddToGroupAsync(Context.ConnectionId,Context.User.Identity.Name);
                 return base.OnConnectedAsync();
             }
             public async Task SendMessage(string user,string message)
             {
                 await Clients.All.SendAsync("ReceiveMessage",message);
             }
    
             public Task SendMessageToGroup(string sender,string message)
             {
                 return Clients.Group(receiver).SendAsync("ReceiveMessage",message);
             }
         }
     }
    
  6. 在 Startup.cs 文件中配置 SignalR。你可以检查this article

    startup.cs 文件如下:

     public class Startup
     {
         public Startup(IConfiguration configuration)
         {
             Configuration = configuration;
         }
    
         public IConfiguration Configuration { get; }
    
         // This method gets called by the runtime. Use this method to add services to the container.
         public void ConfigureServices(IServiceCollection services)
         {
             services.AddDbContext<ApplicationDbContext>(options =>
                 options.UseSqlServer(
                     Configuration.GetConnectionString("DefaultConnection")));
             services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
                 .AddEntityFrameworkStores<ApplicationDbContext>();
             services.AddControllersWithViews();
             services.AddRazorPages();
    
             services.AddSignalR(); 
         }
    
         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
         public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
         {
             if (env.IsDevelopment())
             {
                 app.UseDeveloperExceptionPage();
                 app.UseDatabaseErrorPage();
             }
             else
             {
                 app.UseExceptionHandler("/Home/Error");
                 // The default HSTS value is 30 days. You may want to change this for production scenarios,see https://aka.ms/aspnetcore-hsts.
                 app.UseHsts();
             }
             app.UseHttpsRedirection();
             app.UseStaticFiles();
    
             app.UseRouting();
    
             app.UseAuthentication();
             app.UseAuthorization();
    
             app.UseEndpoints(endpoints =>
             {
                 endpoints.MapControllerRoute(
                     name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");
                 endpoints.MapRazorPages();
                 endpoints.MapHub<ChatHub>("/chathub");
             });
         }
     }
    
  7. 添加 SignalR 客户端代码:

    [注意] 这一步请注意js文件路径。如果js文件加载不成功,客户端代码将无法运行。

    在 Home controller Index 页面(Index.cshtml)中,替换如下内容:

     @{
         ViewData["Title"] = "Index";
     }
    
     <h1>Index</h1>
    
     <div class="container">
         <div class="row">&nbsp;</div>
         <div class="row">
             <div class="col-2">Sender</div>
             <div class="col-4"><input type="text" id="senderInput" /></div>
         </div>
         <div class="row">
             <div class="col-2">Receiver</div>
             <div class="col-4"><input type="text" id="receiverInput" /></div>
         </div>
         <div class="row">
             <div class="col-2">Message</div>
             <div class="col-4"><input type="text" id="messageInput" /></div>
         </div>
         <div class="row">&nbsp;</div>
         <div class="row">
             <div class="col-6">
                 <input type="button" id="sendButton" value="Send Message" />
             </div>
         </div>
     </div>
     <div class="row">
         <div class="col-12">
             <hr />
         </div>
     </div>
     <div class="row">
         <div class="col-6">
             <ul id="messagesList"></ul>
         </div>
     </div>
     <script src="~/js/signalr/dist/browser/signalr.js"></script>
     <script src="~/js/chat.js"></script>
    

    在 wwwroot/js 文件夹中,使用以下代码创建一个 chat.js 文件:

     "use strict";
    
     var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
    
     //Disable send button until connection is established
     document.getElementById("sendButton").disabled = true;
    
     connection.on("ReceiveMessage",function (user,message) {
         var msg = message.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
         var encodedMsg = user + " says " + msg;
         var li = document.createElement("li");
         li.textContent = encodedMsg;
         document.getElementById("messagesList").appendChild(li);
     });
    
     connection.start().then(function () {
         document.getElementById("sendButton").disabled = false;
     }).catch(function (err) {
         return console.error(err.toString());
     });
    
     document.getElementById("sendButton").addEventListener("click",function (event) {
         var sender = document.getElementById("senderInput").value;
         var receiver = document.getElementById("receiverInput").value;
         var message = document.getElementById("messageInput").value;
    
         if (receiver != "") {
    
             connection.invoke("SendMessageToGroup",message).catch(function (err) {
                 return console.error(err.toString());
             });
         }
         else {
             connection.invoke("SendMessage",message).catch(function (err) {
                 return console.error(err.toString());
             });
         }
    
    
         event.preventDefault();
     });
    

之后我们可以通过群组向用户发送消息。像这样:

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-