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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/732197.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

聊聊 C# dynamic 类型,并分享一个将 dynamic 类型变量转为其它类型的技巧和实例

前言 dynamic 是一种有别于传统变量类型的动态类型声明&#xff0c;刚开始接触可能在理解上会有些困难&#xff0c;可以简单地把它理解为一个盲盒&#xff0c;你可以任意猜测盒子有什么东西&#xff0c;并认为这些东西真正存在而进行处理&#xff0c;等到真正打开时&#xff0…

文章自动生成器,在线AI写作工具

随着人工智能AI技术的发展&#xff0c;AI技术被应用到越来越多的场景。对于需要创作内容的同学来说&#xff0c;AI写作-文章内容自动生成器是一个非常好的辅助工具。AI写作工具可以提升我们的创作效率&#xff0c;快速的生成文章&#xff0c;然后在根据需求进行调整修改即可。下…

语法制导的翻译和属性文法

属性的分类 1.综合属性 重写规则&#xff08;产生式&#xff09;左部符号的属性是综合属性。一个结点相应文法符号的属性值通过语法分析树中它的子节点的属性之值计算&#xff08;自底向上&#xff09; 2.继承属性 出现在重写规则右部的符号的属性。一个结点相应文法符号的属性…

概念描述——TCP/IP模型中的两个重要分界线

TCP/IP模型中的两个重要分界线 协议的层次概念包含了两个也许不太明显的分界线&#xff0c;一个是协议地址分界线&#xff0c;区分出高层与低层寻址操作&#xff1b;另一个是操作系统分界线&#xff0c;它把系统与应用程序区分开来。 高层协议地址界限 当我们看到TCP/P软件的…

没等来百度惊艳的All in AI,却等来了国产之光的盘古大模型 5.0

6月21日&#xff0c;华为开发者大会&#xff08;HDC 2024&#xff09;在广东东莞正式开幕。盘古大模型5.0的更新&#xff0c;也是此次HDC2024的另一项重头戏。在过去的一年中&#xff0c;盘古大模型正在疯狂向各行各业渗透。 此次&#xff0c;华为方面展示了他们在具身智能、医…

【面向对象】复习(二)

内存对齐 class A{ static int a; } int main(){ A obj; cout<<sizeof(obj); } 在你的代码中&#xff0c;class A 包含一个静态成员变量 a。静态成员变量不属于类的任何特定实例&#xff0c;而是属于整个类。因此&#xff0c;在计算类的实例大小时&#xff0c;静态…

C语言入门系列:指针入门(超详细)

文章目录 一&#xff0c;什么是指针1&#xff0c;内存2&#xff0c;指针是什么&#xff1f; 二&#xff0c;指针的声明1&#xff0c;声明指针类型变量2&#xff0c;二级指针 三&#xff0c;指针的计算1&#xff0c;两个指针运算符1.1 *运算符1.2 & 运算符1.3 &运算符与…

状态压缩DP——AcWing 291. 蒙德里安的梦想

状态压缩DP 定义 状态压缩DP是一种利用二进制数来表示状态的动态规划算法。它通过将状态压缩成一个整数&#xff0c;从而减少状态数量&#xff0c;提高算法效率。 运用情况 状态压缩DP通常用于解决具有状态转移和最优解性质的问题&#xff0c;例如组合优化、图论、游戏等问…

python-邮票组合问题

[题目描述] 某人有四张3分的邮票和三张5分的邮票&#xff0c;用这些邮票中的一张或若干张可以得到多少种不同的邮资&#xff1f;输入格式&#xff1a; 此题无输入。输出格式&#xff1a; 输出可以得到不同邮资的数量。 样例输入 无样例输出 19数据范围&#xff1a; 对于100%的…

华为---RIP路由协议的汇总

8.3 RIP路由协议的汇总 8.3.1 原理概述 当网络中路由器的路由条目非常多时&#xff0c;可以通过路由汇总(又称路由汇聚或路由聚合)来减少路由条目数&#xff0c;加快路由收敛时间和增强网络稳定性。路由汇总的原理是&#xff0c;同一个自然网段内的不同子网的路由在向外(其他…

