使用C# ASP.NET创建一个可以由服务端推送信息至客户端的WEB应用(1)

背景

用户在WEB页面上点击按钮,服务端需要执行一系列操作,该操作系列步骤较多且耗时长,为了更好的给用户浏览体验,需要在每进行一个步骤由服务端推送消息给客户端(浏览器),避免一个长时间的操作在用户看来是没有进度的过程。

环境

C# ASP.NET VS2022 WIN10 64位

主要使用 Microsoft.AspNet.SignalR 组件实现

步骤

1.创建ASP.NET Web应用程序





2. 通过 NuGet 包管理器安装 Microsoft.AspNet.SignalR




安装完成后会增加下述JS脚本在项目中:

此时直接运行之前Default.aspx会报错,如下图:

这个错误是因为使用SignalR时,需要有一个OWIN启动类来配置SignalR的中间件。OWIN(Open Web Interface for .NET)是一个标准,用于定义.NET Web应用程序和Web服务器之间的接口。

3. 后台代码

3.1 使用 OWIN 中间件来配置 SignalR

增加启动类 StartUp.cs,命名空间适配自己的,需要引用Microsoft.Owin

csharp 复制代码
using Microsoft.Owin;
using Owin;
using System;
using System.Web;

[assembly: OwinStartup(typeof(SignalRTest.Startup))]

namespace SignalRTest
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // 配置SignalR
            app.MapSignalR();
        }
    }
}

此时运行WEB应用,页面不再报错

3.2 增加ProcessHub类

csharp 复制代码
using Microsoft.AspNet.SignalR;
using System;
using System.Threading.Tasks;
using System.Threading;
using System.Web;

namespace SignalRTest
{
    public class ProcessHub : Hub
    {
        // 这个方法将被服务端直接调用,用于向客户端发送进度消息
        public static void SendProgress(string message)
        {
            var hubContext = GlobalHost.ConnectionManager.GetHubContext<ProcessHub>();
            hubContext.Clients.All.updateProgress(message);
        }
    }
}

4. 前端代码

在ASP.NET页面的 head 部分增加 JS代码

js 复制代码
<!-- 引用 jQuery (SignalR 依赖) -->
<script src="Scripts/jquery-1.6.4.min.js"></script>
<!-- 引用 SignalR JavaScript 客户端 -->
<script src="Scripts/jquery.signalR-2.4.3.min.js"></script>
<!-- 引用 SignalR 代理脚本 -->
<script src="/signalr/hubs"></script>
    <script type="text/javascript">
        $(function () {
            // 获取 SignalR hub 的代理
            var processHub = $.connection.processHub;

            // 定义客户端接收进度更新的方法
            processHub.client.updateProgress = function (message) {
                $('#progressDiv').append('<p>' + message + '</p>');
            };

            // 启动连接
            $.connection.hub.start().done(function () {
                console.log('SignalR 连接已建立');
            }).fail(function (error) {
                console.log('SignalR 连接失败: ' + error);
            });
        });
    </script>

body 表单部分 增加相应的控件

Button 用于响应用户操作

progressDiv 用于展示进度文本

html 复制代码
    <form id="form1" runat="server">
        <div>
            <h2>SignalR 进度示例</h2>
            <asp:Button ID="btnProcess" runat="server" Text="开始处理" OnClick="btnProcess_Click" />
            <hr />
            <div id="progressDiv" style="border: 1px solid #ccc; padding: 10px; margin-top: 10px; min-height: 100px; height: 470px;"></div>
        </div>
    </form>

注意
<script src="/signalr/hubs">

必须要有,启动页面后控制台可见输出:

4.1 前端页面的后台代码

csharp 复制代码
using Microsoft.AspNet.SignalR.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace SignalRTest
{
	public partial class Default : System.Web.UI.Page
	{
		protected void Page_Load(object sender, EventArgs e)
		{
		}

        protected void btnProcess_Click(object sender, EventArgs e)
        {
            // 创建一个任务来异步处理Excel生成
            Task.Run(() => ProcessData());
        }

        private void ProcessData()
        {
            Thread.Sleep(100);
            ProcessHub.SendProgress("开始处理数据...");
            Thread.Sleep(1000);

            // 模拟处理2024年数据
            ProcessHub.SendProgress("正在处理2024年的数据...");
            Thread.Sleep(5000);  // 模拟处理需要5秒

            // 模拟处理2025年数据
            ProcessHub.SendProgress("正在处理2025年的数据...");
            Thread.Sleep(5000);  // 模拟处理需要5秒

            ProcessHub.SendProgress("数据处理完成!");
        }
    }
}

注意:

由于按钮没有使用AJAX提交,第一个SendProgress之前若没有Thread.Sleep,容易丢失第一条信息。

后记

没有处理的问题有很多,只作为一个最基础功能的展现

  1. 进度发给了所有客户端,即打开多个进程一个页面上点击所有的都会收到

  2. 没有取消功能,即使关闭浏览器代码依旧在服务端执行

  3. 按钮在点击后没有禁用,单页面上会触发多次点击

  4. 进度文本堆积,没有自动下滚

相关推荐
Irene19912 小时前
ElementPlus 与成熟后台框架对比:vue-element-plus-admin、vue-pure-admin等
前端·ui·框架·vue3
尘中客6 小时前
放弃 Echarts?前端直接渲染后端高精度 SVG 矢量图流的踩坑记录
前端·javascript·echarts·前端开发·svg矢量图·echarts避坑
FreeBuf_6 小时前
Chrome 0Day漏洞遭野外利用
前端·chrome
小彭努力中7 小时前
199.Vue3 + OpenLayers 实现:点击 / 拖动地图播放音频
前端·vue.js·音视频·openlayers·animate
2501_916007477 小时前
网站爬虫原理,基于浏览器点击行为还原可接口请求
前端·javascript·爬虫·ios·小程序·uni-app·iphone
前端大波7 小时前
Sentry 每日错误巡检自动化:设计思路与上手实战
前端·自动化·sentry
ZC跨境爬虫8 小时前
使用Claude Code开发校园交友平台前端UI全记录(含架构、坑点、登录逻辑及算法)
前端·ui·架构
慧一居士8 小时前
Vue项目中,何时使用布局、子组件嵌套、插槽 对应的使用场景,和完整的使用示例
前端·vue.js
Можно8 小时前
uni.request 和 axios 的区别?前端请求库全面对比
前端·uni-app
M ? A9 小时前
解决 VuReact 中 ESLint 规则冲突的完整指南
前端·react.js·前端框架