Унифицированный статический класс между HttpContext и SignalR HubCallerContext
У меня много кода, который зависит от HttpContext.Current,
и я заметил, что запросы, поступающие из концентраторов SignalR, имеют HttpContext.Current == null
,
поэтому мой код разбивается, например:
HttpContext.Current.Request.IsAuthenticated
Итак, я придумал следующее:
public static class UnifiedHttpContext
{
private static HubCallerContext SignalRContext { get; set; }
private static int SignalRUserId
{
get { return WebSecurity.GetUserId(SignalRContext.User.Identity.Name); }
}
private static bool IsSignalRRequest
{
get { return SignalRContext != null; }
}
public static void SetSignalRContext(HubCallerContext context)
{
SignalRContext = context;
}
public static bool IsAuthenticated
{
get
{
if (!IsSignalRRequest)
{
return System.Web.HttpContext.Current.Request.IsAuthenticated;
}
else
{
return SignalRContext.User.Identity.IsAuthenticated;
}
}
}
public static int UserId
{
get
{
if (!IsSignalRRequest)
{
return WebSecurity.CurrentUserId;
}
else
{
return SignalRUserId;
}
}
}
}
И в мастер-хабе (каждый другой хаб наследует от него):
public abstract class MainHub : Hub
{
public override Task OnConnected()
{
UnifiedHttpContext.SetSignalRContext(Context);
Groups.Add(Context.ConnectionId, UnifiedHttpContext.UserId.ToString());
return base.OnConnected();
}
}
-
Является ли этот правильный подход, или это так или иначе решено, что я не знаю?
-
Является ли это опасным, поскольку статические классы совместно используются в приложении, будет ли этот набор одинаковым контекстом для всех пользователей? Если это так, я могу сделать это по запросу?
Ответы
Ответ 1
SignalR дает вам доступ к HubCallerContex
вместо HttpContext
. Вы можете получить доступ к объекту HubCallerContext, используя ключевое слово context
. Если вы хотите получить доступ к HttpContext
, вы можете получить его из контекста следующим образом:
System.Web.HttpContextBase httpContext = Context.Request.GetHttpContext();
Надеюсь, что это поможет.
Ответ 2
Просто потратил пару часов на эту проблему.
Похоже, что невозможно получить контекст SignalR вне класса хаба таким же образом, как вы это сделали бы с HttpContext:
var identity = HttpContext.Current.User.Identity;
или внутри контекста Ninject:
HttpContextBase httpContext = context.Kernel.Get<HttpContextBase>();
var identity = httpContext.Current.User.Identity;
По крайней мере, ответ на этот вопрос гласит: Получить SignalR User (Hub.Context) за пределами концентратора.
Но в этом конкретном случае, когда вам нужно получить текущий идентификатор пользователя, есть решение, которое работает в обоих мирах: WebApi/MVC и SignalR.
IPrincipal principal = Thread.CurrentPrincipal;
var identity = principal.Identity;
Я использовал это, чтобы получить идентификатор пользователя внутри моего кода инъекции зависимостей.
Morover, свойство Context доступно только в hub-методах (это null внутри конструктора хаба). Но Thread.CurrentPrincipal.Identity
даст вам идентификатор пользователя даже внутри конструктора хаба.