默认session在c#中非分布式方案,因inproc模式将数据存于进程内存,负载均衡下请求分发至不同服务器导致会话丢失;stateserver/sqlserver模式仅解决存储位置,不保障并发安全;asp.net core推荐idistributedcache+加密cookie方案,需统一redis实例、cookie配置及轻量缓存内容。

默认 Session 在 C# Web 应用中不是“开箱即用”的分布式方案,它在单机 IIS 下能跑通,但只要加一台服务器或换一个进程,Session 就会丢失或错乱——这不是配置问题,是设计使然。
ASP.NET Framework 的 Session 为什么一上负载均衡就掉登录
根本原因是 SessionStateModule 默认使用 InProc 模式,所有数据存在当前 w3wp.exe 进程内存里。请求被 Nginx/IIS ARR 分发到不同机器时,ASP.NET_SessionId Cookie 还在,但另一台机器根本没有这个 ID 对应的数据。
即使你改成 StateServer 或 SQLServer 模式,也只解决“存储位置”问题,不解决并发安全:多个请求同时读写同一个 session key,可能覆盖、丢字段、甚至反序列化失败。
-
web.config中设sessionState mode="SQLServer"后,必须确保所有节点连接同一数据库、同一表结构、且tempdb不被清空 -
StateServer要求 Windows Service 正常运行,且防火墙放行端口(默认 42424),跨网段常连不上 - 无论哪种模式,
Session.Abandon()和Session.Clear()行为不一致,前者触发Session_End事件(仅InProc有效),后者只是清空键值对
ASP.NET Core 里怎么安全地替代 Session
直接弃用 HttpContext.Session,改用 IDistributedCache + 加密 Cookie 是目前最稳的路径。核心不是“存什么”,而是“谁来管生命周期、谁来防并发、谁来兜底过期”。
关键实操点:
- 注册缓存实现时必须指定唯一
InstanceName,比如options.InstanceName = "MyApp:",否则多服务共用 Redis 时 key 会撞车 -
AddDistributedRedisCache要求连接字符串指向**同一 Redis 实例集群**,不能每个节点连自己本地 Redis - Cookie 配置三要素必须全节点一致:
Name(如.AspNetCore.Cookies)、Key(用于解密的IKeyRing)、ExpireTimeSpan,否则某台机器签发的 cookie,另一台验不过直接 401 - 缓存中只存轻量标识,例如
{ "userId": 123, "loginAt": "2026-05-14T10:00:00Z", "ipHash": "a1b2c3" },敏感信息如手机号、token 值绝不落缓存
C# 客户端程序如何手动维持服务端 Session
当你用 HttpWebRequest 或 HttpClient 模拟登录并后续请求时,Session 不是自动延续的,关键在 CookieContainer 是否复用。
典型错误是每次 new 一个 CookieContainer,导致服务端认为是新会话。
- 全局持有一个
CookieContainer实例,所有请求都赋给它的CookieContainer属性 - 首次登录后,服务端返回的
Set-Cookie头会被自动存入该容器,后续请求自动带上 - 若服务端用的是
ASP.NET_SessionId,且没设HttpOnly,你可以手动读取:cookie.GetCookies(new Uri(url))["ASP.NET_SessionId"].Value - 注意编码:POST 数据用
Encoding.UTF8还是Encoding.GetEncoding("gb2312")必须和服务端一致,否则参数解析失败,登录白做
老系统升级前的临时 Session 替代方案
无法立刻迁移到 Core?又不想碰 SQL Server Session 的坑?那就绕过 SessionStateModule,自己用 Redis 托管会话数据。
要点很直白:
-
web.config中必须关掉原生 Session:<sessionstate mode="Off"></sessionstate>,否则两个机制打架,Session["x"]写进去,Redis里查不到 - Key 设计建议带前缀和过期时间,例如
session:{guid}:user,用EXPIRE命令设 TTL,别依赖服务端被动清理 - 在
Global.asax.cs的Application_BeginRequest里解析 Cookie、查 Redis、把反序列化的Dictionary<string object></string>存进HttpContext.Items,页面里用Context.Items["mySession"]取 - 序列化别用
BinaryFormatter(已废弃且不安全),改用System.Text.Json或Newtonsoft.Json,并统一处理 DateTime 格式
真正难的从来不是“怎么存”,而是“什么时候删”和“删不干净怎么办”。Redis key 泄漏、Cookie 被篡改、时钟不同步导致过期误判——这些细节比选哪种存储方案更决定线上稳定性。










