我有以下集线器,我正在尝试确定如何将其设置为使用基于 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上找到