Session.SetString 方法抛出异常“IFeatureCollection 已被处理".对象名称:'集合'."在 ASP.NET Core 3.1 中 [英] Session.SetString method throws exception "IFeatureCollection has been disposed. Object name: 'Collection'. " in ASP.NET Core 3.1

查看:32
本文介绍了Session.SetString 方法抛出异常“IFeatureCollection 已被处理".对象名称:'集合'."在 ASP.NET Core 3.1 中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用 ASP.NET Core 3.1 编写的项目.

我需要在单例服务中将数据设置为会话:

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

我从 DI 注入了会话对象:

public OperatorService(ILogger logger,ISession 会话,IOptions选项){this._session = 会话;this._logger = 记录器;this._appSettings = options.Value;}

我调用我的方法如下:

public void ChangeOperatorStatus(StatusChangeRequest request){尝试{_session.SetString(request.Key, request.Value);}捕获(异常前){_logger.LogInformation($"更改状态时出现异常:{ex}");}}

但我得到以下异常:

IFeatureCollection 已被释放.
对象名称:'Collection'.

然后我在 Startup.cs 的 ConfigureServices 方法中添加了一些代码:

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

然后我在 Startup.cs 的 Configure 方法中添加了 app.UseSession();.

我尝试了 services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 并且我从 httpContextAccessor.HttpContext.Session 获得了会话,但我得到了同样的错误.>

请帮帮我,谢谢.

解决方案

HttpContext 是单个请求的上下文.它提供对单个请求的请求、响应属性等的访问.你不能缓存它,一旦请求结束它就无效了.

Session 是另一个短暂的东西 - 它只与单个用户会话一样长.网络应用程序的每个用户至少有一个会话.在单例中缓存这些会话之一保证

  • 引用将在一段时间后失效,当会话到期时
  • 单身人士将仅使用该用户的值,而忽略其他所有人的值.这本身就是一个错误,也是一种很好的入侵应用程序的方法.
  • 如果管理员登录,Session 对象可能会在接下来的 20、30 或 60 分钟内将管理员的设置应用到每个人.

这就是为什么使用 Session 对每个请求的中间件有意义,而不是单例服务.

HttpContext的正确使用

Session 只能通过请求的上下文访问,所以获取正确的会话意味着获取正确的 HttpContext.David Fowler 的 ASP.NET 核心指南:

<块引用>

❌ BAD 此示例将 HttpContext 存储在一个字段中,然后尝试稍后使用它.

 私有只读 HttpContext _context;公共 MyType(IHttpContextAccessor 访问器){_context = accessor.HttpContext;}公共无效 CheckAdmin(){if (!_context.User.IsInRole("admin")){throw new UnauthorizedAccessException("当前用户不是管理员");}}

<块引用>

✅ GOOD 此示例将 IHttpContextAccesor 本身存储在一个字段中,并在正确的时间使用 HttpContext 字段(检查是否为空).

 private readonly IHttpContextAccessor _accessor;公共 MyType(IHttpContextAccessor 访问器){_accessor = 存取器;}公共无效 CheckAdmin(){var context = _accessor.HttpContext;if (context != null && !context.User.IsInRole("admin")){throw new UnauthorizedAccessException("当前用户不是管理员");}}

改用范围服务

因为单身人士不知道要使用什么会话.一种选择是简单地将该服务转换为 Scoped 服务.在 ASP.NET Core 中,请求定义了一个范围.这就是控制器操作和管道中间件如何为每个请求访问正确的 HttpContext.

假设该服务由操作或中间件使用,也许唯一需要的更改是将 AddSingleton 替换为 AddScoped

扭转局面,或控制反转

另一个选项是该单例的调用者应该向它提供会话.而不是使用缓存的会话,例如:

public void SetStatus(string status){_session.SetString(SessionKeys.UserStatus, "某个值");}

请求会话或 HttpContext 作为参数:

public void SetStatus(string status,ISession session){session.SetString(SessionKeys.UserStatus, "某个值");}

并让调用者将正确的会话传递给它

I have a project written in ASP.NET Core 3.1.

I need to set data to Session in Singleton service:

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

I injected the session object from DI:

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

I calls the my method as below:

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

but I get the exception below :

IFeatureCollection has been disposed.
Object name: 'Collection'. 

and I added some code to Startup.cs's ConfigureServices method:

services.AddHttpContextAccessor();

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

And I added app.UseSession(); to the Configure method of Startup.cs.

I trid services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); and I get the session from httpContextAccessor.HttpContext.Session but I get the same error.

Please help me, thank you.

解决方案

An HttpContext is the context of a single request. It provides access to the request, response properties etc of that single request. You can't cache it, it becomes invalid once that request ends.

Session is another transient thing - it lives only as long as a single user session. There's at least one session for every user of a web app. Caching one of those sessions in a singleton guarantees that

  • The reference will become invalid after a while, when the session expires and
  • The singleton will use only that user's values, ignoring everyone else's. This is a bug in itself, and a great way to hack into an application.
  • If an administrator logs in, the Session object may apply the admin's settings alive to everyone for the next 20, 30 or 60 minutes.

That's why using a Session makes sense for per-request middleware, not Singleton services.

Correct usage of HttpContext

The Session can only be reached through the request's context, so getting the correct session means getting the correct HttpContext. The correct way to do this is explained in David Fowler's ASP.NET Core Guidance :

❌ BAD This example stores the HttpContext in a field then attempts to use it later.

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

✅ GOOD This example stores the IHttpContextAccesor itself in a field and uses the HttpContext field at the correct time (checking for 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");
       }
   }

Use a Scoped service instead

Since a Singleton can't know what session to use. One option is to simply convert that service to a Scoped service. In ASP.NET Core, a request defines a scope. That's how controller actions and pipeline middleware get access to the correct HttpContext for each request.

Assuming the service is used by an action or middleware, perhaps the only change needed is to replace AddSingleton<ThatService> with AddScoped<ThatService>

Turning the tables, or Inversion of Control

Another option is for callers of that singleton should provide the session to it. Instead of using a cached session eg :

public void SetStatus(string status)
{
    _session.SetString(SessionKeys.UserStatus, "some value");
}

Ask for the session or HttpContext as a parameter :

public void SetStatus(string status,ISession session)
{
    session.SetString(SessionKeys.UserStatus, "some value");
}

And have callers pass the correct session to it

这篇关于Session.SetString 方法抛出异常“IFeatureCollection 已被处理".对象名称:'集合'.&quot;在 ASP.NET Core 3.1 中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