VB.NET ASP WebForm共享变量问题:多用户请求信息互见故障求助
VB.NET ASP WebForm 多用户并发时确认页展示他人数据问题
在VB.NET ASP WebForm应用中,请求创建页面提交后跳转至确认页,展示确认号(confirm_no)和玩家名称。但多用户同时操作时,确认页会显示其他用户的确认号和玩家名称。
相关代码
提交请求的WebMethod代码
Private Shared selectedRequest As PostRequestModel = Nothing <System.Web.Services.WebMethod(EnableSession:=True)> Public Shared Function PostRequest(ByVal earlierTime As String, ByVal latestTime As String, ByVal request As String) As String selectedRequest = JsonConvert.DeserializeObject(Of PostRequestModel)(request) SyncLock selectedRequest selectedearlierTime = GetTimeIn24Hour(earlierTime) selectedlatestTime = GetTimeIn24Hour(latestTime) selectedRequestTime = GetTimeIn24Hour(selectedRequest.playTime) selectedRequest.earliestTime = selectedearlierTime selectedRequest.latestTime = selectedlatestTime CreateRequest() HttpContext.Current.Session("confirmed_request_response_" & HttpContext.Current.Session.SessionID) = selectedRequest If cpError Then logger.Error("App: The players don't qualify for this request because of the following error, " + mErrorReason) Else If HttpContext.Current.Session("Main_confirm") IsNot Nothing Then confNo = HttpContext.Current.Session("Main_confirm") End If logger.Info("App: Your Tee Time request has been recorded having confirmation number " + confNo) End If Dim response = New BookingValidationResponse(Not cpError, mErrorReason) Return JsonConvert.SerializeObject(response) End SyncLock End Function
确认页读取Session的代码
Public Sub LoadRequestFromSession() Dim sessionKey As String = "confirmed_request_response_" & HttpContext.Current.Session.SessionID If HttpContext.Current.Session(sessionKey) IsNot Nothing Then Dim requestFromSession As PostRequestModel = DirectCast(HttpContext.Current.Session(sessionKey), PostRequestModel) End If End Sub
问题原因
- 静态变量共享冲突:
selectedRequest是Shared(静态)变量,ASP.NET中静态变量属于应用域级别,所有用户请求共享同一实例。多用户并发时,后一个用户的请求会覆盖前一个用户的selectedRequest数据,导致存入Session的可能是被覆盖后的对象。 - 无效的同步锁:
SyncLock selectedRequest使用的锁对象是selectedRequest本身,但这个变量在进入同步块前就被重新赋值,锁的对象会随请求不断变化,根本无法起到同步保护的作用,反而会导致并发数据混乱。
解决方案
1. 移除静态变量,改用局部变量
将所有与当前请求相关的变量改为方法内的局部变量,每个请求创建独立的对象实例,避免跨用户共享数据。
2. 使用固定的全局锁对象
如果CreateRequest方法涉及共享资源(比如数据库操作、全局缓存),使用一个固定的静态锁对象来同步操作,确保同一时间只有一个请求执行共享资源操作。
3. 直接存储当前请求的局部实例到Session
处理完成后,直接将当前请求的局部PostRequestModel实例存入Session,不要通过静态变量中转。
修改后的代码示例
优化后的WebMethod代码
' 定义固定的全局锁对象,用于同步共享资源操作 Private Shared ReadOnly lockObj As New Object() <System.Web.Services.WebMethod(EnableSession:=True)> Public Shared Function PostRequest(ByVal earlierTime As String, ByVal latestTime As String, ByVal request As String) As String ' 创建当前请求专属的局部实例 Dim currentRequest = JsonConvert.DeserializeObject(Of PostRequestModel)(request) ' 所有与当前请求相关的变量都改为局部变量 Dim selectedearlierTime = GetTimeIn24Hour(earlierTime) Dim selectedlatestTime = GetTimeIn24Hour(latestTime) Dim selectedRequestTime = GetTimeIn24Hour(currentRequest.playTime) currentRequest.earliestTime = selectedearlierTime currentRequest.latestTime = selectedlatestTime ' 使用固定锁对象同步共享资源操作 SyncLock lockObj CreateRequest() ' 直接将当前请求的实例存入Session HttpContext.Current.Session("confirmed_request_response_" & HttpContext.Current.Session.SessionID) = currentRequest Dim confNo As String = String.Empty If cpError Then logger.Error("App: The players don't qualify for this request because of the following error, " + mErrorReason) Else If HttpContext.Current.Session("Main_confirm") IsNot Nothing Then confNo = HttpContext.Current.Session("Main_confirm").ToString() End If logger.Info("App: Your Tee Time request has been recorded having confirmation number " + confNo) End If End SyncLock Dim response = New BookingValidationResponse(Not cpError, mErrorReason) Return JsonConvert.SerializeObject(response) End Function
确认页代码补充(绑定控件)
Public Sub LoadRequestFromSession() Dim sessionKey As String = "confirmed_request_response_" & HttpContext.Current.Session.SessionID If HttpContext.Current.Session(sessionKey) IsNot Nothing Then Dim requestFromSession As PostRequestModel = DirectCast(HttpContext.Current.Session(sessionKey), PostRequestModel) ' 将数据绑定到页面控件,示例: lblConfirmNumber.Text = requestFromSession.ConfirmNo lblPlayerName.Text = requestFromSession.PlayerName End If End Sub
内容的提问来源于stack exchange,提问作者Arsalan Qaiser
相关产品推荐
相关产品推荐

