HttpContext - это контекст одного запроса. Он обеспечивает доступ к запросу, свойствам ответа и т. Д. Этого единственного запроса. Вы не можете кэшировать его, он становится недействительным после завершения этого запроса.
Сессия - это еще одна временная вещь - она существует только до тех пор, пока один пользовательский сеанс. Для каждого пользователя веб-приложения существует как минимум один сеанс. Кэширование одного из этих сеансов в синглтоне гарантирует, что
- Ссылка станет недействительной через некоторое время, когда истечет сеанс и
- Синглтон будет использовать только значения этого пользователя, игнорируя все остальные. Это ошибка сама по себе, и это отличный способ взломать приложение.
- Если администратор входит в систему, объект сеанса может применять настройки администратора для всех в течение следующих 20, 30 или 60 минут.
Вот почему использование сеанса имеет смысл для промежуточного программного обеспечения для каждого запроса, а не для служб Singleton.
Правильное использование HttpContext
Сессия может быть достигнута только через контекст запроса, поэтому получение правильного сеанса означает получение правильного HttpContext. Правильный способ сделать это объясняется в Руководство Дэвида Фаулера по ASP.NET Core:
❌ ПЛОХО В этом примере HttpContext сохраняется в поле, а затем предпринимается попытка использовать его позже.
private readonly HttpContext _context;
public MyType(IHttpContextAccessor accessor)
{
_context = accessor.HttpContext;
}
public void CheckAdmin()
{
if (!_context.User.IsInRole("admin"))
{
throw new UnauthorizedAccessException("The current user isn't an admin");
}
}
✅ ХОРОШО В этом примере сам IHttpContextAccesor сохраняется в поле и используется поле HttpContext в правильное время (проверка на null).
private readonly IHttpContextAccessor _accessor;
public MyType(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public void CheckAdmin()
{
var context = _accessor.HttpContext;
if (context != null && !context.User.IsInRole("admin"))
{
throw new UnauthorizedAccessException("The current user isn't an admin");
}
}
Вместо этого используйте службу с ограниченной областью действия
Поскольку синглтон не может знать, какой сеанс использовать. Один из вариантов - просто преобразовать эту службу в службу с заданной областью действия. В ASP.NET Core запрос определяет область. Таким образом действия контроллера и промежуточное ПО конвейера получают доступ к правильному HttpContext для каждого запроса.
Предполагая, что служба используется действием или промежуточным программным обеспечением, возможно, единственное необходимое изменение - заменить AddSingleton<ThatService>
на AddScoped<ThatService>
.
Поворот столов или инверсия управления
Другой вариант: вызывающие этого синглтона должны предоставить ему сеанс. Вместо использования кэшированного сеанса, например:
public void SetStatus(string status)
{
_session.SetString(SessionKeys.UserStatus, "some value");
}
Запросите сеанс или HttpContext в качестве параметра:
public void SetStatus(string status,ISession session)
{
session.SetString(SessionKeys.UserStatus, "some value");
}
И пусть вызывающие абоненты передают ему правильный сеанс
person
Panagiotis Kanavos
schedule
29.01.2020
HttpContextAccessor
. Вы все еще не опубликовали, где возникает ошибка. Где это_session.SetString(SessionKeys.UserStatus, "some value");
? Откуда это_session
, особенно в Singleton? - person Panagiotis Kanavos   schedule 29.01.2020_session
, вам пришлось использовать HttpContext временных запросов в качестве синглтона, что приводит к этой ошибке. - person Panagiotis Kanavos   schedule 29.01.2020IHttpContextAccessor
указывать на правильный контекст запроса. - person Panagiotis Kanavos   schedule 29.01.2020ISession
? Ошибка очевидна - код пытается использовать просроченную сессию. Итак, вам нужно выяснить, откуда взялся этот просроченный сеанс. ЕслиOperatorService
является синглтоном, то гарантированно будет неправильный сеанс, как только второй пользователь зайдет на сайт.AddSession
не регистрируетISession
в DI, откуда он взялся? - person Panagiotis Kanavos   schedule 29.01.2020AddSession
даже не регистрируетISession
в службах внедрения зависимостей. Как вы создаетеOperatorService
? И почему это синглтон, а не сервис Scoped? Разместите код, который регистрирует или создает OperatorService, и код, который его использует. Вот что нужно исправить - person Panagiotis Kanavos   schedule 29.01.2020ISession
параметромChangeOperatorStatus
, чтобы вызывающие абоненты могли передавать правильный сеанс - person Panagiotis Kanavos   schedule 29.01.2020