如何防止Web窗体DataTable被不同计算机用户跨会话访问
问题根因
和DataTable本身无关,核心问题是你错误使用了static静态变量存储用户私有状态,直接导致跨用户数据串扰。
ASP.NET 中类的静态变量是应用程序域级别的全局共享资源,所有访问当前站点的用户,都会读写同一个静态变量实例。你在页面类中做了如下声明:
public partial class Tvrtb : System.Web.UI.Page { // 用于为日历控件着色的ArrayList static ArrayList datesArray; static DataTable dtArray; }
这种写法下,不管多少用户、从什么终端登录,所有操作都会修改同一份datesArray和dtArray:A选的日期会写到共享实例里,B访问时读到的就是A写进去的数据,反过来B的修改也会被A看到,就是你遇到的串扰现象。
除此之外你的代码还有两个明显的状态管理bug:
- 只在首次非回发请求(
!IsPostBack)中初始化了dtArray,datesArray从未做初始化,首次点击日期时存在空引用异常风险; - 虽然在
gvbind方法里把两个对象存入了ViewState,但从未在页面生命周期早期从ViewState读回值,完全依赖静态变量的共享值维持状态,不仅串用户,一旦应用池回收释放静态变量,用户的操作状态会直接丢失。
修复方案
不需要放弃DataTable,只要修正变量作用域和状态读写逻辑即可,具体修改步骤:
- 移除两个字段的
static修饰符,改为页面类的普通实例字段,每个请求的页面实例会独立持有这两个对象,不会共享:public partial class Tvrtb : System.Web.UI.Page { ArrayList datesArray; DataTable dtArray; } - 补全Page_Load中的状态恢复逻辑,每次页面加载时先从ViewState读回之前存储的用户操作数据,仅在首次访问时初始化新的对象:
protected void Page_Load(object sender, EventArgs e) { // 回发时从ViewState恢复用户之前选的数据 if (ViewState["selectedDates"] != null) { datesArray = (ArrayList)ViewState["selectedDates"]; } if (ViewState["vsDTArray"] != null) { dtArray = (DataTable)ViewState["vsDTArray"]; } if (!Page.IsPostBack) { // 首次访问初始化空数据结构 datesArray = new ArrayList(); dtArray = new DataTable(); dtArray.Columns.Add("VacReqNum", typeof(string)); dtArray.Columns.Add("ReqDate", typeof(DateTime)); dtArray.Columns.Add("ReqHours", typeof(string)); dtArray.Columns.Add("VacReqID", typeof(string)); dtArray.Columns.Add("VacReqDayID", typeof(string)); // 初始化后存入ViewState,供后续回发使用 ViewState["selectedDates"] = datesArray; ViewState["vsDTArray"] = dtArray; // 首次加载的控件状态初始化 cleb.Visible = true; NewVac.Visible = false; } } - 原有日期选择、GridView绑定的业务逻辑不需要大改,
DisplaySelectedDates方法直接读取当前实例的datesArray给日历着色即可,每个用户的状态存在自己页面的ViewState中,完全隔离,不会再出现串扰。
可选替代实现方案
如果觉得ViewState存储DataTable会增加页面渲染体积(ViewState会序列化后存在页面隐藏域,随请求回传),可以选择以下方案:
- 用Session存储用户临时选的日期数据:逻辑和上述ViewState写法完全一致,只是把读写载体换成Session,数据存在服务端,不会增加页面传输体积,注意Session有默认过期时间,适合这类短时间填表的场景。
- 前端维护临时状态:用JS在前端记录用户选中的日期、填写的休假时长,不需要每次选日期都回发服务端,等用户最终提交申请时,一次性把所有数据传到服务端做校验入库,这种方案服务端不需要在填表过程中维护临时状态,性能最优,也从根源上避免了状态共享导致的串扰问题。
注意:静态变量仅适合存储全应用共享的全局数据,比如系统配置、公共缓存类内容,绝对不要用来存储单个用户的私有临时状态,只要用静态变量存用户数据,必然会出现跨用户串扰问题。
内容的提问来源于stack exchange,提问作者Huerita37
相关产品推荐
相关产品推荐

