Blazor Server模式下刷新页面时如何立即清理Timer资源?
解决Blazor Server页面刷新/导航时立即清理Timer的问题
在.NET 8 RC1的Blazor Server应用中,组件的Dispose方法会因SignalR连接超时(默认2-3分钟)延迟执行,导致刷新页面后旧Timer实例持续运行。要避免这种情况,需主动在页面离开时清理Timer,以下是两种可靠的实现方式:
方法一:监听NavigationManager导航事件
利用NavigationManager的LocationChanged事件捕获页面刷新、路由跳转等离开操作,立即停止并释放Timer:
@page "/timer-page" @inject NavigationManager NavManager @implements IDisposable <h3>Timer Demo Page</h3> @code { private System.Timers.Timer? _timer; private IDisposable? _navigationSubscription; protected override void OnInitialized() { // 初始化Timer,每秒执行一次回调 _timer = new System.Timers.Timer(1000); _timer.Elapsed += TimerElapsed; _timer.Start(); // 订阅导航变化事件 _navigationSubscription = NavManager.LocationChanged += OnLocationChanged; } private void TimerElapsed(object? sender, System.Timers.ElapsedEventArgs e) { // Timer执行的业务逻辑 Console.WriteLine($"Timer tick: {DateTime.Now:HH:mm:ss}"); } private void OnLocationChanged(object? sender, LocationChangedEventArgs e) { // 导航离开时停止并清理Timer _timer?.Stop(); _timer?.Dispose(); _timer = null; } public void Dispose() { // 清理事件订阅和Timer资源 _navigationSubscription?.Dispose(); _timer?.Stop(); _timer?.Dispose(); } }
说明:
LocationChanged事件会在页面刷新、前进后退、路由跳转时触发,能及时捕获用户离开当前页面的操作- 操作Timer时先调用
Stop()(或Change(Timeout.Infinite, Timeout.Infinite))停止计时,再执行Dispose,避免回调逻辑在清理后仍执行
方法二:结合CancellationToken实现可控取消
通过CancellationTokenSource生成取消令牌,在导航离开时触发取消,Timer回调中检查令牌状态并自行清理:
@page "/timer-page" @inject NavigationManager NavManager @implements IDisposable <h3>Timer Demo Page</h3> @code { private System.Timers.Timer? _timer; private CancellationTokenSource _cts = new(); private IDisposable? _navigationSubscription; protected override void OnInitialized() { _timer = new System.Timers.Timer(1000); // 将取消令牌传入Timer回调 _timer.Elapsed += (s, e) => TimerElapsed(_cts.Token); _timer.Start(); _navigationSubscription = NavManager.LocationChanged += (s, e) => _cts.Cancel(); } private void TimerElapsed(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { // 令牌取消时停止并清理Timer _timer?.Stop(); _timer?.Dispose(); _timer = null; return; } Console.WriteLine($"Timer tick: {DateTime.Now:HH:mm:ss}"); } public void Dispose() { _navigationSubscription?.Dispose(); _cts.Cancel(); _cts.Dispose(); _timer?.Stop(); _timer?.Dispose(); } }
核心思路:
Blazor Server组件的生命周期依赖SignalR连接,页面刷新后旧连接不会立即断开,导致Dispose延迟执行。因此必须主动监听导航事件,在用户离开页面时立即清理Timer资源,而不是依赖组件的Dispose方法。
内容的提问来源于stack exchange,提问作者zyash
相关产品推荐
相关产品推荐

