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

Blazor Server中更新ApplicationState的ErrorMessage时出现重复通知问题

Blazor Server中更新ApplicationState的ErrorMessage时出现重复通知问题

看起来你遇到了设置ErrorMessage时重复触发错误通知的问题,我来帮你分析一下可能的原因和对应的解决办法:

首先排查最可能的两个方向:事件重复订阅、ErrorMessage被重复设置

1. 事件被多次订阅(最常见原因)

你的MainLayout在firstRender时订阅AppState.OnNotification事件,Dispose时取消订阅,但如果MainLayout的实例被创建了多个(比如组件重复渲染、布局被嵌套使用),或者Dispose方法没有被正确调用,就会导致多个实例同时订阅事件,每次触发都会执行多次ShowNotification。

验证方式:
在MainLayout的关键方法里加日志输出,看看订阅和取消订阅的执行情况:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender && AppState is not null)
    {
        AppState.OnNotification += OnNotificationHandler;
        Console.WriteLine("MainLayout: 已订阅OnNotification事件");
    }
    await base.OnAfterRenderAsync(firstRender);
}

public void Dispose()
{
    if (AppState is not null)
    {
        AppState.OnNotification -= OnNotificationHandler;
        Console.WriteLine("MainLayout: 已取消订阅OnNotification事件");
    }
}

如果控制台输出多次“已订阅”但没有对应的“已取消订阅”,说明有MainLayout实例没有被销毁,导致重复订阅。

解决办法:

  • 检查应用的布局结构,确保MainLayout只作为全局布局仅使用一次,没有在多个页面/组件中重复引用或嵌套。
  • 改用WeakEventManager来管理事件,避免订阅者未正确取消订阅导致的内存泄漏和重复触发。修改ApplicationState的事件实现:
using Microsoft.Extensions.DependencyInjection;
using System.ComponentModel;

public class ApplicationState
{
    private readonly WeakEventManager _notificationEventManager = new WeakEventManager();
    private string _errorMessage = string.Empty;

    public string ErrorMessage
    {
        get => _errorMessage;
        set
        {
            if (!string.Equals(_errorMessage, value) && !string.IsNullOrWhiteSpace(value))
            {
                _errorMessage = value;
                ShowError();
            }
            else
            {
                _errorMessage = value;
            }
        }
    }

    public event Action? OnNotification
    {
        add => _notificationEventManager.AddEventHandler(value);
        remove => _notificationEventManager.RemoveEventHandler(value);
    }

    public void ShowError()
    {
        _notificationEventManager.HandleEvent(this, EventArgs.Empty, nameof(OnNotification));
        _errorMessage = string.Empty;
    }
}

WeakEventManager会自动处理订阅者被销毁后的事件清理,避免无效订阅导致的重复触发。

2. ErrorMessage被重复设置

如果ErrorMessage的setter被调用了两次,自然会触发两次事件。你可以在setter里加日志验证:

public string ErrorMessage
{
    get => _errorMessage;
    set
    {
        Console.WriteLine($"ErrorMessage设置: 当前值={_errorMessage}, 新值={value}");
        if (!string.Equals(_errorMessage, value) && !string.IsNullOrWhiteSpace(value))
        {
            _errorMessage = value;
            ShowError();
        }
        else
        {
            _errorMessage = value;
        }
    }
}

如果控制台输出两次相同的“新值=Some error”,那你需要检查点击按钮的代码逻辑,看看是不是不小心执行了两次赋值操作,或者有没有Blazor绑定/状态变化导致的重复赋值。

关于渲染模式的疑问

你提到了渲染模式的问题,目前你的Routes和AntContainer都使用了InteractiveServerRenderMode(prerender: false),只要你的App.razor中MainLayout是作为全局布局仅使用一次,这个设置本身不会直接导致重复订阅。但如果AntContainer组件内部也引用了MainLayout,就会导致多个布局实例,这时候就需要调整组件结构,避免重复使用布局。

额外的优化建议

在ShowNotification方法中,你可以先捕获当前的ErrorMessage值,避免因为ShowError()里清空_errorMessage导致后续拿到空值(不过你这个场景里事件触发时ErrorMessage还没被清空,所以影响不大,但养成这个习惯更稳妥):

private async Task ShowNotification()
{
    if (AppState is not null)
    {
        var errorMsg = AppState.ErrorMessage;
        if (!string.IsNullOrWhiteSpace(errorMsg))
        {
            await Notice.Error(new NotificationConfig()
            {
                Message = errorMsg
            });
        }
    }
}

你可以先按上面的步骤排查,看看是事件重复订阅还是重复赋值导致的问题,应该就能解决两次通知的情况了。

备注:内容来源于stack exchange,提问作者Victor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 10:48:03