.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
相关产品推荐
相关产品推荐

