[英]Session.SetString method throws exception "IFeatureCollection has been disposed. Object name: 'Collection'. " in ASP.NET Core 3.1
I have a project written in ASP.NET Core 3.1.我有一个用 ASP.NET Core 3.1 编写的项目。
I need to set data to Session in Singleton service:我需要在 Singleton 服务中将数据设置为 Session:
_session.SetString("some key", "some value");
I injected the session object from DI:我从 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.\r\nObject name: 'Collection'.
and I added some code to Startup.cs's ConfigureServices method:我在 Startup.cs 的 ConfigureServices 方法中添加了一些代码:
services.AddHttpContextAccessor();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(20);
options.Cookie.HttpOnly = true;
})
.AddDistributedMemoryCache();
And I added app.UseSession();
我添加了app.UseSession();
to the Configure method of Startup.cs.到 Startup.cs 的 Configure 方法。
I trid services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
我尝试了services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
and I get the session from httpContextAccessor.HttpContext.Session
but I get the same error.我从httpContextAccessor.HttpContext.Session
获得了会话,但我得到了同样的错误。
Please help me, thank you.请帮帮我,谢谢。
An HttpContext is the context of a single request. HttpContext 是单个请求的上下文。 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在单例中缓存这些会话之一可以保证
That's why using a Session makes sense for per-request middleware, not Singleton services.这就是为什么使用 Session 对每个请求中间件有意义,而不是单例服务。
Correct usage of HttpContext HttpContext 的正确使用
The Session can only be reached through the request's context, so getting the correct session means getting the correct HttpContext. Session 只能通过请求的上下文访问,因此获取正确的会话意味着获取正确的 HttpContext。 The correct way to do this is explained in David Fowler's ASP.NET Core Guidance : David Fowler 的 ASP.NET Core Guidance 中解释了正确的方法:
❌ BAD This example stores the HttpContext in a field then attempts to use it later. ❌ 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");
}
}
✅ GOOD This example stores the IHttpContextAccesor itself in a field and uses the HttpContext field at the correct time (checking for null). ✅ GOOD 此示例将 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");
}
}
Use a Scoped service instead改用 Scoped 服务
Since a Singleton can't know what session to use.由于单例无法知道要使用哪个会话。 One option is to simply convert that service to a Scoped service.一种选择是简单地将该服务转换为 Scoped 服务。 In ASP.NET Core, a request defines a scope.在 ASP.NET Core 中,请求定义了一个范围。 That's how controller actions and pipeline middleware get access to the correct HttpContext for each request.这就是控制器操作和管道中间件如何为每个请求访问正确的 HttpContext。
Assuming the service is used by an action or middleware, perhaps the only change needed is to replace AddSingleton<ThatService>
with AddScoped<ThatService>
假设服务由操作或中间件使用,可能唯一需要的更改是将AddSingleton<ThatService>
替换为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 :请求会话或 HttpContext 作为参数:
public void SetStatus(string status,ISession session)
{
session.SetString(SessionKeys.UserStatus, "some value");
}
And have callers pass the correct session to it并让调用者将正确的会话传递给它
It took me a while to get this fixed.我花了一段时间才解决这个问题。 In my case, it was a 3.1 aspnetcore and it didn't worked until I turn the container function from就我而言,它是一个 3.1 aspnetcore,直到我将容器功能从
public async void OnPost
to到
public async Task<IActionResult> OnPost
Looks like the HttpContext was disposed before it was used...看起来 HttpContext 在使用之前已被处理...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.