为什么我无法在 SignalR Hub 中使用
AppDbContext
?查询本身没有任何问题。它在集线器上下文之外工作。 email
正确解析。
System.NullReferenceException:对象引用未设置到对象的实例。 在 lambda_method1325(闭包,QueryContext) 在 Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](表达式查询,CancellationToken cancellationToken) 在 Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
我的整个想法是每当用户登录时,将所有未送达的消息发送给他。或者也许我不应该这样做?也许前端应该调用一个端点,该端点最初将从发件箱表加载这些未传递的消息,而不是 OnConnectedAsync?
[Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)]
public sealed class SignalRHub : Hub
{
readonly ILogger<SignalRHub> _logger;
readonly IMediator _mediator;
public SignalRHub(ILogger<SignalRHub> logger, IMediator mediator)
{
_logger = logger;
_mediator = mediator;
}
public override async Task OnConnectedAsync()
{
var email = Context.User.GetEmailAddress();
await SendUndeliveredNotificationsAsync(email);
await base.OnConnectedAsync();
}
async Task SendUndeliveredNotificationsAsync(string email)
{
var undeliveredNotifications = await _mediator.Send(new GetUndeliveredNotificationsForUserQuery(email));
var tasks = undeliveredNotifications.Select(notificationMessage => _mediator.Send(new SendInAppNotificationCommand(notificationMessage.Id)));
await Task.WhenAll(tasks);
}
}
public sealed record GetUndeliveredNotificationsForUserQuery(string Email) : IRequest<IReadOnlyCollection<NotificationMessage>>;
public sealed class GetUndeliveredNotificationsForUserQueryHandler : IRequestHandler<GetUndeliveredNotificationsForUserQuery, IReadOnlyCollection<NotificationMessage>>
{
readonly AppDbContext _dbContext;
public GetUndeliveredNotificationsForUserQueryHandler(AppDbContext dbContext) => _dbContext = dbContext;
public async Task<IReadOnlyCollection<NotificationMessage>> Handle(GetUndeliveredNotificationsForUserQuery request, CancellationToken cancellationToken)
=> await _dbContext.NotificationMessages
.AsNoTracking()
.Include(x => x.Notification)
.ThenInclude(x => x.Employee)
.Where(x => x.Notification.Employee != null && x.Notification.Employee.Email == request.Email && x.DateDelivered == null)
.ToListAsync(cancellationToken);
}
问题解决了!
尽管索赔已从
AuthorizeAttribute
解决,但租户 ID 本身并未设置。
这就是我最终做的。重要的是
_dbContext.TenancyContext.Tenant = applicationTenant;
[Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)]
public sealed class SignalRHub : Hub
{
readonly ILogger<SignalRHub> _logger;
readonly AppDbContext _dbContext;
public SignalRHub(ILogger<SignalRHub> logger, AppDbContext dbContext)
{
_logger = logger;
_dbContext = dbContext;
}
...
public async Task GetUndeliveredMessages()
{
var email = Context.User.GetEmailAddress();
var tenant = Context.User.GetTenant();
var applicationTenant = await _dbContext.Tenants.AsNoTracking().FirstOrDefaultAsync(x => x.NormalizedCanonicalName == tenant);
_dbContext.TenancyContext.Tenant = applicationTenant;
var undeliveredMessages = await _dbContext.NotificationMessages
.AsNoTracking()
.Include(x => x.Notification)
.ThenInclude(x => x.Employee)
.Where(x => x.Notification.Employee != null && x.Notification.Employee.Email == email && x.ChannelType == ChannelType.InApp && x.DateDelivered == null)
.Select(x => x.MapToResponse())
.ToListAsync();
await Clients.Caller.SendAsync("ReceiveUndeliveredMessages", undeliveredMessages);
}
}