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

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

问题描述

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

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

我需要在Singleton服务中将数据设置为Session:

I need to set data to Session in Singleton service:

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

我从DI中注入了会话对象:

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

我按如下方式调用my方法:

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.\r\nObject name: 'Collection'. 

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

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();

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

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

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

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

请帮助我,谢谢.

推荐答案

HttpContext是单个请求的上下文.它提供对单个请求的请求,响应属性等的访问.您无法对其进行缓存,请求结束后,该缓存将变为无效.

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

  • 一段时间后,会话终止,
  • 单例将仅使用该用户的值,而忽略其他所有人的值.这本身就是一个错误,并且是一种侵入应用程序的伟大方法.
  • 如果管理员登录,则Session对象可以在接下来的20、30或60分钟内将管理员的设置有效地应用于所有人.
  • 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.

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

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

正确使用HttpContext

只能通过请求的上下文访问会话,因此获得正确的会话意味着获得正确的HttpContext. 大卫·福勒(David Fowler)的ASP.NET核心指南:

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 :

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

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

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

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

改为使用范围服务

由于Singleton不知道要使用哪个会话.一种选择是简单地将该服务转换为范围服务.在ASP.NET Core中,请求定义范围.这就是控制器动作和管道中间件如何为每个请求访问正确的HttpContext的方式.

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.

假设该服务由操作或中间件使用,则唯一需要做的更改就是将AddSingleton<ThatService>替换为AddScoped<ThatService>

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

旋转表格或反转控制

该单例的呼叫者的另一种选择是为其提供会话.而不是使用缓存的会话,例如:

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

询问会话或HttpContext作为参数:

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天全站免登陆