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

.NET Core 7 SignalR:如何通过DI实现定时统计更新

问题分析与解决方案

核心问题梳理

  1. 依赖注入方式错误:私有方法GetStats中使用[FromServices]无效,ASP.NET Core仅支持构造函数/公共方法参数注入,私有方法无法通过该特性获取服务。
  2. 异步操作未正确等待:原TimerManager中直接调用异步Action会导致未捕获的异步异常,且无法保证操作执行完成。
  3. 重复创建定时器:每个客户端连接时都创建新定时器,导致重复推送相同数据,资源浪费。

重构后的代码实现

1. 修正TimerManager以支持异步操作

public class TimerManager
{
    private Timer _timer;
    private Func<Task> _asyncAction;
    
    public DateTime TimerStarted { get; set; }
    public bool IsTimerStarted { get; set; }

    public void PrepareTimer(Func<Task> asyncAction, int delayMS)
    {
        _asyncAction = asyncAction;
        // 使用异步回调处理逻辑
        _timer = new Timer(async _ => await ExecuteAsync(), null, 1000, delayMS);
        TimerStarted = DateTime.Now;
        IsTimerStarted = true;
    }

    private async Task ExecuteAsync()
    {
        await _asyncAction();

        // 保留原120秒自动停止逻辑,如需永久运行可删除此判断
        if ((DateTime.Now - TimerStarted).TotalSeconds <= 120)
            return;

        IsTimerStarted = false;
        _timer.Dispose();
    }
}

2. 重构StatsHub使用构造函数注入

[Authorize]
public class StatsHub : Hub
{
    private readonly IQueueService _queueService;
    private readonly TimerManager _timerManager;

    // 通过构造函数注入依赖服务
    public StatsHub(IQueueService queueService, TimerManager timerManager)
    {
        _queueService = queueService;
        _timerManager = timerManager;
    }

    public override async Task OnConnectedAsync()
    {
        // 仅当定时器未启动时初始化,避免重复创建
        if (!_timerManager.IsTimerStarted)
        {
            _timerManager.PrepareTimer(async () =>
            {
                var results = await _queueService.GetStats();
                await Clients.All.SendAsync("SendQueueStats", results.Payload);
            }, 15000);
        }

        await base.OnConnectedAsync();
    }
}

3. 配置服务注册(Program.cs)

确保TimerManager注册为单例,保证全局仅一个定时器实例:

builder.Services.AddSingleton<TimerManager>();
builder.Services.AddScoped<IQueueService, QueueService>(); // 替换为你的实现类
builder.Services.AddSignalR();

关键优化说明

  • 构造函数注入:通过构造函数获取依赖服务,符合ASP.NET Core DI规范,确保服务生命周期正确管理。
  • 异步安全定时器:将原同步Action改为Func<Task>,并在定时器回调中异步等待操作完成,避免异步异常丢失。
  • 全局单例定时器:仅在第一个客户端连接时启动定时器,避免重复推送和资源浪费。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 14:02:34