我已经将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;
}
}
答案 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
。