C#通过API接口返回流式响应内容---SignalR方式

devtools/2025/3/29 7:42:56/

1、背景

在上两篇《C#通过API接口返回流式响应内容—分块编码方式》和《C#通过API接口返回流式响应内容—SSE方式》实现了流式响应的内容。
上面的这两个主要是通过HTTP的一些功能,除了这些之外,还有WebSocket的方式。C#中的WebSocket的有比较多的方案:SignalRFleckFreeIMWebSocket-SharpNetCoreServer等。其中SignalR是微软官网推荐的、FleckWebSocketC#的开源项目,并且用的比较多,其他三个(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 +'&nbsp;'; });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开源项目


http://www.ppmy.cn/devtools/170598.html

相关文章

ROM(只读存储器) 、SRAM(静态随机存储器) 和 Flash(闪存) 的详细解析

在嵌入式系统和其他计算机系统中&#xff0c;存储器是不可或缺的组成部分。不同类型的存储器各有其特点和应用场景。以下是 ROM&#xff08;只读存储器&#xff09;、SRAM&#xff08;静态随机存储器&#xff09; 和 Flash&#xff08;闪存&#xff09; 的详细解析。 1. ROM&am…

汽车免拆诊断案例 | 2024 款路虎发现运动版车无法正常识别智能钥匙

故障现象  一辆2024款路虎发现运动版车&#xff0c;搭载2.0 L发动机&#xff0c;累计行驶里程约为5 000 km。车主反映&#xff0c;使用遥控器无法解锁车门&#xff0c;随后使用机械钥匙打开车门&#xff0c;踩下制动踏板&#xff0c;按压起动按钮&#xff0c;仪表盘提示“将智…

如何设置家用威联通 NAS UPS 断电后自动关机并通知其他设备?

场景 &#x1f4dd;备注: 求轻喷, 求放过. &#x1f605; 我真的是个理线方面的白痴. 这已经是我的极限了. &#x1f602; 我的家庭实验室 Homelab 服务器集群配置如下. 上半部分之前已经介绍过了, 这里就不再赘述了. 今天重点介绍介绍 UPS 和 NAS 部分. 1台 UPS, 型号为 APC B…

windows下安装并使用node.js

一、下载Node.js 选择对应你系统的Node.js版本下载 Node.js官网下载地址 Node.js中文网下载地址??? 这里我选择的是Windows64位系统的Node.js20.18.0&#xff08;LTS长期支持版本&#xff09;版本的.msi安装包程序 官网下载&#xff1a; 中文网下载&#xff1a; 二、安…

【Uniapp】关于核心页面生命周期流程详解

UniApp 的页面生命周期继承自 Vue 组件生命周期&#xff0c;本文将解析核心页面生命周期流程&#xff0c;介绍对应的触发时机、作用并给出示例。 页面生命周期触发顺序 onLoad → onShow → onReady → onHide → onUnload 各个页面生命周期介绍 一、onLoad 触发时机&…

【MySQL】事务

目录 基本概念事务操作自动提交事务开启事务提交事务回滚事务代码示例 事务的特性 ACID事务的隔离级别读未提交 read uncommitted读已提交 read committed可重复读 repeatable read序列化&#xff08;串行&#xff09; serializable操作示例 基本概念 在 MySQL 中的事务&#…

SQL 通配符

SQL 通配符 在SQL查询中&#xff0c;通配符是一种非常有用的特性&#xff0c;它允许用户在查询时使用特殊字符来匹配一系列的值。本文将详细介绍SQL中的通配符及其用法&#xff0c;帮助读者更好地理解如何在SQL查询中使用通配符。 1. 什么是通配符&#xff1f; 通配符是SQL查…

PRODIGY: “不折腾人”的蛋白-蛋白/蛋白-小分子结合能计算工具

PRODIGY&#xff08;全称为 PROtein binDIng enerGY prediction&#xff09;是一种蛋白质结合能预测工具&#xff0c;可利用蛋白质-蛋白质复合物的三维结构来预测其结合亲和力。PRODIGY 利用一种高效的基于接触的方法&#xff0c;在估计结合自由能和解离常数的同时&#xff0c;…