不能直接用 OracleSessionStateProvider,因其自.NET Framework 4.5起已过时且依赖被移除的System.Data.OracleClient,运行时会抛TypeLoadException;必须自实现SessionStateStoreProviderBase,使用Oracle.ManagedDataAccess,并注意表结构、序列化、SQL绑定变量及清理机制。
为什么不能直接用 OracleSessionStateProvider?
asp.net 自带的 oraclesessionstateprovider 早在 .net framework 4.5 之后就被标记为过时,官方文档明确说明它“不再受支持”,且依赖已弃用的 system.data.oracleclient(该命名空间在 .net core/.net 5+ 中彻底移除)。如果你在 web.config 里硬配 type="system.web.sessionstate.oraclesessionstateprovider",运行时会直接抛出 system.typeloadexception —— 类型根本不存在。
真正能用的路径只有一条:自己实现 SessionStateStoreProviderBase,用 Oracle.ManagedDataAccess 驱动连接 Oracle 数据库。
如何手动实现 Oracle Session 存储提供程序?
核心是继承 SessionStateStoreProviderBase 并重写关键方法。重点不是全量实现,而是聚焦高频路径:CreateUninitializedItem、GetItem、SetItemExpireCallback、RemoveItem 和 ResetItemTimeout。其余如 Initialize 负责读取连接字符串和表名配置;Dispose 清理连接池资源。
- Session 数据必须序列化为
byte[](推荐BinaryFormatter仅限 .NET Framework;.NET Core+ 必须用System.Text.Json或Newtonsoft.Json+ 自定义ISessionStateItemCollection序列化逻辑) - 数据库表结构需包含:
SessionId(VARCHAR2(88),主键)、ApplicationName(VARCHAR2(255))、Created(DATE)、Expires(DATE)、LockDate(DATE)、LockDateLocal(DATE)、LockCookie(NUMBER)、Timeout(NUMBER)、Locked(CHAR(1))、SessionItemShort(VARCHAR2(8000))、SessionItemLong(BLOB) - 所有 SQL 查询必须使用绑定变量,严禁字符串拼接
ApplicationName或SessionId,否则触发 SQL 注入
Web.config 中怎么配这个自定义 Provider?
别碰 <sessionstate mode="Off|InProc|StateServer"></sessionstate> 这些预设值。必须设为 Custom,并指向你编译好的程序集类型:
<sessionstate mode="Custom" customprovider="OracleSessionProvider"><providers><add name="OracleSessionProvider" type="MyApp.Providers.OracleSessionStateProvider, MyApp" connectionstringname="OracleSessionDB" applicationname="/" commandtimeout="30"></add></providers></sessionstate>
注意几个硬性约束:
-
connectionStringName必须对应<connectionstrings></connectionstrings>下的真实名称,且连接字符串中要包含Pooling=true;Min Pool Size=1;Max Pool Size=20;,否则高并发下连接耗尽 -
applicationName建议固定为/,避免多子应用共享 session 时因名称不同导致查不到数据 - 不要设置
timeout在 provider 标签里——它由<sessionstate timeout="20"></sessionstate>统一控制,provider 内部只负责按此值写入Expires字段
容易被忽略的清理与超时陷阱
Oracle 不像 SQL Server 有 aspnet_WebEvent_LogEvent 这类内置清理作业。Session 过期记录不会自动删除,全靠你实现的 SetItemExpireCallback 触发后台线程轮询 SELECT SessionId FROM Session WHERE Expires —— 但 Oracle 的 <code>SYSDATE 是服务器本地时区,而 ASP.NET 默认用 UTC 时间计算 Expires,时区不一致会导致大量“假过期”或“永不过期”。
解决方案只有两个:
- 在写入
Expires时统一转为数据库服务器时区(用TimeZoneInfo.ConvertTimeToUtc反向推算后存) - 或者强制数据库和应用服务器时区一致(例如都设为 UTC),并在连接字符串加
Connection Timeout=15;Statement Cache Size=10;DateTimeKind=Utc;
另外,LockCookie 字段必须用 OracleNumber 类型映射,用 int 直接赋值会触发精度截断,导致解锁失败 —— 这个细节在 Oracle.ManagedDataAccess 的参数绑定里极易翻车。










