You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 3.1更新Session触发IFeatureCollection已释放错误如何解决

问题根因
  • 核心原因:ASP.NET Core 中HttpContext的生命周期和当前请求完全绑定,你在Start方法中同步执行5-10分钟的阻塞任务,远超过默认请求超时时间,请求被回收后HttpContext连带其关联的Session对象都会被释放,后续访问Session就会触发IFeatureCollection已释放的错误。
  • 场景错误:Session本身是会话级别的存储,设计用途不是存储长耗时任务的实时进度,且你用的内存型Session服务重启后数据就会丢失。
  • 代码错误:Start方法被标记为async Task但内部没有任何await逻辑,会引发编译告警,且同步阻塞会占用请求线程导致服务并发能力下降;另外Start方法为private修饰符,无法作为控制器Action被前端直接请求。
解决方案

1. 替换进度存储方案

不要用Session存储进度,新建线程安全的单例进度服务,以用户唯一标识为键存储不同用户的进度数据:

public class ProgressService
{
    // 线程安全字典:key=用户唯一ID,value=(进度值,状态文本,同步是否完成)
    private readonly ConcurrentDictionary<string, (int Percentage, string Status, bool SyncCompleted)> _progressStore = new();

    public void Update(string userId, int percentage, string status, bool isCompleted = false)
    {
        _progressStore.AddOrUpdate(userId, (percentage, status, isCompleted), (k, old) => (percentage, status, isCompleted));
    }

    public (int Percentage, string Status, bool SyncCompleted) Get(string userId)
    {
        return _progressStore.TryGetValue(userId, out var val) ? val : (0, "未开始", false);
    }

    public void Clear(string userId) => _progressStore.TryRemove(userId, out _);
}

在Startup.cs的ConfigureServices方法中注册服务:

services.AddSingleton<ProgressService>();

2. 改造Start方法

不要在请求线程中执行耗时任务,收到请求后初始化进度,将任务扔到后台执行,立刻返回响应避免请求超时:

// 注入ProgressService
private readonly ProgressService _progressService;
public HomeController(ProgressService progressService)
{
    _progressService = progressService;
}

// 改成public,去掉不必要的async标记
public IActionResult Start(string token, string btnClick)
{
    // 提前获取当前用户ID,不要在后台任务中访问HttpContext
    var userId = User.FindFirstValue(System.Security.Claims.ClaimTypes.NameIdentifier);
    // 初始化进度
    _progressService.Update(userId, 10, "正在获取用户信息...");

    // 后台执行耗时任务,不阻塞当前请求
    _ = Task.Run(() =>
    {
        try
        {
            GetUserDetails();
            _progressService.Update(userId, 35, "正在获取其他数据...");
            GetOtherData();
            _progressService.Update(userId, 55, "处理完成", true);
            // 后续任务完成后更新进度到100即可
        }
        catch (Exception ex)
        {
            _progressService.Update(userId, 0, $"处理失败:{ex.Message}", true);
        }
    });

    // 立刻返回视图
    return View();
}

3. 改造GetData方法

从进度服务读取数据,不再使用Session:

public JsonResult GetData()
{
    var userId = User.FindFirstValue(System.Security.Claims.ClaimTypes.NameIdentifier);
    var progress = _progressService.Get(userId);
    var result = $"{progress.Percentage},{progress.Status},{progress.SyncCompleted}";
    return Json(result);
}
注意事项
  • 如果你的任务耗时超过10分钟,建议用IHostedService或者Hangfire这类专业后台任务框架处理,避免ASP.NET Core进程回收时任务被强制终止
  • 后台任务中禁止直接引用请求生命周期的对象(比如HttpContext、Scoped服务),如果需要使用Scoped服务,要手动创建作用域获取实例
  • 你原有Startup中的Session配置本身无问题,只是使用场景不匹配,不需要修改Session相关配置

内容的提问来源于stack exchange,提问作者Asif Hussain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 10:39:01