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



>我有以下中心,我正在尝试确定如何设置它以使用基于 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 秒在计时器上运行一次服务方法并广播统计数据。

您不想从中心运行计时器。您可以使用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

最新更新