如何在Blazor Server中检测页面刷新并跳过特定Dispose操作?
在Blazor Server中区分页面刷新与正常导航/关闭的解决方案
要解决刷新页面时不执行Dispose里的数据库操作问题,核心思路是通过JavaScript监听浏览器的beforeunload事件(仅在刷新、关闭浏览器、跳转外部页面时触发),结合Blazor内部导航事件标记当前Dispose的触发原因,具体实现步骤如下:
1. 组件代码修改
在你的组件中注入IJSRuntime和NavigationManager,添加状态标记并监听相关事件:
@inject IJSRuntime JSRuntime @inject NavigationManager NavigationManager @implements IDisposable @implements IAsyncDisposable <!-- 你的组件内容 --> @code { private bool _isPageRefreshing; private DotNetObjectReference<YourComponent>? _dotNetComponentRef; protected override async Task OnInitializedAsync() { // 创建组件的DotNet引用,供JS调用 _dotNetComponentRef = DotNetObjectReference.Create(this); // 注册浏览器beforeunload事件监听 await JSRuntime.InvokeVoidAsync("registerBeforeUnload", _dotNetComponentRef); // 监听Blazor内部导航事件,重置刷新标记 NavigationManager.LocationChanged += OnInternalNavigation; } // 供JS调用的方法,标记页面即将刷新/关闭 [JSInvokable] public void SetPageRefreshingFlag() { _isPageRefreshing = true; } private void OnInternalNavigation(object? sender, LocationChangedEventArgs e) { // 内部导航切换页面时,重置标记为false _isPageRefreshing = false; } public void Dispose() { // 移除导航事件监听 NavigationManager.LocationChanged -= OnInternalNavigation; _dotNetComponentRef?.Dispose(); // 仅在非刷新场景下执行数据库操作 if (!_isPageRefreshing) { lockingService.Unlock(componentName, CurrentUserID); lockingService.NotifierLockingState -= RefreshUserInterface!; } } public async ValueTask DisposeAsync() { // 异步移除JS事件监听,避免内存泄漏 if (_dotNetComponentRef != null) { await JSRuntime.InvokeVoidAsync("unregisterBeforeUnload", _dotNetComponentRef); _dotNetComponentRef.Dispose(); } } }
2. 添加JavaScript代码
在你的wwwroot目录下创建或修改site.js文件,添加以下事件注册/移除逻辑:
// 注册beforeunload事件,触发时通知Blazor组件 window.registerBeforeUnload = function (dotNetRef) { const beforeUnloadHandler = () => { dotNetRef.invokeMethodAsync('SetPageRefreshingFlag'); }; window.addEventListener('beforeunload', beforeUnloadHandler); // 缓存处理函数,用于后续移除 window._blazorBeforeUnloadHandler = beforeUnloadHandler; }; // 移除beforeunload事件监听 window.unregisterBeforeUnload = function () { if (window._blazorBeforeUnloadHandler) { window.removeEventListener('beforeunload', window._blazorBeforeUnloadHandler); delete window._blazorBeforeUnloadHandler; } };
原理说明
beforeunload事件仅在浏览器刷新、关闭窗口、跳转到外部网站时触发,Blazor内部的路由导航(如通过NavLink切换页面)不会触发该事件。- 当
beforeunload触发时,JS会调用Blazor组件的SetPageRefreshingFlag方法,将_isPageRefreshing设为true。 - Blazor内部导航时,
LocationChanged事件会触发,将_isPageRefreshing重置为false,此时Dispose中的数据库操作会正常执行。 - 最终在Dispose方法中,根据
_isPageRefreshing的值判断是否执行数据库操作,从而跳过页面刷新的场景。
内容的提问来源于stack exchange,提问作者Zohair
相关产品推荐
相关产品推荐

