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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:03:39