You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 6中WPF通过SignalR接收MVC实时更新无响应问题

问题描述

我有一个WPF应用,点击按钮时会向ASP.NET Core 6 MVC应用发送请求。MVC控制器的动作方法会调用一个带循环的长任务方法,我想用SignalR实时更新WPF的标签,显示当前循环的迭代次数。但现在的问题是:点击按钮后,任务执行期间标签完全没变化,只有任务结束时才显示最后一次的迭代数值。我猜是同步/异步的问题,但作为新手搞不懂原理。

WPF按钮处理代码

private async void myButton_Click(object sender, RoutedEventArgs e) {
    HubConnection connection = new HubConnectionBuilder().WithUrl("https://localhost:7036/miHub").Build();
    await connection.StartAsync();
    connection.On<string>("Notify", (str) => { lblProgress.Content = str; });

    //calls mvc controller action 
    string url = "https://localhost:7036/Sincro/procesa";

    using (var httpClient = new HttpClient()) {
        string json = await httpClient.GetStringAsync(url);
    }
}

MVC控制器代码

public class SincroController : Controller {
    private readonly IHubContext<MiHub> _hubContext;
    
    //ctor
    public SincroController(IHubContext<MiHub> hubContext) {
        _hubContext = hubContext;
    }
    
    public async Task<JsonResult> procesa() {
        await longProcess();
        
        var json = new { foo = "bar" };
        return Json(json);
    }
    
    private async Task<int> longProcess() {
        for(int row=0; row<5000; row++) {
            await _hubContext.Clients.All.SendAsync("Notify", $"Processing thing {row}");
        }
        return 0;
    }
}
解决方案

核心问题分析

  1. WPF跨线程UI访问限制:WPF的UI控件只能由创建它的UI线程更新,SignalR的回调是在后台线程触发的,直接修改标签会被WPF阻止,导致界面无响应。
  2. MVC端消息积压:longProcess循环里连续调用SendAsync但没有让出线程,ASP.NET Core会把消息缓存起来,直到整个任务完成才一次性推送,所以前端只能收到最后一条。

具体修复步骤

1. 修复WPF的UI线程更新问题

修改SignalR的回调逻辑,通过Dispatcher切换回UI线程更新标签:

connection.On<string>("Notify", (str) => {
    // 切换到UI线程执行更新操作
    Application.Current.Dispatcher.Invoke(() => {
        lblProgress.Content = str;
    });
});

2. 解决MVC端的消息积压问题

在循环中添加短暂的延迟,让ASP.NET Core有机会及时推送已发送的SignalR消息:

private async Task<int> longProcess() {
    for(int row=0; row<5000; row++) {
        await _hubContext.Clients.All.SendAsync("Notify", $"Processing thing {row}");
        // 让出线程,避免消息批量积压
        await Task.Delay(1);
    }
    return 0;
}

3. 优化SignalR连接生命周期(可选)

每次点击按钮创建新连接会浪费资源,建议把连接实例提升为类字段,提前初始化:

private HubConnection _hubConnection;

public MainWindow() {
    InitializeComponent();
    // 初始化SignalR连接
    _hubConnection = new HubConnectionBuilder().WithUrl("https://localhost:7036/miHub").Build();
    _hubConnection.On<string>("Notify", (str) => {
        Application.Current.Dispatcher.Invoke(() => {
            lblProgress.Content = str;
        });
    });
    // 提前启动连接,无需每次点击都重新建立
    _ = _hubConnection.StartAsync();
}

private async void myButton_Click(object sender, RoutedEventArgs e) {
    string url = "https://localhost:7036/Sincro/procesa";
    using (var httpClient = new HttpClient()) {
        string json = await httpClient.GetStringAsync(url);
    }
}

内容的提问来源于stack exchange,提问作者patsy2k

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 17:13:18