C#通过SignalR直接返回流式响应内容

news/2025/3/20 20:06:12/

1、背景

实现流式响应基本上分为两大技术方案:(1)基于HTTP的Stream处理;(2)基于socket的连接。前者的实现方式有:《C#通过API接口返回流式响应内容—SSE方式》和《C#通过API接口返回流式响应内容—分块编码方式》。后者有:《C#通过API接口返回流式响应内容—SignalR方式》。
在上一篇的SignalR文章中,本质上还是是用socket发消息的功能,但实际上SignalR本身也是支持流式处理的。本篇阐述通过SignalR直接返回流式内容。并且个人认为比较适合DeepSeek流式响应的。

2、效果

在这里插入图片描述

3、具体代码

3.1 服务器端的代码

新创建一个StreamHub,实现Hub功能
在这里插入图片描述
具体代码如下:

using Microsoft.AspNetCore.SignalR;
using System.Threading.Channels;namespace SignalRHub.Hubs
{public class StreamHub:Hub{public ChannelReader<string> DeepSeekStream(string inputStr,CancellationToken cancellationToken){var channel = Channel.CreateUnbounded<string>();_ = WriteItemsAsync(channel.Writer, inputStr, cancellationToken);return channel.Reader;}//将返回的内容写入到流中private async Task WriteItemsAsync(ChannelWriter<string> writer,string inputStr,CancellationToken cancellationToken){Exception localException = null;try{//模拟deepseek的对话内容var phrases = new string[] { "你好!", "我是", "北京清华长庚医院", "信息管理部的", "郑林" };foreach (var item in phrases){await writer.WriteAsync(item, cancellationToken);await Task.Delay(1000, cancellationToken);}}catch (Exception ex){localException = ex;}finally{writer.Complete(localException);}}}
}

3.2 前端代码

<!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 stockPricesDiv = document.getElementById("stockPrices");stockPricesDiv.addEventListener("click", (event) =>{sendMsgAndReturnStream("Hello");});const connection = new signalR.HubConnectionBuilder().withUrl("http://localhost:5071/dsstream").configureLogging(signalR.LogLevel.Information).build();async function start() {try {await connection.start().then(() => {sendMsgAndReturnStream("Hello");});console.log("SignalR Connected.");} catch (err) {console.log(err);setTimeout(start, 5000);}};connection.onclose(async () => {await start();});// Start the connection.start();function sendMsgAndReturnStream(msg){connection.stream("DeepSeekStream", msg).subscribe({next: (item) => {stockPricesDiv.innerHTML+= item +'&nbsp;'; },complete: () => {stockPricesDiv.innerHTML+= "已完成"; },error: (err) => {stockPricesDiv.innerHTML+= "异常"+err; },});}</script>
</body>
</html>

4、参考资料

1、在 ASP.NET Core SignalR 中使用流式传输


http://www.ppmy.cn/news/1580670.html

相关文章

【PCB工艺】基础:电子元器件

电子原理图&#xff08;Schematic Diagram&#xff09;是电路设计的基础&#xff0c;理解电子元器件和集成电路&#xff08;IC&#xff09;的作用&#xff0c;是画好原理图的关键。 本专栏将系统讲解 电子元器件分类、常见 IC、电路设计技巧&#xff0c;帮助你快速掌握电子电路…

STM32之I2C硬件外设

注意&#xff1a;硬件I2C的引脚是固定的 SDA和SCL都是复用到外部引脚。 SDA发送时数据寄存器的数据在数据移位寄存器空闲的状态下进入数据移位寄存器&#xff0c;此时会置状态寄存器的TXE为1&#xff0c;表示发送寄存器为空&#xff0c;然后往数据控制寄存器中一位一位的移送数…

【VSCode】VSCode常用插件

Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code&#xff1a;简体中文支持插件HTML/CSS/JavaScript Snippets&#xff1a;支持HTML/CSS/JavaScript快速匹配输入HTML Snippets&#xff1a;这个插件提供了一系列 HTML 代码片段&#xff0c;通过简单的缩写…

单片机自学总结

自从工作以来&#xff0c;一直努力耕耘单片机&#xff0c;至今&#xff0c;颇有收获。从51单片机&#xff0c;PIC单片机&#xff0c;直到STM32&#xff0c;以及RTOS和Linux&#xff0c;几乎天天在搞:51单片机&#xff0c;STM8S207单片机&#xff0c;PY32F003单片机&#xff0c;…

vue 获取当前时间并自动刷新

新增需求&#xff0c;需要在大屏的右上角展示当前时间&#xff0c;并实时按秒刷新&#xff0c;通过通义千问搜索关键js代码后&#xff0c;整理出如下代码。 【效果图】 【HTML】 <div class"time-wrap">{{ formattedDateTime }}<span> {{ weekTime }}&…

前端小食堂 | Day18 - 身份认证の八卦阵

&#x1f510; 今日秘术&#xff1a;JWT/OAuth2 攻防奥义 1. JWT 安全の六合阵法 // &#x1f6ab; 危险操作&#xff1a;未验证签名 const decodeUnsafe (token) > JSON.parse(atob(token.split(.)[1])); // ✅ 安全姿势一&#xff1a;严格签名验证 import jwt fro…

idea2024创建maven web项目

1、file->new->project->MavenArchetype&#xff0c;在右侧“Archetype”处选择 “org.apache.maven.archetypes:maven-archetype-webapp”&#xff0c;点击“create”创建项目。 2、配置tomcat&#xff0c;如下图所示&#xff1a; 设置上下文路径后&#xff0…

三分钟掌握视频分辨率修改 | 在 Rust 中优雅地使用 FFmpeg

前言 在视频处理领域&#xff0c;调整视频分辨率是一个绕不过去的需求。比如&#xff0c;你可能需要将一段视频适配到手机、平板或大屏电视上&#xff0c;或者为了节省存储空间和网络带宽而压缩视频尺寸。然而&#xff0c;传统的FFmpeg命令行工具虽然功能强大&#xff0c;但复…