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

Blazor WASM中API控制器无法触发Razor组件EventHandler

问题分析与解决方案

核心问题

你遇到的问题本质是Blazor WASM客户端与服务端的Scoped服务是完全独立的实例:服务端API控制器注入的ITestMartInterface是服务端进程内的实例,而客户端Razor组件订阅的是浏览器进程内的客户端实例,两者没有任何关联。服务端触发的事件只会在自己的实例上执行,客户端组件根本接收不到。

正确解决方案:使用SignalR实现服务端到客户端的实时推送

Blazor WASM是纯客户端运行的应用,服务端无法直接调用客户端内存中的对象或事件,必须通过跨进程实时通讯机制实现,SignalR是官方推荐的标准方案。

步骤1:服务端配置SignalR

  1. 安装SignalR包:
Install-Package Microsoft.AspNetCore.SignalR
  1. 创建SignalR Hub类:
public class UpdateHub : Hub
{
    // 无需额外方法,仅作为服务端与客户端的通讯端点
}
  1. 在服务端Program.cs中注册并映射Hub:
// 注册SignalR服务
builder.Services.AddSignalR();

// 映射Hub路由
app.MapHub<UpdateHub>("/updateHub");
  1. 修改API控制器,注入IHubContext实现推送:
private readonly IHubContext<UpdateHub> _hubContext;

public AtsMessageReceivedController(IHubContext<UpdateHub> hubContext)
{
    _hubContext = hubContext;
}

[HttpGet]
// 替换async void为async Task,避免异步内存泄漏
public async Task Get()
{
    // 向所有连接的客户端推送更新通知
    await _hubContext.Clients.All.SendAsync("ReceiveUpdate");
}

步骤2:客户端配置SignalR

  1. 安装客户端SignalR包:
Install-Package Microsoft.AspNetCore.SignalR.Client
  1. 创建客户端SignalR服务,封装连接与事件订阅:
public interface IUpdateSignalRService
{
    event EventHandler UpdateReceived;
    Task StartConnectionAsync();
}

public class UpdateSignalRService : IUpdateSignalRService, IAsyncDisposable
{
    private readonly HubConnection _hubConnection;
    public event EventHandler UpdateReceived;

    public UpdateSignalRService()
    {
        // 替换为你的服务端实际地址
        var baseUrl = "https://your-server-address";
        _hubConnection = new HubConnectionBuilder()
            .WithUrl($"{baseUrl}/updateHub")
            .Build();

        // 订阅服务端推送的消息
        _hubConnection.On("ReceiveUpdate", () =>
        {
            UpdateReceived?.Invoke(this, EventArgs.Empty);
        });
    }

    public async Task StartConnectionAsync()
    {
        if (_hubConnection.State == HubConnectionState.Disconnected)
        {
            await _hubConnection.StartAsync();
        }
    }

    public async ValueTask DisposeAsync()
    {
        await _hubConnection.StopAsync();
        await _hubConnection.DisposeAsync();
    }
}
  1. 在客户端Program.cs注册该服务:
builder.Services.AddScoped<IUpdateSignalRService, UpdateSignalRService>();

步骤3:客户端Razor组件订阅事件

@inject IUpdateSignalRService signalRService
@implements IAsyncDisposable

@code {
    protected override async Task OnInitializedAsync()
    {
        // 启动SignalR连接
        await signalRService.StartConnectionAsync();
        // 订阅更新事件
        signalRService.UpdateReceived += DoStuff;
    }

    public async void DoStuff(object sender, EventArgs e)
    {
        // 执行你的业务代码
        // 如果需要更新UI,需手动调用StateHasChanged
        StateHasChanged();
    }

    // 组件销毁时取消订阅并释放资源
    public async ValueTask DisposeAsync()
    {
        signalRService.UpdateReceived -= DoStuff;
        await ((IAsyncDisposable)signalRService).DisposeAsync();
    }
}

关键注意事项

  • 移除原有的跨端共享ITestMartInterface的逻辑,因为两端实例完全隔离,无法实现跨进程事件触发。
  • 处理SignalR连接的异常与重连逻辑(可在UpdateSignalRService中添加Closed事件监听实现自动重连)。
  • 组件销毁时必须取消事件订阅并释放SignalR连接,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 00:56:20