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

Blazor Server应用定时器定时更新页面运行一段时间后停止问题求助

故障原因分析

  • 定时器被GC意外回收:初始版本的System.Threading.Timer是OnInitialized方法内的局部变量,没有实例级别的根引用,运行一段时间后GC触发回收时会销毁定时器,直接导致回调停止执行。
  • 异步阻塞引发死锁:两个版本的代码都用.Result同步阻塞等待异步方法返回,Blazor Server每个Circuit存在专属同步上下文,阻塞等待会导致同步上下文被占满,异步方法完成调度时无法获取上下文资源,形成死锁,后续定时器回调将无法被正常执行。
  • 数据库同步查询阻塞:数据库查询使用同步方法Single而非异步实现,数据库IO延迟时会占用线程池资源,高频率调用下容易导致线程池耗尽,定时器回调无法被调度。

解决方案

  1. 将定时器声明为组件的实例字段,避免作为局部变量被GC回收
  2. 全链路使用await实现异步调用,移除所有.Result、.Wait()类阻塞代码,规避死锁风险
  3. 数据库操作替换为异步实现,减少线程池资源占用
  4. 正确实现IAsyncDisposable接口,组件销毁时主动释放定时器资源

修正后的完整代码

@page "/Refresh2"
@inject IDbContextFactory<SQLbeginnerContext> DbFactory
@using TestBlazorServer.Models
@using Microsoft.EntityFrameworkCore
@using System.Timers
@implements IAsyncDisposable

<h3>PageRefresh2</h3>
<h1>@Time</h1>
<h1>@currentCount</h1>
<h1>TestValue:@databaseValue</h1>

@code {
    private int currentCount = 0;
    // 声明为实例字段,防止GC回收
    private readonly Timer _timer2 = new(1000);
    private string Time { get; set; }
    private int? databaseValue { get; set; }

    protected override void OnInitialized()
    {
        _timer2.Elapsed += async (sender, eventArgs) => await OnTimerCallback();
        _timer2.AutoReset = true;
        _timer2.Start();
    }

    private async Task OnTimerCallback()
    {
        await InvokeAsync(async () =>
        {
            currentCount++;
            Time = DateTime.Now.ToString();
            // 用await替代.Result,避免同步阻塞
            databaseValue = await TimerProcessGetValue();
            StateHasChanged();
        });
    }

    // 异步释放定时器资源
    public async ValueTask DisposeAsync()
    {
        await _timer2.DisposeAsync();
    }

    public async Task<int?> TimerProcessGetValue()
    {
        int? timerProcessValue;
        await using (var dbContext = DbFactory.CreateDbContext())
        {
            // 数据库查询替换为异步实现,减少线程阻塞
            timerProcessValue = (await dbContext.TestTable.SingleAsync(x => x.Id == 1)).TestValue;
        }
        return timerProcessValue;
    }
}

额外说明

如果修改后仍然出现长时间运行后停止的情况,大概率是Blazor Server的Circuit被服务器判定为空闲后回收,属于服务端正常的资源回收机制,可在前端添加简单的定时心跳逻辑,避免Circuit被判定为 idle 状态。

内容的提问来源于stack exchange,提问作者BTOM

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 21:54:06