C#通过API接口返回流式响应内容---SignalR方式
1、背景
在上两篇《C#通过API接口返回流式响应内容—分块编码方式》和《C#通过API接口返回流式响应内容—SSE方式》实现了流式响应的内容。
上面的这两个主要是通过HTTP的一些功能,除了这些之外,还有WebSocket的方式。C#中的WebSocket的有比较多的方案:SignalR、Fleck、FreeIM、WebSocket-Sharp、NetCoreServer等。其中SignalR是微软官网推荐的、Fleck是WebSocket的C#的开源项目,并且用的比较多,其他三个(FreeIM、WebSocket-Sharp、NetCoreServer)本人未使用,但原理相同,大家可以网上找找方案。
本篇主要是使用SignalR的方案
2、效果

3、具体代码
3.1、创建一个Hub

创建一个Hub服务,本质上它是一个服务器,用作一个服务转发。它是通过继承Hub实现。
using Microsoft.AspNetCore.SignalR;namespace SignalRHub.Hubs
{public class DeepSeekChat:Hub{public async Task SendDeepSeekStream(string msg){await Clients.All.SendAsync("ReceiveMsg", msg); //非常简单的方法,就是直接推送数据}}
}
3.2、配置Hub
在program.cs中配置Hub
using Microsoft.AspNetCore.SignalR;using SignalRHub.Hubs;var builder = WebApplication.CreateBuilder(args);builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSignalR(); //【添加SignalR服务】
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}//app.UseHttpsRedirection();
app.UseCors(MyAllowSpecificOrigins);app.UseAuthorization();app.MapControllers();
app.MapHub<DeepSeekChat>("/dschat"); //【配置Endpoint】
app.Run();
3.3、配置推送服务
当我们实现了DeepSeekChat时,我们如何通过服务器,将数据推送到终端呢?因此我们需对外的API接口,当我们调用API的接口时,API方法内部调用signalr的实例,并调用推送方法,从而将我们的内容推送到终端。
在apicontroller中或者program.cs
在apicontroller中的方法如下,【这个是一个Get方法】
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using SignalRHub.Hubs;namespace SignalRHub.Controllers
{[Route("api/[controller]")][ApiController]public class ViaAPIController : ControllerBase{private readonly IHubContext<DeepSeekChat> chatHub;public ViaAPIController(IHubContext<DeepSeekChat> chatHub){this.chatHub = chatHub;}[HttpGet("sendmsg")]public async Task SendMsg(){//模拟deepseek的对话内容var phrases = new string[] { "你好!", "我是", "北京清华长庚医院", "信息管理部的", "郑林" };foreach (var item in phrases){await chatHub.Clients.All.SendAsync("ReceiveMsg", item);await Task.Delay(1000);}}}
}
在program.cs的代码如下:
//上文中的其他配置略过
app.UseAuthorization();
app.MapControllers();
app.MapHub<DeepSeekChat>("/dschat");
//【这儿就是直接配置的,两者的效果是一样的,都是发送数据】
app.MapPost("sendNotification", async (string msg, IHubContext<DeepSeekChat> context) => {var phrases = new string[] { "你好!", "我是", "北京清华长庚医院", "信息管理部的", "郑林" };foreach (var item in phrases){await context.Clients.All.SendAsync("ReceiveMsg", item);await Task.Delay(1000);}
});app.Run();
两者的效果是一致的
3.4、前端代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>SignalR Client</title><script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.18/signalr.min.js"></script>
</head>
<body><h3>流式响应</h3><div id="stockPrices"></div><script>const connection = new signalR.HubConnectionBuilder().withUrl("http://localhost:5071/dschat").build();connection.on("ReceiveMsg", (msg) => {const stockPricesDiv = document.getElementById("stockPrices");stockPricesDiv.innerHTML+= msg +' '; });connection.start().then(() => {console.log("SignalR connection started.");}).catch(err => {console.error("Error connecting to SignalR: ", err);});window.addEventListener("beforeunload", () => {connection.stop().then(() => {console.log("SignalR connection stopped.");}).catch(err => {console.error("Error stopping SignalR connection: ", err);});});</script>
</body>
</html>
比较简单
3.5、配置Cors
这样运行的话,浏览器是报错的,因为有Cors限制,因此需要在program.cs中配置
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";var builder = WebApplication.CreateBuilder(args);//设置CORS
builder.Services.AddCors(options => {options.AddPolicy(name: MyAllowSpecificOrigins,policy => {policy.SetIsOriginAllowed(t=>true) //默认全部访问.AllowAnyHeader().AllowAnyMethod().AllowCredentials();});
});
builder.Services.AddControllers();//其他配置//app.UseHttpsRedirection();
app.UseCors(MyAllowSpecificOrigins); //配置Cors
app.UseAuthorization();
app.MapControllers();
3.6、完整的program配置
完整的配置如下:
using Microsoft.AspNetCore.SignalR;
using SignalRHub.BackgroundServices;
using SignalRHub.Hubs;var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";var builder = WebApplication.CreateBuilder(args);//设置CORS
builder.Services.AddCors(options => {options.AddPolicy(name: MyAllowSpecificOrigins,policy => {policy.SetIsOriginAllowed(t=>true) //.AllowAnyHeader().AllowAnyMethod().AllowCredentials();});
});builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSignalR();//添加SignalR服务
//builder.Services.AddHostedService<Worker>(); //添加一个后台服务var app = builder.Build();// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}//app.UseHttpsRedirection();
app.UseCors(MyAllowSpecificOrigins); //配置Corsapp.UseAuthorization();app.MapControllers();
app.MapHub<DeepSeekChat>("/dschat");app.MapPost("sendNotification", async (string msg, IHubContext<DeepSeekChat> context) => {var phrases = new string[] { "你好!", "我是", "北京清华长庚医院", "信息管理部的", "郑林" };foreach (var item in phrases){await context.Clients.All.SendAsync("ReceiveMsg", item);await Task.Delay(1000);}
});app.Run();
4、原理
这个是一个原理图,只不过本文的样例是单向的
5、参考资料
1、SignalR微软官网
2、ASP.NET Core 配置跨域(CORS)
3、3个WebSocket的.Net开源项目
相关文章:
C#通过API接口返回流式响应内容---SignalR方式
1、背景 在上两篇《C#通过API接口返回流式响应内容—分块编码方式》和《C#通过API接口返回流式响应内容—SSE方式》实现了流式响应的内容。 上面的这两个主要是通过HTTP的一些功能,除了这些之外,还有WebSocket的方式。C#中的WebSocket的有比较多的方案&…...
vulhub靶机----基于docker的初探索,环境搭建
环境搭建 首先就是搭建docker环境,这里暂且写一下 #在kali apt update apt install docker.io配置docker源,位置在/etc/docker/daemon.json {"registry-mirrors": ["https://5tqw56kt.mirror.aliyuncs.com","https://docker…...
P1659 [国家集训队] 拉拉队排练 (manacher 算法)
P1659 [国家集训队] 拉拉队排练 - 洛谷 这题需要求前k大的回文子串的长度的乘积。因为n的大小为1e6 ,所以我们只能使用manacher 线性的来找到所有的回文子串。 其中长度大的回文子串可以包含小的回文子串,所以其实我们只需要知道以每一个位置为回文中心…...
Redis命令详解--集合
Redis set 是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据,常用命令: SADD key member1 [member2...] 向集合添加一个或多个成员 SREM key member1 [member2...] 移除集合中一个或多个成员 SMEMBERS key 获…...
AI对话框实现
请注意,功能正在开发中,代码和注释不全 场景:AI对话框实现,后端调用AI大模型。前端发送请求后端返回流式数据,进行一问一答的对话功能(场景和现在市面上多个AI模型差不多,但是没人家功能健全&a…...
可视化图解算法:删除链表中倒数第n个节点
1. 题目 描述 给定一个链表,删除链表的倒数第 n 个节点并返回链表的头指针 例如, 给出的链表为: 1→2→3→4→5, n 2. 删除了链表的倒数第 n 个节点之后,链表变为1→2→3→5. 数据范围: 链表长度 0≤n≤1000,链表中任意节点的…...
智能汽车图像及视频处理方案,支持视频智能拍摄能力
美摄科技,作为智能汽车图像及视频处理领域的先行者,凭借其卓越的技术实力和前瞻性的设计理念,为全球智能汽车制造商带来了一场视觉盛宴的革新。我们自豪地推出——美摄科技智能汽车图像及视频处理方案,一个集高效性、智能化、画质…...
如何根据 CUDA 配置安装 PyTorch 和 torchvision(大模型 环境经验)
目录 前言1. CUDA2. 环境配置前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 写过ubuntu的配置安装:Ubuntu安装配置Cuda和Pytorch gpu 以下针对Window,如何通过Cuda配置对应版本,安装大模型环境! 代码有配置包,直接执行:pip install -r requi…...
微信小程序的业务域名配置(通过ingress网关的注解)
一、背景 微信小程序的业务域名配置(通过kong网关的pre-function配置)是依靠kong实现,本文将通过ingress网关实现。 而我们的服务是部署于阿里云K8S容器,当然内核与ingress无异。 找到k8s–>网络–>路由 二、ingress注解 …...
自学Python创建强大AI:从入门到实现DeepSeek级别的AI
人工智能(AI)是当今科技领域最热门的方向之一,而Python是AI开发的首选语言。无论是机器学习、深度学习还是自然语言处理,Python都提供了丰富的库和工具。如果你梦想创建一个像DeepSeek这样强大的AI系统,本文将为你提供…...
Matlab 舰载机自动着舰控制系统研究
1、内容简介 Matlab 188-舰载机自动着舰控制系统研究 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略...
【华为OD-E卷 -123 判断一组不等式是否满足约束并输出最大差 100分(python、java、c++、js、c)】
【华为OD-E卷 - 判断一组不等式是否满足约束并输出最大差 100分(python、java、c++、js、c)】 题目 给定一组不等式,判断是否成立并输出不等式的最大差(输出浮点数的整数部分) 要求: 不等式系数为 double类型,是一个二维数组 不等式的变量为 int类型,是一维数组; 不等式…...
剑指 Offer II 113. 课程顺序
comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20113.%20%E8%AF%BE%E7%A8%8B%E9%A1%BA%E5%BA%8F/README.md 剑指 Offer II 113. 课程顺序 题目描述 现在总共有 numCourses 门课需要选,记为 0 到 n…...
小科普《DNS服务器》
DNS服务器详解 1. 定义与核心作用 DNS(域名系统)服务器是互联网的核心基础设施,负责将人类可读的域名(如www.example.com)转换为机器可识别的IP地址(如192.0.2.1),从而实现设备间的…...
嵌入式硬件篇---WIFI模块
文章目录 前言一、核心工作原理1. 物理层(PHY)工作频段2.4GHz5GHz 调制技术直接序列扩频正交频分复用高效数据编码 2. 协议栈架构MAC层Beacon帧4次握手 3. 核心工作模式 二、典型应用场景1. 智能家居系统远程控制环境监测视频监测 2. 工业物联网设备远程…...
WindowsAD域服务权限提升漏洞
WindowsAD 域服务权限提升漏洞(CVE-2021-42287, CVE-2021-42278) 1.漏洞描述 Windows域服务权限提升漏洞(CVE-2021-42287, CVE-2021-42278)是由于Active Directory 域服务没有进行适当的安全限制,导致可绕过安…...
Oracle常见系统函数
一、字符类函数 1,ASCII(c)和CHR(i)字符串和ascii码互转换 SQL> select ascii(Z) ,ascii(H),ascii( A) from dual;ASCII(Z) ASCII(H) ASCII(A) ---------- ---------- ----------90 72 32SQL> select chr(90),chr(72),chr(65) from dual;C…...
甘特图dhtmlx-gantt 一行多任务
继上篇进行修改 dhtmlxGantt 甘特图 一行展示多条任务类型_dhtmlxgantt多个任务显示在一行-CSDN博客 主要修改 getProductData 数据部分: 数据中添加: render: "split", //允许任务在同一行中拆分显示, parent: "1",…...
docker配置国内镜像站链接
修改这个文件 sudo vi /etc/docker/daemon.json将镜像站的链接放在里面,如果大于等于两个用逗号分隔 { "registry-mirrors": ["https://docker.1panel.live"] }使配置生效 sudo systemctl daemon-reload sudo systemctl restart docker条件允…...
Flutter 学习之旅 之 flutter 使用 SQLite(sqflite) 实现简单的数据本地化 保存/获取/移除/判断是否存在 的简单封装
Flutter 学习之旅 之 flutter 使用 SQLite(sqflite) 实现简单的数据本地化 保存/获取/移除/判断是否存在 的简单封装 目录 Flutter 学习之旅 之 flutter 使用 SQLite(sqflite) 实现简单的数据本地化 保存/获取/移除/判断是否存在…...
【leetcode hot 100 208】实现Trie(前缀树)
解法一:字典树 Trie,又称前缀树或字典树,是一棵有根树,其每个节点包含以下字段: 指向子节点的指针数组 children。对于本题而言,数组长度为 26,即小写英文字母的数量。此时 children[0] 对应小…...
Pytest的夹具共享(2)
1、问题:夹具跟用例都是写在一个py文件中,在自动化框架中,测试用例、夹具在不同的文件中,跨文件夹具使用呢? “”" 在XXX测试用例模块中,使用夹具? 如何跨文件调用? -1&#x…...
前端安全之DOMPurify基础使用
DOMPurify时一款专门用于防御XSS攻击的库,通过净化HTML的内容,移除恶意脚本,同时保留安全的HTML标签和数学。以下是基础使用指南,涵盖基础的安装与用法。 1,安装DOMPurify 通过npm或yarn安装 npm install dompurify …...
鸿蒙 元服务摘要
元服务(原名原子化服务),是HarmonyOS提供的一种面向未来的服务提供方式,是有独立入口的(用户可通过点击方式直接触发)、免安装的(无需显式安装,由系统程序框架后台安装后即可使用&am…...
【css酷炫效果】纯CSS实现粒子旋转动画
【css酷炫效果】纯CSS实现粒子旋转动画 缘创作背景html结构css样式完整代码效果图 想直接拿走的老板,链接放在这里:https://download.csdn.net/download/u011561335/90492008 缘 创作随缘,不定时更新。 创作背景 刚看到csdn出活动了&…...
k8s中的service解析
k8s中的service解析 在k8s中,我们可以通过pod来创建服务。 然而,当我们创建多个 Pod 来提供同一项服务时,直接通过 Pod IP 进行访问会变得复杂且不可维护。因此,Kubernetes 提供了 Service 这一抽象概念,用于对外暴露…...
案例:图书管理
掌握图书管理案例的实现,能够使用Spring Boot整合Thymeleaf完成图书管理案例。 1.任务需求 (1)项目使用Spring Boot整合Thymeleaf,项目展示的页面效果全部通过Thymeleaf的模板文件实现。 (2)查询所有图书。…...
Docker和Dify学习笔记
文章目录 1 docker学习1.1 基本命令使用1.1.1 docker ps查看当前正在运行的镜像1.1.2 docker stop停止容器1.1.3 docker compose容器编排1.1.4 docker网络[1] 进入到容器里面敲命令[2] docker network ls[3] brige网络模式下容器访问宿主机的方式 2 Dify的安装和基础使用2.1 下…...
【Java集合夜话】第1篇:拨开迷雾,探寻集合框架的精妙设计
欢迎来到Java集合框架系列的第一篇文章!🌹 本系列文章将以通俗易懂的语言,结合实际开发经验,带您深入理解Java集合框架的设计智慧。🌹 若文章中有任何不准确或需要改进的地方,欢迎大家指出,让我…...
VSCode创建VUE项目(四)增加用户Session管理
将用户信息存储或者更新到Session sessionStorage.setItem("userID",loginform.value.username); sessionStorage.setItem(loginTime, Date.now()); 获取Session信息 const storedUserInfo sessionStorage.getItem(userID); const loginTime sessionStorage.get…...
