C#利用SignalR实现通信事例Demo

1.服务端安装SignalR的Nuget包

dotnet add package Microsoft.AspNet.SignalR --version 2.4.3

2.接下来,创建一个ChatHub类,它是SignalR通信的核心:

using Microsoft.AspNetCore.SignalR;

public class ChatHub : Hub
{
    public static Dictionary<string, string> user = new();
    
    public void Connect(string key)
    {
        if (user.ContainsKey(key)) { user.Remove(key); }
        user.Add(key,Context.ConnectionId);
        Console.WriteLine("("+ DateTime.Now +")客户端:"+ key + "上线成功!");
    }
    

    public async Task HandMsg(Chat chat)
    {
        chat.time = DateTime.Now;
        ChatHandlerService handler;
        switch ( (Command) chat.cmd)
        {
            case Command.PRIVATE:
                handler = new PrivateServiceImpl();
                await handler.execute(chat,user,Context,Clients);
                break; 
            case Command.LINERADIO:
                handler = new LineradioServiceImpl();
                await handler.execute(chat, user, Context, Clients);
                break;
        }
    }
}
  •  这个是信息处理的提取ChatHandlerService
public interface ChatHandlerService
{
    Task execute(Chat chat,Dictionary<string, string> user,HubCallerContext context, IHubCallerClients clients);
}
  •  这个是单聊的具体实现
public class PrivateServiceImpl : ChatHandlerService
{
    public Task execute(Chat chat, Dictionary<string, string> user, HubCallerContext context, IHubCallerClients clients)
    {
        if (user.ContainsKey(chat.target!))
        {
            string target = user[chat.target!];
            clients.Client(target).SendAsync("receive", chat);
            return Task.CompletedTask;
        }
        chat.message = "好友不在线";
        clients.Client(context.ConnectionId).SendAsync("receive", chat);
        return Task.CompletedTask;
    }
}
  • 这个是 通知全部在线的用户

public class LineradioServiceImpl : ChatHandlerService
{

    public async Task execute(Chat chat, Dictionary<string, string> user, HubCallerContext context, IHubCallerClients clients)
    {
        await clients.All.SendAsync("receive", chat); 
    }
}
  •  指令枚举
public enum Command
{
    PRIVATE = 300,
    GROUP = 400,
    LINERADIO = 500
}
  • 聊天模型 
public class Chat
{
    public string userKey { get; set; } = null!;
    
    public string? target { get; set; }
    
    public string? message { get; set; }
        
    public int type { get; set; }
    
    public int cmd { get; set; }
    
    public DateTime time { get; set; }
}

提示:Connect是连接的实例方法,当客户端成功后在回调使用此方法,HandMsg是我的信息处理方法,其中你可以不用我的service和实现层,直接在ChatHub类中使用你传入的数据就可以了。

3.在Program中使用

builder.Services.AddSignalR();

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(
        builder =>
        {
            builder.WithOrigins("http://localhost")
                .AllowAnyHeader()
                .WithMethods("GET", "POST")
                .AllowCredentials();
        });
});


app.MapHub<ChatHub>("/chathub");

提示:注意需要配置跨域

4.编写客服端代码

<!DOCTYPE html>
<html lang="">
<head>
    <title>SignalR</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/8.0.0/signalr.min.js"></script>
    <meta charset="utf-8" />
</head>
<style>
    input {
        border-radius: 12px;
        padding: 5px 5px;
    }
    .sendButton {
        width:200px;
        border-radius: 12px;
        background: #3F95FF;
        padding: 6px 0;
        border: none;
        color: white;
    }
</style>
<body>

<h1>SignalR</h1>
<div style="display: flex;gap: 12px;flex-direction: column">
    <div>
        <label for="target">发送给:</label>
        <input type="text" id="target" />
    </div>
    <div>
        <label for="msg">信息:</label>
        <input type="text" id="msg" />
    </div>
    <div>
        <button type="button" id="sendButton" class="sendButton">发送</button>
    </div>
</div>
<div>
    <ul id="messagesList"></ul>
</div>

<script>

    /**
     * 获取URL中的查询参数值
     *
     * @param {string} name - 查询参数名
     * @returns {string|null} - 查询参数值,如果不存在则返回null
     */
    function getQueryParam(name) {
        const urlParams = new URLSearchParams(window.location.search);
        return urlParams.get(name);
    }

    /**
     * 初始化SignalR连接
     */
    const connection = new signalR.HubConnectionBuilder()
        .withUrl("https://localhost:7066/chathub")
        .configureLogging(signalR.LogLevel.Information)
        .build();

    /**
     * 监听服务器发送的消息
     *
     * @param {object} res - 接收到的消息对象
     */
    connection.on("receive", res => {
        const li = document.createElement("li");
        li.textContent = `${ res.userKey  }: ${res.message}`;
        document.getElementById("messagesList").appendChild(li);
    });

    /**
     * 启动SignalR连接,并调用Connect方法向服务器发送连接请求
     */
    connection.start()
        .then(() => {
            connection.invoke("Connect", getQueryParam("key"))
                .catch(err => console.error(err.toString()));
        })
        .catch(function (err) {
            return console.error(err.toString());
        });

    /**
     * 发送按钮点击事件处理函数
     *
     * @param {Event} event - 事件对象
     */
    document.getElementById("sendButton").addEventListener("click", event => {
        const target = document.getElementById("target").value;
        const message = document.getElementById("msg").value;
        let sendMessage = {
            userKey: getQueryParam("key"),
            target: target,
            cmd: 300,
            message: message
        };

        /**
         * 调用服务器HandMsg方法发送消息
         */
        connection.invoke("HandMsg", sendMessage)
            .then(res => {
                const li = document.createElement("li");
                li.textContent = `我: ${message}`;
                document.getElementById("messagesList").appendChild(li);
                document.getElementById("msg").value = "";
            })
            .catch(err => console.error(err.toString()));

        event.preventDefault();
    });
</script>
</body>
</html>

浏览器需要在后面跟上参数Key 

http://localhost/?key=10086

 

5.完整代码地址

https://gitee.com/byte1026/signal-r.git

 

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值