![](/img/trans.png)
[英]Using Transactions with EntityFramework FROM the business logic layer
[英]Provide user information from signalr request in business logic layer using autofac
我有一个带SignalR 2集线器并为DI使用autofac的ASP.NET MVC 5应用程序。
整个业务逻辑封装在它们自己层中的管理器类中。 一些管理器方法需要有关当前登录用户的信息(UserId,TenantId,..)。
通过将AuthorizationProvider注入需要用户信息的每个管理器类中,我解决了这个问题。
public interface IAuthorizationProvider
{
long? GetUserId();
long? GteTenantId();
}
public class MyManager : IMyManager
{
private IAuthorizationProvider _authorizationProvider;
public MyManager(IAuthorizationProvider authorizationProvider)
{
_authorizationProvider = authorizationProvider;
}
public void MyMethod()
{
// Getting the User information here is pretty simple
long userId = _authorizationProvider.GetUserId();
}
}
通常,我可以从HttpContext和会话中获取用户信息。 所以我写了一个SessionAuthorizationProvider:
public class SessionAuthorizationProvider{
public long? GetUserId()
{
HttpContext.Current?.Session?[SessionKeys.User]?.Id;
}
public long? GteTenantId() { ... }
}
但是现在我在SignalR集线器中有了一种使用相同机制的新方法。
[HubName("myHub")]
public class MyHub : Hub
{
private IMyManager _myManager;
public MyHub(IMyManager myManager)
{
_myManager = myManager;
}
[HubMethodName("myHubMethod")]
public void MyHubMethod(long userId, long tenantId)
{
_myManager.MyMethod();
}
}
问题是SignalR请求没有会话。 因此,我还在集线器方法中将所需的用户信息设置为来自客户端的参数postet。
因此,我认为为SignalR编写新的AuthorizationProvider并修改依赖解析器是解决此问题的最佳方法。 但是我无法在新的SignalrAuthorizationProvider中获得当前用户。
public class SignalrAuthorizationProvider{
public long? GetUserId()
{
// How to get the user information here???
}
public long? GteTenantId() { /* and here??? */ }
}
有针对此问题的推荐解决方案吗?
当然,我可以扩展MyMethod以接受用户信息作为参数。 但是MyMethod从另一个管理器调用另一个方法,并且该管理器也调用另一个方法。 仅在最后一次方法调用时才需要用户信息。 因此,将来我必须至少更改3种方法,并更改更多方法。
这是问题的草图
这是一个潜在的解决方案。 但这很不好
默认情况下,SignalR不支持会话,您应该避免使用它。 请参阅无法通过SignalR Hub访问会话信息。 我的设计错了吗? 。 但是您仍然可以使用cookie或querystring获得所需的值。
在这两种情况下,您都需要访问基础集线器的HubCallerContext
,可以通过Hub
的Context
属性对其进行访问。
用理想的话来说,您只需要拥有对SignalAuthorizationProvider
的依赖
即:
public class SignalrAuthorizationProvider {
public SignalrAuthorizationProvider(HubCallerContext context){
this._context = context;
}
private readonly HubCallerContext _context;
public long? GetUserId() {
return this._context.Request.QueryString["UserId"]
}
}
但是由于SignalR设计,这是不可能的。 在构建Hub和AFAIK之后分配Context
属性,无法对其进行更改。
源代码在这里: HubDispatcher.cs
一种可能的解决方案是在Hub
内注入可变的依赖关系,并在OnConnected
和OnReconnected
方法中更改对象。
public class SignalrAuthorizationProvider : IAuthorizationProvider
{
private Boolean _isInitialized;
private String _userId;
public String UserId
{
get
{
if (!_isInitialized)
{
throw new Exception("SignalR hack not initialized");
}
return this._userId;
}
}
public void OnConnected(HubCallerContext context)
{
this.Initialize(context);
}
public void OnReconnected(HubCallerContext context)
{
this.Initialize(context);
}
private void Initialize(HubCallerContext context) {
this._userId = context.QueryString["UserId"];
this._isInitialized = true;
}
}
和枢纽
public abstract class CustomHub : Hub
{
public CustomHub(IAuthorizationProvider authorizationProvider)
{
this._authorizationProvider = authorizationProvider;
}
private readonly IAuthorizationProvider _authorizationProvider;
public override Task OnConnected()
{
this._authorizationProvider.OnConnected(this.Context);
return base.OnConnected();
}
public override Task OnReconnected()
{
this._authorizationProvider.OnReconnected(this.Context);
return base.OnReconnected();
}
}
具有可变的依赖关系不是最佳的设计,但是我看不到任何其他方式可以访问IRequest
或HubCallerContext
。
而不是不是一个完美的解决方案的抽象Hub
类。 您可以将RegisterHubs
autofac方法更改为将AOP与Castle.Core
一起使用,并让拦截器为您调用这些方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.