具有SignalR集线器的ASP.NET Core中的范围服务

时间:2019-06-27 14:08:32

标签: c# asp.net asp.net-core .net-core signalr

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

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

当我尝试访问SignalR集线器中的IUser服务时出现问题。在构建集线器时,尽管IUser请求的中间件只是对其进行设置,但注入的/hub没有设置任何属性。

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

如何为特定的SignalR连接设置IUser

// Startup.cs - User has several settable properties 
services.AddScoped<IUser, User>();
// 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);
    }
}
[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
    }
}
public class DownloadController : Controller
{
    private readonly IUser _user;

    public DownloadController(IUser user)
    {
        // user gets injected and has properties set
        _user = user;
    }
}

2 个答案:

答案 0 :(得分:0)

要在Signalr Hub中使用范围服务,可以注入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>();    

        }

    }
}

答案 1 :(得分:0)

您是否在 Hub 方法中尝试过 Context.GetHttpContext().RequestServices?这应该是正在进行的请求的 IServiceProvider

相关问题