与Vatee万腾平台同行,共创智能未来

在科技日新月异的今天&#xff0c;智能化已成为推动社会进步的重要力量。Vatee万腾平台&#xff0c;作为这一浪潮中的佼佼者&#xff0c;正以其独特的创新力和前瞻的视野&#xff0c;引领我们迈向智能未来。与Vatee万腾平台同行&#xff0c;我们不仅能享受到科技带来的便捷与舒…

[最新教程]Claude Sonnet 3.5注册方法详细步骤分享,新手小白收藏,文末免费送已注册的Claude账号

一.Claude sonnet 3.5大模型面世 6月21日&#xff0c;被称为“OpenAI 最强竞对”的大模型公司 Anthropic 发布了 Claude 3.5 系列模型中的第一个版本——Claude 3.5 Sonnet。 Anthropic 在官方博客中表示&#xff0c;Claude 3.5 Sonnet 提高了智能化的行业标准&#xff0c;在…

传统图像特征描述及提取方法

目录 一、图像特征描述 二、图像特征的分类 2.1 图像的点、线、面特征 2.2 图像的纹理形状特征 2.3 图像颜色特征 2.4图像的统计特征 三、图像特征提取的评价 一、图像特征描述 图像特征是一幅图像区别于另一幅图像最基本的特征,是其可以作为标志性的属性。 图像特征分为…

2024 年解锁 Android 手机的 7 种简便方法

您是否忘记了 Android 手机的 Android 锁屏密码&#xff0c;并且您的手机已被锁定&#xff1f;您需要使用锁屏解锁 Android 手机&#xff1f;别担心&#xff0c;您不是唯一一个忘记密码的人。我将向您展示如何解锁 Android 手机的锁屏。 密码 PIN 可保护您的 Android 手机和 G…

高考志愿填报,如何权衡学校和专业?

高考是人生的分水岭&#xff0c;成绩好的学生能就读更好的大学&#xff0c;获得更多的学习资源&#xff0c;但也有一些同学即使凭借高分数进入了高校&#xff0c;专业的学习过程却不尽如人意&#xff0c;他们也没有将100%的精力投入到专业学习当中。 无论高考结束之后获得了多…

python--fasApi学习(Dash+FastAPI框架)

在学习fastApi 框架时&#xff0c;发现了一个好用的框架&#xff0c;参考&#xff1a; 博客参考&#xff1a; https://blog.csdn.net/gitblog_00002/article/details/137331157下载文档并部署&#xff1a; 下载代码&#xff1a; git clone https://gitee.com/insistence2022/…

LeetCode 1-两数之和

LeetCode第1题 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现…

全流程FVCOM水环境、污染物迁移、水交换、水质、潮流、温盐、波浪及泥沙数值模拟

近年来&#xff0c;随着计算技术的发展和对海洋、水环境问题认识的加深&#xff0c;数值模拟技术在海洋、水环境等科学研究中的应用越来越广泛。FVCOM因其独特的优点&#xff0c;成为研究海洋动力过程、污染物扩散、水质变化等问题的重要工具。作为一种基于有限体积法的数值模型…

DBeaver 数据结果集设置不显示逗号(太丑了)

从Navicat切换过来使用DBeaver&#xff0c;发现类似bigint 这种数据类型在结果集窗口中显示总是给我加上一个逗号&#xff0c;看着很不习惯&#xff0c;也比较占空间&#xff0c;个人觉得这种可读性也不好。 于是我在网上尝试搜索设置方法&#xff0c;可能我的关键词没命中&…

利用LabVIEW和机器学习实现无规律物体识别

针对变化无规律的物体识别&#xff0c;LabVIEW结合机器学习算法提供了一种高效的解决方案。介绍如何使用LabVIEW编程实现此功能&#xff0c;包括所需工具包、算法选择和实现步骤&#xff0c;帮助开发者在无规律的复杂环境中实现高精度的物体识别。 1. 项目概述 无规律物体的识…