带有 SignalR Hub 的 ASP.NET Core 中的范围服务

Ale*_*lex 7 c# asp.net signalr .net-core asp.net-core

我已将 SignalR 引入到我的 ASP.NET Core 2 项目中,但在使用我通常在控制器中使用的范围服务时遇到了一些问题。我觉得这个问题可能是由于 HTTP 请求、Websocket 和集线器之间的生命周期不同造成的。

对于每个 HTTP 请求,中间件都会读取Authorization令牌并更新该请求的作用域服务 ( ) 上的一些属性(例如 id、声明等)IUser。我在所有控制器中使用此服务没有任何问题。为了使其与 SignalR 一起使用,我发送一个access_token查询参数并事先使用一些其他中间件将此查询参数添加为工作正常的标头。

当我尝试访问IUserSignalR 中心中的服务时,问题就出现了。在构建集线器时,IUser被注入的 没有设置任何属性,尽管/hub请求的中间件只是设置了它们。

如果我将服务设置为单例,那么它可以工作,但IUser持续时间不应超过单个请求。

IUser我应该如何为特定 SignalR 连接设置?

// Startup.cs - User has several settable properties 
services.AddScoped<IUser, User>();
Run Code Online (Sandbox Code Playgroud)
// User Middleware
public class UserMiddleware
{
    private readonly RequestDelegate _next;

    public UserMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public Task Invoke(HttpContext context)
    {
        // retrieve service for this request
        var user = context.RequestServices.GetService<IUser>();

        // set some properties on the User from auth token
        // e.g. User.Id = 1;

        return _next(context);
    }
}
Run Code Online (Sandbox Code Playgroud)
[Authorize(Roles = Claim.Names.Read)]
public class MyHub : Hub
{
    private readonly IUser _user;

    public MyHub(IUser user)
    {
        // user that gets injected has null properties
        _user = user;
    }

    public async Task Foo()
    {
        // do work with the _user credentials
    }
}
Run Code Online (Sandbox Code Playgroud)
public class DownloadController : Controller
{
    private readonly IUser _user;

    public DownloadController(IUser user)
    {
        // user gets injected and has properties set
        _user = user;
    }
}
Run Code Online (Sandbox Code Playgroud)

Rya*_*yan -1

要在信号中心中使用作用域服务,您可以ServiceProvider直接在其中注入并创建作用域:

public class ChatHub : Hub
{      
    private IServiceProvider _serviceProvider;
    public ChatHub(IServiceProvider serviceProvider)
    {
        _serviceProvider= serviceProvider;
    }

    public async Task Foo()
    {
        using (var scope = _serviceProvider.CreateScope())
        {
           var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

           var user = scope.ServiceProvider.GetRequiredService<IUser>();    

        }

    }
}
Run Code Online (Sandbox Code Playgroud)