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

ASP.NET Core 6.0中并发请求与会话状态计数异常问题

问题分析与解决方案

你的代码在并发请求下计数混乱,核心有两个原因:

  1. Session修改延迟持久化:ASP.NET Core默认会在请求结束时才将Session的修改写入后端存储(即使是内存存储)。你在lock块里修改了Session,但lock释放后,修改还没同步到共享存储,后续请求进入lock时读取的依然是旧值,导致多个请求拿到相同的计数并递增。
  2. 分支逻辑遗漏返回结果:当subscriptionCount为null时,你设置计数为1后没有返回任何IActionResult,这会导致请求返回204 No Content,同时可能延长Session修改的提交时机。

修正后的代码

private readonly static object _lockObj = new();

public IActionResult Subscribe()
{
    lock (_lockObj)
    {
        int? subscriptionCount = HttpContext.Session.GetInt32("SubscriptionCount");

        if (subscriptionCount == null)
        {
            HttpContext.Session.SetInt32("SubscriptionCount", 1);
            // 立即提交Session修改,确保后续请求能读取到最新值
            HttpContext.Session.Commit();
            return Ok(new { Result = "Created" });
        }
        else
        {
            if (subscriptionCount > 10)
            {
                return StatusCode(StatusCodes.Status403Forbidden, new { Result = "Max subscriptions per user/session reached" });
            }
            else
            {
                subscriptionCount++;
                HttpContext.Session.SetInt32("SubscriptionCount", subscriptionCount.Value);
                Console.WriteLine($"SubscriptionCount={subscriptionCount}");
                // 立即提交Session修改
                HttpContext.Session.Commit();
                return Ok(new { Result = "Created" });
            }
        }
    }
}

关键改进说明

  • 立即提交Session:调用HttpContext.Session.Commit()强制将Session的修改同步到共享存储,确保后续请求进入lock时能读取到最新的计数。
  • 完善分支返回逻辑:在subscriptionCount为null的分支添加return Ok(...),保证请求返回预期结果,同时避免Session提交延迟。
  • 保留static锁:_lockObj是静态的,确保进程内所有请求都能通过这个锁同步,避免并发修改计数。

分布式场景补充(可选)

如果你的应用部署在多服务器或多进程环境下,static锁无法跨进程同步,此时需要:

  • 使用分布式Session存储(如Redis)
  • 配合分布式锁(如Redis锁)来替代static锁,确保跨进程的计数同步。

内容的提问来源于stack exchange,提问作者Suresh Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 21:50:28