有一个多租户SaaS应用程序,我想在其中为SignalR Hub的OnConnectedAsync/OnDisconnectedAsync挂钩中的每tenantId个创建组.

问题是ITenancyContext<ApplicationTenant>被注册为作用域服务,这意味着它只在请求的作用域内可用.在SignalR集线器的上下文中,它与请求没有关联,因此它不可用.

那么我怎么才能让它变得可用呢?授权它并以某种方式丰富索赔吗?

public sealed class NotificationHub : Hub
{
    readonly ILogger<NotificationHub> _logger;
    readonly Guid _tenantId;

    public NotificationHub(ILogger<NotificationHub> logger, ITenancyContext<ApplicationTenant> tenancyContext) => (_logger, _tenantId) = (logger, tenancyContext.Tenant.Id);

    public override async Task OnConnectedAsync()
    {
        await JoinGroup(_tenantId.ToString());
        _logger.LogInformation("{ConnectionId} has connected to the hub. TenantId: {TenantId}", Context.ConnectionId, _tenantId);
        await base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception? exception)
    {
        await LeaveGroup(_tenantId.ToString());
        _logger.LogInformation("{ConnectionId} was disconnected from the hub. TenantId: {TenantId}", Context.ConnectionId, _tenantId);
        await base.OnDisconnectedAsync(exception);
    }

    Task JoinGroup(string groupName) => Groups.AddToGroupAsync(Context.ConnectionId, groupName);

    Task LeaveGroup(string groupName) => Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}

推荐答案

我认为我们可以创建一个中间件来实现它.在这个中间件中注入ITenancyContext<ApplicationTenant>,让我们称之为TenantMiddleware.

public class TenantMiddleware
{
    private readonly ITenancyContext<ApplicationTenant> _tenancyContext;

    public TenantMiddleware(ITenancyContext<ApplicationTenant> tenancyContext)
    {
        _tenancyContext = tenancyContext;
    }

    public async Task InvokeAsync(HttpContext context, Func<Task> next)
    {
        var user = context.User.Identity as ClaimsIdentity;
        if (user != null)
        {
            var TenantId= _tenancyContext.Tenant.Id;
            user.AddClaim(new Claim("TenantId", TenantId.ToString()));
        }

        await next();
    }
}

然后我们就可以在你的NotificationHub级课上使用它.

public override async Task OnConnectedAsync()
{
    // Get TenantId like below.
    var user = Context.User.Identity as ClaimsIdentity;
    var tenantIdClaim = user?.FindFirst("TenantId");
    _tenantId = tenantIdClaim != null ? Guid.Parse(tenantIdClaim.Value) : Guid.Empty;
    ...
    await JoinGroup(_tenantId.ToString());
    _logger.LogInformation("{ConnectionId} has connected to the hub. TenantId: {TenantId}", Context.ConnectionId, _tenantId);
    await base.OnConnectedAsync();
}

Csharp相关问答推荐

在C#c/await中,延迟长度是否会影响控制返回调用者?

如何从Date中剥离Timezone部分以仅保留本地Date部分?(no字符串解析或操作)

System.Text.Json:反序列化返回为空数组的字典时出错

将实例绑定方法传递到列表foreach

如何打印已添加到List的Linq值,而不是C#中的:System.Collections.Generic.List ' 1[System.Int32]?

使用其可能实现的基类和接口的属性的方法

在WPF.NET 6中使用C++/WinRT组件(但实际上是任何WinRT组件)

并行令牌更新

需要澄清C#的Clean Architecture解决方案模板的AuditableEntityInterceptor类

使用C#中的SDK在Microsoft Graph API上使用SubscribedSkus的问题

使用带有WithAppOnly()请求选项的pageIterator

注册所有IMediatR类

NET8 Maui&;iOS:AppCenter崩溃错误

如果设置了另一个属性,则Newtonsoft JSON忽略属性

为什么@rendermode Interactive Auto不能在.NET 8.0 Blazor中运行?

如何使用用于VS代码的.NET Maui扩展在我的iOS/Android设备或模拟器上进行调试?

在使用StringBuilder时,如何根据 colored颜色 设置为richTextBox中的特定行着色?

System.NotSupportdException:流不支持读取

C#中类库项目的源代码生成器

如何在使用Google.Drive.apis.V3下载文件/文件夹之前压缩?