.NET Core 7 SignalR 如何使用 DI 创建基于时间的统计更新

问题描述 投票:0回答:1

我有以下集线器,我正在尝试确定如何将其设置为使用基于 DI 的服务每 15 秒将统计数据发送回客户端以从我的数据库中提取数据。我似乎无法理解如何构建这个逻辑来工作。

[Authorize]
public class StatsHub : Hub
{
    public override async Task OnConnectedAsync()
    {
        // this method call obviously won't work due to the paramters, not sure how to structure this
        GetStats();

        return base.OnConnectedAsync();
    }

    private void GetStats([FromServices] IQueueService queueService, [FromServices] TimerManager timerManager)
    {
        timerManager.PrepareTimer(async () => {
            var results = await queueService.GetStats();

            await Clients.All.SendAsync("SendQueueStats", results.Payload);
        }, 15000);            
    }
}

这里是

PrepareTimer
方法逻辑

private Timer _timer;
private AutoResetEvent _autoResetEvent;
private Action _action;

public DateTime TimerStarted { get; set; }
public bool IsTimerStarted { get; set; }

public void PrepareTimer(Action action, int delayMS)
{
    _action = action;
    _autoResetEvent = new AutoResetEvent(false);
    _timer = new Timer(Execute, _autoResetEvent, 1000, delayMS);
    TimerStarted = DateTime.Now;
    IsTimerStarted = true;
}

public void Execute(object stateInfo)
{
    // Execute the action associated with the timer.
    _action();

    // If the timer has been running for less than 120 seconds, return.
    if (!((DateTime.Now - TimerStarted).TotalSeconds > 120))
        return;

    // Set IsTimerStarted to false since the timer has stopped.
    IsTimerStarted = false;

    // Dispose of the timer.
    _timer.Dispose();
}

我似乎无法全神贯注地思考如何让它以我希望的方式工作——基本上每 15 秒在计时器上运行一次服务方法并广播统计数据。

.net-core signalr asp.net-core-7.0
1个回答
0
投票

你不想从你的集线器运行计时器。您使用

IHostedService
为您运行定时操作,只需调用集线器即可发送统计信息。

例如:

public class TimerService : IHostedService
{
    private readonly IQueueService _queueService;
    private readonly StatsService _statsService;
    private readonly CancellationTokenSource _cts;

    private Timer? _timer = null;

    public TimerService(IQueueService queueService, StatsService statsService)
    {
        _queueService = queueService;
        _statsService = statsService;

        _cts = new CancellationTokenSource();
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _timer = new Timer(SendStats, null, TimeSpan.Zero, TimeSpan.FromSeconds(15));

        return Task.CompletedTask;
    }

    private void SendStats(object? state)
    {
        var stats = _queueService.GetStats();

        Task.WaitAll(_statsService.SendStats(stats, _cts.Token));
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _cts.Cancel();
        
        _timer?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }
}

将此注册为托管服务,.NET 将负责为您运行它。

builder.Services.AddHostedService<TimerService>();

服务中的计时器调用

StatsService
调用带有数据的客户端。这会完成您加载数据然后调用集线器将其发送出去的繁重工作。传入构造函数的
IHubContext<T>
是一个 SignalR 接口,它允许集线器外部的类发送消息。更多信息在这里

public class StatsService
{
    private readonly IHubContext<StatsHub> _hub;

    public StatsService(IHubContext<StatsHub> hub)
    {
        _hub = hub;
    }

    public async Task SendStats(int[] stats, CancellationToken cancellationToken)
    {
        await _hub.Clients.All.SendAsync("SendQueueStats", stats, cancellationToken);
    }
}

除非您想在客户端连接或断开连接到集线器时做一些特定的事情,否则可以简化为:

[Authorize]
public class StatsHub : Hub
{
}

有关使用

IHostedService
运行定时作业的信息可以在Microsoft Learn

上找到
© www.soinside.com 2019 - 2024. All rights reserved.