0

We have an aspx page which calls the code behind using $post.

The code works well until there are 2 (or more) users who do the post at the same time.

When that happens, the one user's data gets returned on the other's webpage.

The code is in VB.NET but I think the issue is in the way the aspx works with the code behind, so I've included C# in the tags. Happy to hear any C# suggestions as well :)

function getDetails() {
          
            if ($('.loader-container').is(':visible')) return;
            
            var newItem = "";
            var bool;
            var Barcode = $('#txtBarcode').val()

            $('.loader-container').show();

            var IBTOutNumber = Barcode;
           
            var formData = {                   
                IBTOutNumber: IBTOutNumber,
            };

            RequestUrl = "sendstock.aspx?Page=SendStock";
            RequestUrl += "&Action=GetStockDetails";                              
            $.post(RequestUrl, { FormData: JSON.stringify(formData) }, function (respone) {
              
                 $('.loader-container').hide();
                    if (respone.Success == true) {
                        var dataItems = JSON.parse(respone.dt)
                        $.each(dataItems, function (index, row) {
                          
                            newItem += "<tr class='dispatch Pointer'>" +
                                "<td id='IBTOutNumber' >" + row.transaction_number + "</td>" +
                                "<td id='BranchName'>" + row.branch_name + "</td>" +
                                "<td id='BranchCode'>" + row.branch_code + "</td>" +
                                
                                "</tr>";
                            $("#errMsg").addClass("hide")
                            $("#stock tbody").append(newItem);
                            bool = true;

                        });
                        count()
                        
                    }
            }, 'json');
        }

Here is the code behind.

    Dim Action = String.Empty
    Dim Page = String.Empty
    Dim Message = String.Empty

    If String.IsNullOrEmpty(Request.QueryString("Action")) = False Then
        Action = Request.QueryString("Action").ToString()
    End If

    If Request.QueryString("Page") IsNot Nothing And Request.QueryString("Page") <> "" Then
        Page = Request.QueryString("Page").ToString()

        Dim RequsestFormData = Request.Form("formData")

        Select Case Page
            Case "SendStock"
                Select Case Action
                    Case "GetStockDetails"
                        Dim getStock As New GetStock
                        Dim getDetails = JsonConvert.DeserializeObject(Of GetStockDetails)(RequsestFormData)
                        getStock = GetStockDetail(getDetails.IBTOutNumber)
                        Message = JsonConvert.SerializeObject(getStock)
                        Response.Clear()
                        Response.Write(Message)
                        Response.ContentType = "Text/Json"
                        _SendContent = True

        End Select

    If _SendContent = True Then
        Response.End()
    End If

Here is the code for the GetStockDetails function:

Public Function GetStockDetail(ByVal IBTOutNumber As String) As GetStock
    Dim getStock As New GetStock

    Try

        Dim dt As New DataTable
        dt.Columns.Add("transaction_number")
        dt.Columns.Add("branch_code")
        dt.Columns.Add("branch_name")
        dt.Columns.Add("address_line_1")
        dt.Columns.Add("address_line_2")
        dt.Columns.Add("address_line_3")
        dt.Columns.Add("address_line_4")
        dt.Columns.Add("address_line_5")
        dt.Columns.Add("counter", GetType(Integer))

        Dim _ReturnedData As DataTable
        Try
            _ReturnedData = _BLayer.ReturnBranchDetails("010", IBTOutNumber, True)

        Catch ex As Exception
            _blErrorLogging.ErrorLogging(ex)
            getStock.Message = "Something went wrong."
            getStock.Success = False
            Return getStock
        End Try

        If _ReturnedData.Rows(0)("error") <> "" Then
            getStock.ErrorMessages &= _ReturnedData.Rows(0)("error") & vbCrLf
            GoTo NoLine
        End If
        dt.Rows.Add(IBTOutNumber, _ReturnedData.Rows(0)("branch_code"), _ReturnedData.Rows(0)("branch_name"), _ReturnedData.Rows(0)("address1"), _ReturnedData.Rows(0)("address2"), _ReturnedData.Rows(0)("address3"), _ReturnedData.Rows(0)("address4"), _ReturnedData.Rows(0)("address5"))

NoLine:

        Dim json As String = JsonConvert.SerializeObject(dt, Formatting.Indented)
        getStock.dt = json
        getStock.Success = True

    Catch ex As Exception
        _blErrorLogging.ErrorLogging(ex)
        getStock.Message = "Something Went Wrong."
        getStock.Success = False
        Return getStock
    End Try

    Return getStock
End Function

And code for the ReturnBranchDetails function:

