Метод Session.SetString генерирует исключение «IFeatureCollection удален. Имя объекта: 'Collection'." В ASP. NET Core 3.1. - PullRequest
1 голос
/ 29 января 2020

У меня есть проект, написанный на ASP. NET Core 3.1.

Мне нужно установить данные для сеанса в службе Singleton:

 _session.SetString("some key", "some value");

Я ввел объект сеанса из DI:

  public OperatorService( 
                ILogger<OperatorService> logger, 
                ISession session,
                IOptions<AppSettings> options)
            {
                this._session = session; 
                this._logger = logger; 
                this._appSettings = options.Value;
            }

Я вызываю метод my, как показано ниже:

public void ChangeOperatorStatus(StatusChangeRequest request)
        {
            try
            {
              _session.SetString(request.Key, request.Value);
            }
            catch (Exception ex)
            {
                _logger.LogInformation($"Exception while changing status: {ex}"); 
            } 
        } 

, но я получаю исключение ниже:

IFeatureCollection has been disposed.\r\nObject name: 'Collection'. 

, и я добавил некоторый код к методу Startup.cs ConfigureServices:

services.AddHttpContextAccessor();

services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(20);
    options.Cookie.HttpOnly = true;
})
.AddDistributedMemoryCache();

И я добавил app.UseSession(); к методу Configure Startup.cs.

Я запускаю services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); и получаю сеанс от httpContextAccessor.HttpContext.Session но я получаю ту же ошибку.

Пожалуйста, помогите мне, спасибо.

1 Ответ

2 голосов
/ 29 января 2020

HttpContext - это контекст одного запроса. Он предоставляет доступ к запросу, свойствам ответа и т. Д. 1058 * этого отдельного запроса. Вы не можете кэшировать его, он становится недействительным, как только этот запрос заканчивается.

Сессия - это еще одна временная вещь - она ​​живет только один сеанс пользователя. Для каждого пользователя веб-приложения есть хотя бы один сеанс. Кэширование одного из этих сеансов в синглтоне гарантирует, что

  • Ссылка станет недействительной через некоторое время, когда истечет время сеанса и
  • Синглтон будет использовать только значения этого пользователя, игнорируя все еще. Это ошибка сама по себе, и отличный способ взломать приложение.
  • Если администратор входит в систему, объект Session может применить настройки администратора ко всем в течение следующих 20, 30 или 60 минут.

Именно поэтому использование Session имеет смысл для промежуточное ПО для каждого запроса, а не службы Singleton.

Правильное использование HttpContext

Сеанс может быть достигнут только через контекст запроса, поэтому получение правильного сеанса означает получение исправить HttpContext. Правильный способ сделать это объяснен в ASP. NET Базового руководства Дэвида Фаулера :

❌ BAD. Этот пример сохраняет 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 (проверка на ноль).

   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");
       }
   }

Вместо этого используйте сервис Scoped

Поскольку Singleton не может знать, какой сеанс использовать. Один из вариантов - просто преобразовать этот сервис в сервис Scoped. В 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");
}

И пусть вызывающие абоненты передают ему правильный сеанс

...