【发布时间】:2021-08-16 15:13:25
【问题描述】:
我正在使用 ASP.NET Core,并且我正在通过 SingalR 集线器端点将一些用户添加到集合中:
public class MatchMakingHub : Hub
{
//....
// called by client
public async Task EnlistMatchMaking(int timeControlMs)
{
Guid currentId = Guid.Parse(this.Context.User.GetSubjectId());
GetPlayerByIdQuery getPlayerByIdQuery = new GetPlayerByIdQuery(currentId);
Player currentPlayer = await requestSender.Send<Player>(getPlayerByIdQuery);
var waitingPlayer = new WaitingPlayer(currentPlayer, timeControlMs);
this.matchMakePool.Add(waitingPlayer);
}
}
matchMakePool 是一个单例集合。
稍后,我有一个 ASP.NET Core 后台服务从集合中获取用户,并通知他们被获取:
public class MatchMakingBackgroundService : BackgroundService
{
private readonly MatchMakePoolSingleton matchMakePoolSingleton;
private readonly IServiceProvider serviceProvider;
private const int RefreshTimeMs = 1000;
public MatchMakingBackgroundService(MatchMakePoolSingleton matchMakePoolSingleton, IServiceProvider serviceProvider)
{
this.matchMakePoolSingleton = matchMakePoolSingleton;
this.serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while(!stoppingToken.IsCancellationRequested)
{
var result = matchMakePoolSingleton.RefreshMatches();
var tasks = new List<Task>();
foreach(var match in result)
{
tasks.Add(StartGameAsync(match));
}
await Task.WhenAll(tasks);
await Task.Delay(RefreshTimeMs, stoppingToken);
}
}
private async Task StartGameAsync(MatchMakeResult match)
{
using var scope = serviceProvider.CreateScope();
var sender = scope.ServiceProvider.GetRequiredService<ISender>();
var hubContext = serviceProvider.GetRequiredService<IHubContext<MatchMakingHub>>();
CreateNewGameCommand newGameCommand = new CreateNewGameCommand(match.WhitePlayer.Id, match.BlackPlayer.Id, TimeSpan.FromMilliseconds(match.TimeControlMs));
Guid gameGuid = await sender.Send(newGameCommand);
await hubContext.Clients.User(match.WhitePlayer.Id.ToString()).SendAsync("NotifyGameFound", gameGuid);
await hubContext.Clients.User(match.BlackPlayer.Id.ToString()).SendAsync("NotifyGameFound", gameGuid);
}
}
我的问题是NotifyGameFound 没有在客户端被调用。当我直接从集线器本身通知他们时,它已收到,但由于某种原因,当我通过提供的IHubContext<MatchMakingHub> 调用它时它没有收到。我怀疑这是因为它在另一个线程上运行。
这是客户端代码:
// in blazor
protected override async Task OnInitializedAsync()
{
var tokenResult = await TokenProvider.RequestAccessToken();
if(tokenResult.TryGetToken(out var token))
{
hubConnection
= new HubConnectionBuilder().WithUrl(NavigationManager.ToAbsoluteUri("/hubs/MatchMaker"), options =>
{
options.AccessTokenProvider = () => Task.FromResult(token.Value);
}).Build();
await hubConnection.StartAsync();
hubConnection.On<Guid>("NotifyGameFound", id =>
{
//do stuff
});
await MatchMakeRequast();
}
}
async Task MatchMakeRequast() =>
await hubConnection.SendAsync("EnlistMatchMaking", Secs * 1000);
【问题讨论】:
-
不确定它是否会有所帮助,但为什么要使用
IServiceProvider创建范围?有一个IServiceScopeFactory就是为了这个。另外,我不明白您为什么要从您的范围之外获得IHubContext。我不确定没有它它会如何运作。 -
您应该可以在注入服务的构造函数中使用
IHubContext<MatchMakingHub> hubContext。 -
看起来您正在通过数据库中的用户 ID 选择 signalrClients,您确定在 ClaimTypes.NameIdentifier 声明中提供了正确的用户 ID 或提供了 IUserIdProvider 的正确实现?
标签: c# asp.net-core signalr blazor background-service