Public Function ReturnBranchDetails(ByVal CompanyCode As String, ByVal IBTOutNumber As String,
                                    ByVal isDispatch As Boolean) As DataTable


    Dim curdata As New DataTable
    curdata.TableName = "dispatch"
    curdata.Columns.Add("error")
    curdata.Columns.Add("branch_name")
    curdata.Columns.Add("branch_code")
    curdata.Columns.Add("address1")
    curdata.Columns.Add("address2")
    curdata.Columns.Add("address3")
    curdata.Columns.Add("address4")
    curdata.Columns.Add("address5")

    tmpSQL = "SELECT branch_details.branch_name,dispatched_timestamp,receiving_date " &
             "FROM ibt_transactions " &
             "WHERE ibt_transactions.transaction_number = '" & IBTOutNumber & "' " &
             "LIMIT 1"
    Try
        Ds = usingObjDB.GetDataSet(_ConnectionString, tmpSQL)
        If usingObjDB.isR(Ds) Then
            For Each dr As DataRow In Ds.Tables(0).Rows
                If isDispatch = True Then
                    If dr("dispatched_timestamp") & "" <> "" Then
                        curdata.Rows.Add("IBT Out " & dr("receiving_date") & " has already been dispatched.")
                        Return curdata
                        'Return "IBT Out " & dr("transaction_number") & " has already been dispatched."
                    End If

                  
                Else
                     If dr("receiving_date") & "" <> "" Then
                        curdata.Rows.Add("IBT Out " & dr("transaction_number") & " has not been dispatched.")
                        Return curdata
                        'Return "IBT Out " & dr("transaction_number") & " has already been dispatched."
                    End If

                End If



                curdata.Rows.Add("", dr("branch_name"), dr("receiving_branch_code"), dr("address_line_1"), dr("address_line_2"),
                                 dr("address_line_3"), dr("address_line_4"), dr("address_line_5"))
               
            Next
        Else
            curdata.Rows.Add("IBT Out Number: " & RG.Apos(IBTOutNumber) & " does not exist.")
            Return curdata
            'Return "IBT Out Number: " & RG.Apos(IBTOutNumber) & " does not exist."
        End If
    Catch ex As Exception
        curdata.Rows.Add(ex.Message)
    End Try

    Return curdata

End Function
Daniel Gee
  • 426
  • 7
  • 21
  • 2
    There's something wrong with your server-side code, which you haven't shown. At a guess, you may be using `static` / `shared` fields incorrectly. – Richard Deeming Jan 14 '22 at 10:43
  • @RichardDeeming, I've added the code behind to the question. Thanks! – Daniel Gee Jan 14 '22 at 10:52
  • 1
    Your Javascript uses `Page=SendStock`, but your server-side code only handles `Page=DispatchStock`. Is that in your code, or a mistake in the question? – Richard Deeming Jan 14 '22 at 10:56
  • @RichardDeeming, sorry, my mistake. I fixed the Typo. It was a mistake in the question. – Daniel Gee Jan 14 '22 at 11:07
  • What does `GetStockDetail` do? – Jamiec Jan 14 '22 at 11:11
  • That function queries the database and gets the record for IBTOutNumber. – Daniel Gee Jan 14 '22 at 11:32
  • 1
    We might need some details on that GetStock function. Does it persist any values - get some value from static class - maybe from session()? – Albert D. Kallal Jan 14 '22 at 17:26
  • @AlbertD.Kallal, I have updated the question and added the functions. Thanks! – Daniel Gee Jan 17 '22 at 07:05
  • How is authentication handled in your app? I don't see that in your code. One user's request shouldn't have access to the other user's session. – Dan Csharpster Jan 18 '22 at 16:04
  • @DanCsharpster, there is a login screen which verifies the user's permissions. On the load of this page it checks that the user has the required permission to access the page. There is no user data sent in the request. I considered that the issue might be a session problem, but I can't understand how IIS would be mixing up the sessions? – Daniel Gee Jan 19 '22 at 12:10
  • @DanielGee are you trying them from different tabs in the same browser? Tabs share cookies, so if you login as user1 on tab1, then login as user2 on tab2, then go back to tab1, you are now user2, not user1. That's one way to potentially reproduce this issue. – Dan Csharpster Jan 19 '22 at 16:32
  • Could this be a session issue? Or perhaps you have a singleton in your application that holds your users data. When user 1 logs in they have their data. When user 2 logs in, user 1 & 2 will have user 2's data – JamesS Jan 20 '22 at 10:34
  • 1
    As mentioned before, is there anything shared/static used? Most of the time this is the problem. – Firewizz Jan 21 '22 at 10:14
  • 1
    Like `usingObjDB`, Maybe something in there is static – Firewizz Jan 21 '22 at 10:26
  • @DanCsharpster, the issue occurs on different PCs. – Daniel Gee Jan 21 '22 at 12:16
  • @JamesS, no user data is being used in this code. Each user should have their own independant session in IIS. The data is being fetched based on the IBTOutNumber, not based on the user. – Daniel Gee Jan 21 '22 at 12:24
  • @Firewizz, there are no shared or static variables / objects. We use the usingObjDB thousands of time in the Solution and don't have this issue anywhere else. The issue only occurs when 2 users click submit at the exact same time. – Daniel Gee Jan 21 '22 at 12:26
  • Can you share the contents of the isR method of usingObjDb? – John Glenn Jan 21 '22 at 16:40
  • If it occurs when two users click submit at the exact same time then it is most likely a server-side issue and most probably the SQL server you are using is not configured correctly or is unable to handle synchronous requests. That would be my first port of call if I was happy that there's nothing persisting in my code. Incidentally you've got a serious security issue there which I'd be more concerned with than your code not working. You've got to giv your server a good look over already it sounds like a black hat playground –  Jan 22 '22 at 10:06
  • *the SQL server you are using ... is unable to handle synchronous requests* - no – Caius Jard Jan 23 '22 at 21:40
  • We're using a PostgreSQL database. It handles around 800 queries per second, on average. – Daniel Gee Jan 24 '22 at 12:06

1 Answers1

1

Update the method ReturnBranchDetails to have its own LOCALLY defined variable for tmpSql.

From what I can see, tmpSql is defined outside of the method and when the two requests are processed one is slightly behind the other and the queries that are made are the same since they share a variable across the two requests.

' Define the value here or inline the value into the "GetDataSet" method.
Dim tmpSql As String

Additionally, I'd recommend looking into using prepared statements to prevent SQL Injection. If I provided a "id" that had the value of ' OR 1=1; -- then I could get ALL records returned (or command injection, etc).

What is SQL Injection

Sample of using SqlCommand

Noah
  • 859
  • 7
  • 17