You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

问题原因

  1. 静态变量共享冲突:selectedRequest是Shared(静态)变量,ASP.NET中静态变量属于应用域级别,所有用户请求共享同一实例。多用户并发时,后一个用户的请求会覆盖前一个用户的selectedRequest数据,导致存入Session的可能是被覆盖后的对象。
  2. 无效的同步锁: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:25:59