首页 > 技术文章 > SignalR 入门 .netCore实现聊天室

cheery-go 2021-12-20 15:39 原文

SignalR 入门 .netCore实现聊天室

本文根据微软SignalR 简介 | Microsoft DocsASP.NET Core SignalR 简介 | Microsoft Docs 内容,结合自己学习过程中的理解而成,希望对大家认识和使用SinalR有帮助。

什么是SignalR?

ASP.NET SignalR 是 ASP.NET 开发人员的库

可以用来干什么?

可简化将实时 web 功能添加到应用程序的过程。 实时 web 功能使服务器代码能够在可用时立即将内容推送到连接的客户端,而不是让服务器等待客户端请求新的数据。

SignalR 自动处理连接管理,让你可同时向所有连接的客户端广播消息,就像聊天室一样。 也可以向特定客户端发送消息。 客户端和服务器之间的连接是持久的,不同于传统的 HTTP 连接,后者针对每次通信重新建立。

SignalR 支持 "服务器推送" 功能,在该功能中,服务器代码可以使用远程过程调用来调用浏览器中的客户端代码 (RPC) [1],而不是目前在 web 上通用的请求-响应模式。

传统的获取服务器数据的方法是:通过客户端向服务器发送请求,服务器相应请求返回数据给客户端的方式(请求-响应模式)。而SinalR实现服务器主动向客户端推送数据。

SignalR怎么实现服务器和客户端之间的通信?

SignalR 使用 集线器Hub 在客户端和服务器之间进行通信。

中心是一种高级管道,它允许客户端和服务器分别调用方法。 SignalR 自动处理跨计算机边界的调度,使客户端能够在服务器上调用方法,反之亦然。 可以将强类型参数传递给方法,从而启用模型绑定。 SignalR 提供了两个内置的集线器协议:基于 JSON 的文本协议和基于 MessagePack的二进制协议。 与 JSON 相比,MessagePack 通常会创建较小的消息。 较早的浏览器必须支持 XHR 级别 2 ,才能提供 MessagePack 协议支持。

中心通过发送包含客户端方法的名称和参数的消息来调用客户端代码。 作为方法参数发送的对象将使用配置的协议进行反序列化。 客户端尝试将名称与客户端代码中的方法匹配。 当客户端找到匹配项时,它将调用方法并向其传递反序列化的参数数据。

代码实现:ASP.NET Core SignalR 入门 | Microsoft Docs

实现一个聊天室的场景demo,测试:打开两个浏览器聊天,显示聊天列表

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

中心 是一个类,用作处理客户端 - 服务器通信的高级管道。

  • 在 SignalRChat 项目文件夹中,创建 Hubs 文件夹。

  • 在 Hubs 文件夹中,使用以下代码创建 chatHub.cs 文件 :

    using Microsoft.AspNetCore.SignalR;
    using System.Threading.Tasks;
    
    namespace SignalRChat.Hubs
    {
        public class ChatHub : Hub
        {
            public async Task SendMessage(string user, string message)
            {
                await Clients.All.SendAsync("ReceiveMessage", user, message);
            }
        }
    }
    
配置.netCore项目以使用 SignalR服务。
using SignalRChat.Hubs;

 public void ConfigureServices(IServiceCollection services)
        {
            ...
            services.AddSignalR();
        }

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
     		...
     		app.UseEndpoints(endpoints =>
            {
                ...
                endpoints.MapHub<ChatHub>("/chatHub");
            });
		 }

这些更改将 SignalR 添加到 ASP.NET Core 依赖关系注入和路由系统。

添加可将消息从任何客户端发送到所有连接客户端的代码。

html

<div class="container">
        <div class="row">&nbsp;</div>
        <div class="row">
            <div class="col-2">User</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>
<script src="~/js/signalr/dist/browser/signalr.js"></script>
<script src="~/js/chat.js"></script>

javascript

"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 li = document.createElement("li");
    document.getElementById("messagesList").appendChild(li);
    // We can assign user-supplied strings to an element's textContent because it
    // is not interpreted as markup. If you're assigning in any other way, you 
    // should be aware of possible script injection concerns.
    li.textContent = `${user} says ${message}`;
});

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

前面的代码:

  • 创建并启动连接。
  • 向“提交”按钮添加一个用于向中心发送消息的处理程序。
  • 向连接对象添加一个用于从中心接收消息并将其添加到列表的处理程序。

  1. RPC(Remote Procedure Call)译作:远程过程调用,是一种通过网络从远程计算机程序上请求服务而不需要了解底层网络技术的思想。 RPC 是一种技术思想而非一种规范或协议,常见的技术和框架有:应用级的服务框架:阿里的 Dubbo/Dubbox、Google gRPC、Spring Boot/Spring Cloud。远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)。通信框架:MINA 和 Netty。花了一个星期,我终于把RPC框架整明白了! - 51CTO.COMRPC是什么,看完你就知道了 - 知乎 (zhihu.com) ↩︎

推荐阅读