How can I make one to one chat system in Asp.Net.Core Mvc Signalr?

≡放荡痞女 提交于 2021-01-29 19:28:00

问题


I want to implement private chat system with Mssql Database. This codes works as public when I send the message, message is appears all clients. But I want to one to one chat system. One user enter the receiver id which stored in database and message text, then send the message to Receiver . Then the message appears in receiver message area which has that receiver id.

Here is my js code

"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);
});

Here is my hub class

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",user,message);
        }

    }
}

Here is my html code

            <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:


To send the message to specific user, you could use the following methods:

  1. Use Single-user groups.

    You can create a group for each user, and then send a message to that group when you want to reach only that user. The name of each group is the name of the user. If a user has more than one connection, each connection id is added to the user's group.

    For example, base on the getting start document, I have create a SignalR application, it will send message to all users. Then, in the ChatHub class, add the Authorize attribute and override the OnConnectedAsync() method, in the OnConnectedAsync method, we could create a group based on the Identity User. Then, add a SendMessageToGroup method to send message to group.

     [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);
         }  
     }
    

    In the Index.cshtml page, add a Receiver input element to enter the receiver name (the same as the group name).

     <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>
    

    Then, update the sendButton click event in the chat.js file:

     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", sender, receiver, message).catch(function (err) {
                 return console.error(err.toString());
             });
         }
         else { 
             connection.invoke("SendMessage", sender, message).catch(function (err) {
                 return console.error(err.toString());
             });
         }
         event.preventDefault();
     });
    

    After that, we could send message to specific user, screenshot as below (if the receiver is null, it will send message to all user, else, will send message to specific user):

  2. Send message via the ConnectionID.

    From the above sample code, in the OnConnectedAsyc method, we could get the ConnectId and the User Name, then, you could store them in the database. Then, you can add the SendMessageToUser method in the ChatHub.cs. In this method, you could query the database and find the connectionId based on the receiver name, after that using Clients.Client("connectionId").SendAsync() method to send the message to a specific user.

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

Here are some related articles, you can refer to them:

Use hubs in SignalR for ASP.NET Core

Mapping SignalR Users to Connections

Update:

Detail Steps:

  1. Open the Visual Studio 2019 (the latest version), and create an Asp.net Core Web Application (named SignalRApp, using .net core 3.1 version):

    Choose the MVC template and change the Authentication to "Individual User Accounts".

  2. Using the following command in the Package Manager Console tools. More detail information, check EF Core Migrations.

    add-migration InitialCreate
    update-database

  3. After that, we could run the application and register users. The login screenshot as below:

  4. Add the SignalR client library

    • In Solution Explorer, right-click the project, and select Add > Client-Side Library.
    • In the Add Client-Side Library dialog, for Provider select unpkg.
    • For Library, enter @microsoft/signalr@latest.
    • Select Choose specific files, expand the dist/browser folder, and select signalr.js and signalr.min.js.
    • Set Target Location to wwwroot/js/signalr/, and select Install. LibMan creates a wwwroot/js/signalr folder and copies the selected files to it.
  5. Create a SignalR hub.

    In the Project folder, create a Hubs folder and add a ChatHub.cs file with the following code:

     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", user, message);
             }
    
             public Task SendMessageToGroup(string sender, string receiver, string message)
             {
                 return Clients.Group(receiver).SendAsync("ReceiveMessage", sender, message);
             }
         }
     }
    
  6. Configure SignalR in the Startup.cs file. You could check this article.

    The startup.cs file as below:

     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. Add SignalR client code:

    [Note] In this step, please pay attention to the js file path. If the js file doesn't load successfully, the client code will not work.

    In the Home controller Index page(Index.cshtml), replace the content as below:

     @{
         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>
    

    In the wwwroot/js folder, create a chat.js file with the following code:

     "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", sender, receiver, message).catch(function (err) {
                 return console.error(err.toString());
             });
         }
         else {
             connection.invoke("SendMessage", sender, message).catch(function (err) {
                 return console.error(err.toString());
             });
         }
    
    
         event.preventDefault();
     });
    

After that we could send messages to user via groups. Like this:



来源:https://stackoverflow.com/questions/65568240/how-can-i-make-one-to-one-chat-system-in-asp-net-core-mvc-signalr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!