用asp.net ajax 的UpdatePanel控件搞了这么一个小程序:
UpdatePanel中包含两个TextBox:TextBox1,TextBox2;
两个按钮 Button1 ,Button2
将UpdatePanel更新触发定义为Button1及Button2的 Click事件;Button1 Click事件处理代码如下:
{
System.Threading.Thread.Sleep(5000);
this.TextBox1.Text = "1";//此处设置断点
}Button2 Click事件处理代码如下:
{
System.Threading.Thread.Sleep(5000);
this.TextBox2.Text = "2";//此处设置断点
}
现做如下测试
运行页面
初始textbox1、textbox2上都无内容;
点击按钮Button1后 5秒内迅速点击 Button2 ;
则在上述两个断点都发生了中断,说明两次请求都被正确的执行了;
而页面上的结果呢?页面上的结果是TextBox2上显示2,而TextBox1上无内容;
为什么两个函数都被执行了却只显示了后一次执行的结果?
原来asp暗地里维护了页面的状态(主要是服务器控件的状态),客户端提交请求后,
将页面上各控件的状态(例如textbox的现实值)返回给服务器,
如果没有(事件响应)代码修改某控件,则服务器再把请求送来的控件数据原封不动的发到客户端;
所以,上例中,第一次请求返回到客户端,客户端把界面改成textbox1=1 textbox2为空,
而第二次由于提交到服务器上的textbox1的值为空,服务器将改值再次返回回来,结果自然是
textbox1为空了;
其实在这个例子中,程序问题也不大,既然用户第二次提交的时候他看到的textbox1就是为空,
那么最后他得到结果时textbox1为空,textbox2为1也不会让他感到奇怪。
但如果我们改一下,用户点击button1表示存储textbox1的数据到数据库中,如果成功则将textbox1显示“成功”;
用户点击button2表示存储textbox2的数据到数据库中,如果成功则将textbox2显示“成功”
据此相应的修改事件代码;
那么再做上述测试,用户发送点button1要求发送textbox1中的内容,随即(5秒内)点击button2,
则界面只会显示textbox2为“成功”,但其实数据库中已经存储了两个数据,给用户的印象却是只有第二次存储成功了!
其根本原因是updatepanel的异步更新模式给了用户并发执行应用的机会,
而如果程序仍按传统的请求-响应-请求-响应……这样但序列的思维方式编程就回让asp架构读到(界面上的)脏数据。
要找到一个完美的解决方案,我认为比较困难,
只是修改程序(例如每次主动更新updatepanel中所有可能被其他事件程序修改的控件)不能完全解决问题,
这涉及到如何将服务器端最后执行的结果在客户端最后一个呈现给用户。