.net中SignalR的使用

前言

  前面学习了asp.net长连接和websocket

  asp.net实现长连接 - chenxizhaolu - 博客园

  webSocket在.net中的使用案例 - chenxizhaolu - 博客园

  今天学习下SignalR,这样实时Web功能三部曲就算学习完成了。

  ASP.NET Core SignalR 是一个开放源代码库,用于简化向应用程序添加实时 Web 功能。实时 Web 功能允许服务器端代码在数据可用时立即将内容推送到连接的客户端,而不是让客户端周期性地轮询服务器以获取新数据。SignalR 特别适用于需要高频率数据更新的场景,如聊天应用、实时仪表板、游戏和协作工具等。

一个简单的聊天对话框

  客户端发送消息到服务端,服务端回复。

  服务端代码:

复制代码
 public class ChatHub : Hub
 {
     public async Task SendMessage(string user, string message)
     {
         await Clients.All.SendAsync("ReceiveMessage", user, "服务端收到了客户端的消息:" + message);
     }
     public override async Task OnConnectedAsync()
     {
         await Clients.All.SendAsync("ReceiveMessage", "System", $"{Context.ConnectionId} joined the chat");
         await base.OnConnectedAsync();
     }
     public override async Task OnDisconnectedAsync(Exception exception)
     {
         await Clients.All.SendAsync("ReceiveMessage", "System", $"{Context.ConnectionId} left the chat");
         await base.OnDisconnectedAsync(exception);
     }
 }
复制代码
复制代码
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAll", policy =>
    {
        policy.WithOrigins("http://localhost:5065") // 允许所有来源
              .AllowAnyMethod() // 允许所有 HTTP 方法
              .AllowAnyHeader()// 允许所有请求头
              .AllowCredentials();

    });
});
builder.Services.AddSignalR();
builder.WebHost.UseUrls("http://localhost:5000");
var app = builder.Build();
// 启用 CORS 中间件
app.UseCors("AllowAll");
app.UseRouting();
app.MapHub<ChatHub>("/chatHub");
app.Run();
复制代码

  客户端代码:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseStaticFiles();
app.Run();
复制代码
<!-- wwwroot/index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>SignalR 聊天</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            padding-top: 50px;
        }

        #messages {
            height: 400px;
            overflow-y: scroll;
            border: 1px solid #ccc;
            padding: 10px;
            margin-bottom: 10px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1 class="mt-5">SignalR 聊天</h1>
        <div id="messages"></div>
        <input type="text" id="userInput" class="form-control mt-2" placeholder="你的名字">
        <input type="text" id="messageInput" class="form-control mt-2" placeholder="输入消息...">
        <button id="sendButton" class="btn btn-primary mt-2">发送</button>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.min.js"></script>
    <script>
        const connection = new signalR.HubConnectionBuilder()
            .withUrl("http://localhost:5000/chatHub", { withCredentials: true }) // 允许发送凭证
            .configureLogging(signalR.LogLevel.Information)
            .build();

        // 启动连接
        connection.start().then(() => {
            console.log("SignalR 连接已建立");
        }).catch(err => console.error(err.toString()));

        // 接收消息
        connection.on("ReceiveMessage", (user, message) => {
            const msg = document.createElement("div");
            msg.textContent = `${user}: ${message}`;
            document.getElementById("messages").appendChild(msg);
            window.scrollTo(0, document.body.scrollHeight);
        });

        // 发送消息
        document.getElementById("sendButton").addEventListener("click", async () => {
            const user = document.getElementById("userInput").value;
            const message = document.getElementById("messageInput").value;
            await connection.invoke("SendMessage", user, message);
            document.getElementById("messageInput").value = "";
        });
    </script>
</body>
</html>
复制代码

实时推送功能

复制代码
 public class Worker : BackgroundService
 {
     private readonly ILogger<Worker> _logger;
     private readonly IHubContext<ChatHub> _chatHubContext;
     public Worker(ILogger<Worker> logger, IHubContext<ChatHub> chatHubContext)
     {
         _logger = logger;
         _chatHubContext = chatHubContext;
     }
     protected override async Task ExecuteAsync(CancellationToken stoppingToken)
     {
         while (!stoppingToken.IsCancellationRequested)
         {
             _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);

             await _chatHubContext.Clients.All.SendAsync("OnlineUsers", "System", $"当前在线Connection: {string.Join(',', ChatHub.ConnectedConnections.Keys)}");
             await Task.Delay(10000, stoppingToken);
         }
     }
 }
复制代码
builder.Services.AddHostedService<Worker>();

 简单看一下效果

  客户端可以给服务端发送消息,服务端立马返回。如果想指定客户端返回,只需要修改SendAsync第一个参数,也就是methodName就可以。

  服务端定时推送给所有客户端当前在线情况

SignalR Console客户端示例

 

源码地址:https://gitee.com/xiaoqingyao/keep-alive-http-demo.git

posted @   chenxizhaolu  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2018-02-28 2018年新年计划
点击右上角即可分享
微信分享提示