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

.NET 8 Blazor SSR异步操作后通知无法显示问题求助

.NET 8 Blazor SSR异步操作后通知不显示的解决方案

问题分析

你的代码在同步抛出异常时通知正常显示,但添加await异步操作(比如Task.Delay或数据库调用)后,即便通知服务的Notify方法被执行,通知组件却无法显示。核心原因有两点:

  • 异步操作完成后,事件触发的线程可能不在Blazor的渲染同步上下文中,直接调用StateHasChanged()无法触发页面重新渲染。
  • Notification组件的Open()方法仅修改了内部状态_open,但没有通知Blazor需要更新组件渲染。

修复步骤

1. 修复Notification组件,添加状态更新通知

修改Notification组件的Open()方法,调用StateHasChanged()通知Blazor重新渲染组件:

public partial class Notification
{
    private bool _open;

    [Parameter]
    public NotificationLevel NotificationLevel { get; set; }

    [Parameter]
    public string Message { get; set; }

    public void Open()
    {
        _open = true;
        // 通知Blazor组件状态已变更,需要重新渲染
        StateHasChanged();
    }
}

2. 在布局的事件处理方法中使用InvokeAsync确保上下文正确

Blazor SSR中,异步操作后的事件回调可能在非UI线程执行,此时需要用InvokeAsync()包装状态更新逻辑,确保在正确的同步上下文中调用StateHasChanged():

public partial class MainLayout : IDisposable
{
    [Inject]
    private NotificationService _errorNotification { get; set; }

    public Notification _notificationReference;
    private string _errorMessage;
    private NotificationLevel _notificationLevel;

    protected override void OnInitialized()
    {
        base.OnInitialized();
        _errorNotification.Error += SetErrorNotificationListener;
    }

    private async void SetErrorNotificationListener(object? sender, Services.ErrorEventArgs args)
    {
        // 使用InvokeAsync确保在Blazor渲染上下文内执行
        await InvokeAsync(() =>
        {
            _errorMessage = args.ErrorMessage;
            _notificationLevel = args.NotificationLevel;
            _notificationReference.Open();
            StateHasChanged();
        });
    }

    // 移除事件订阅避免内存泄漏
    public void Dispose()
    {
        _errorNotification.Error -= SetErrorNotificationListener;
    }
}

3. 可选:优化通知服务的事件触发(进阶)

如果你的通知服务可能在非UI线程触发事件,可以修改Notify方法,确保事件在Blazor同步上下文执行(依赖IJSRuntime触发上下文绑定):

public class NotificationService : IDisposable
{
    private static readonly object _errorEvent = new();
    private readonly EventHandlerList _events = new();
    private readonly IJSRuntime _jsRuntime;

    public NotificationService(IJSRuntime jsRuntime)
    {
        _jsRuntime = jsRuntime;
    }

    public void Dispose()
    {
        _events?.Dispose();
    }

    public event EventHandler<ErrorEventArgs> Error
    {
        add => _events.AddHandler(_errorEvent, value);
        remove => _events.RemoveHandler(_errorEvent, value);
    }

    public async void Notify(string errorMessage, NotificationLevel notificationLevel)
    {
        if (_events[_errorEvent] is not EventHandler<ErrorEventArgs> handler) return;
        var eventArgs = new ErrorEventArgs(errorMessage, notificationLevel);
        // 触发Blazor同步上下文,确保事件在UI线程执行
        await _jsRuntime.InvokeAsync<object>("eval", "0");
        handler?.Invoke(this, eventArgs);
    }
}

验证修复

修改后重新运行代码,添加await Task.Delay(1000)后抛出异常,通知应该能正常显示。核心是确保状态变更和组件更新操作都在Blazor的渲染同步上下文中执行,异步场景下必须通过InvokeAsync()来包装相关逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 19:45:32