ASP.NET - Accessing web page twice from client - asp.net

What happens if one user tries to access an ASP.NET page twice before the first page is returned to the client? Have a look at the code below:
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Session("ID") = 1
End Sub
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Response.Redirect("Default3.aspx")
End Sub End Class
Partial Class Default2
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Session("ID") = 2
End Sub
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Response.Redirect("Default3.aspx")
End Sub
End Class
Imports System.Threading
Partial Class Default3
Inherits System.Web.UI.Page
Dim intTest As Integer = 0
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
For intTest = 0 To 10
Response.Write(Session("ID") & " " & intTest & "<br>")
Thread.Sleep(1000)
Next
End Sub
End Class
Accessing default3.axpx from the same client (PC) concurrently from default.aspx (by clicking button) and default2.aspx (by clicking button) causes the session variable to be the same on both requests (though I set the variable to 1 on the first request and 2 on the second). Is it possible to replicate this behaviour without threading? I believe I have this bug in an asp.net application that does not use threading.

Your question is not about multi-threading; it is about SessionState.
ASP.NET run time uses lock to avoid overriding same session variables although it can handles multiple requests.
It's why you are do not see miss-matching results.
Please also look at -
ASP.NET Application and Page Life Cycle
ASP.NET Application Life Cycle Overview

It's important to understand that session information is stored at the application level, and really has nothing directly to do with a page.
You could compare it to a global variable in a class. If all your methods are reading and writing to this variable, it will always contain the information from the last time it was updated. It doesn't matter how many times, or which methods, updated it.
To help see this in your code, create a new class with one property. Change your session variable to be an object of this class. Modify your session logic to refer to this object instead of a string, and update the property.
Finally, put a break point on the setter of your property.
This will let you see whenever your session variable is updated, and with what value. You can also view your stack trace to see what's setting it.
-note, this is all assuming you aren't introducing a farm into this and are accessing session from different machines--

Related

Run after Init, before Page_Load

After a PostBack caused by ddlPlant_SelectedIndexChanged, I need to set set HttpContext.Current.Session("PlantNumber"). This needs to happen after ddlPlant loads in Site.Master, but before the code in Default.aspx needs the value.
Public Class SiteMaster Inherits MasterPage
Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Init
If (Not Page.IsPostBack) Then
ddlPlant.DataSource = myDataSource
ddlPlant.DataBind()
ddlPlant.SelectedValue = "1"
End If
HttpContext.Current.Session("PlantNumber") = ddlPlant.SelectedValue
End Sub
Protected Sub ddlPlant_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Handles ddlPlant.SelectedIndexChanged
End Sub
End Class
Public Class _Default Inherits Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Dim units As New List(Of EquipmentModel)
For Each unit As EquipmentModel In getUnits.Out.Results
If (CStr(unit.Plant_ID) = HttpContext.Current.Session("PlantNumber")) Then
units.Add(unit)
End If
Next
gvEquipmentUnit.DataSource = units.OrderBy(Function(n) n.Equipment_ID)
gvEquipmentUnit.DataBind()
End Sub
With the code above, when Session("PlantNumber") is set after PostBack, ddlPlant.SelectedIndex = Nothing, and ddlPlant.SelectedValue is an empty string.
I've tried moving the Session("PlantNumber") = ddlPlant.SelectedValue line to Site.Master's Page_Load instead, but that runs after it is needed in Default.aspx.vb
I looked up PreLoad, but apparently it doesn't work for the Master page.
Ultimately, I decided not to use a Session variable, and instead call the control directly from any page that needs that value on load (almost all of them):
DirectCast(Master.FindControl("ddlPlant"), DropDownList).SelectedValue

creating event control in vb.net. Multiple controls with the same ID '1' were found

Im trying to create buttons on page load and have event controls to those. Im able to create the buttons but the event doesnt seem to be triggered when the button is clicked instead it throws an error stating multiple controls with id found.I think this has something to do with postback and unique ID creation for the buttons. can some one point me as to what to be added along with this?
Sub createbutton()
Dim but As New Button
but.Text = "save"
but.ID = "but"
AddHandler but.Click, AddressOf Button_Click
Me.form1.Controls.Add(but)
End Sub
The event control for this is as below.
Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
' Handle your Button clicks here
MsgBox("done")
End Sub
Im getting the error
Multiple controls with the same ID '1' were found
The subroutine createbutton works on page load as follows.
Public Class Default3
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load ' to gen page on load ;)
createbutton()
End Sub
Help is appreciated , Thanks :)
i think you are a guy who worked a lot with VB 6.0
Control array feature is available in VB 6.0
in VB.net everything is depend upon control ID.
if you don't have specific requirement like ID should be same then i suggest pls append prefix and incremental ID would resolve your issue.
Let me know if you have some specific requirements
Thanks
Asif
Corrected Code, Instead of ID it's name which allow uniqueness
Public Class Form1
Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
' Handle your Button clicks here
MsgBox("done")
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
createbutton()
End Sub
Sub createbutton()
Dim but As New Button
but.Text = "save"
but.Name = "but"
AddHandler but.Click, AddressOf Button_Click
Me.Controls.Add(but)
End Sub
End Class

How to prevent the object from becoming null?

I have the following code. During page load, I get the customer object from the database. After that when I try to access the same object in a different method, the object comes out as empty. Assume Student object has properties like firstName, lastName etc.
Public class Test
Public oStudent as Student
Public Sub Page_Load(ByVal sender as Object, ByVal e as System.EventArgs) Handles Me.Load
oStudent = getStudent(22) 'This is just a sample. This is not my actual database.
End Sub
Public Sub Update(ByVal sender as Object, ByVal e as System.EventArgs) Handles crtlStudent.Update
Update(oStudent)'This one updates makes a database call to update the studnet
End Sub
End class
When the page loads, the student is returned from the database correctly. However, when I'm on my update method, oStudent object becomes null/empty. Is this the way the page life cycle works? If yes, I would need to store the oStudent in a session or cache it right? Is there any other way to prevent the oStudent from becoming null other using session variables or caching it?
It is not the case that the object is null in the other method but after the page is disposed. That happens at the end of every page's lifecycle, so when it was rendered as HTML and sent to the client.
So you either have to re-initialize/load the object on every postback or persist it somewhere. In your sample-code you are loading it always in Page_Load, hence i doubt that it's null anywhere. So i guess that it's not the real code which could be:
Public Sub Page_Load(ByVal sender as Object, ByVal e as System.EventArgs) Handles Me.Load
If Not IsPostBack Then
oStudent = getStudent(22) ' in a button-click handler it will be null since it's a PostBack
End If
End Sub
Is there any other way to prevent the oStudent from becoming null
other using session variables or caching it?
Nine Options for Managing Persistent User State in Your ASP.NET Application

Web Controls Not Talking to Each other in ASP.NET using VB.NET

I have an asp.net page that loads two controls, Control A and Control B. Control A has some generic form submit and clear buttons that trigger click events in its' own code behind which use reflection to call the update function in Control B which has a few input fields. I have debugged this and everything seems to be in order, however; when the update function in control B is called the input fields are not returning a value when using inputname.text or me.inputname.text. Does anyone have any ideas why this is not working? Any guidance would be appreciated.
This is the code in Control A's codebehind which calls the update method in Control B's code behind
Protected Sub btnSave_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSave.Click
Try
Dim lctlControl = Session("SelectedQstnCtl")
Dim methodObj = lctlControl.GetType().GetMethod("UpdateGenInfo", BindingFlags.NonPublic Or BindingFlags.Instance)
' Execute UpdateGenInfo method to update the data
methodObj.Invoke(lctlControl, Nothing)
Catch ex As Exception
'TODO: check for concurrency error here
End Try
End Sub
This is the update function in Control B that is being called. The session values are being passed, but the form fields are not.
Protected Sub UpdateGenInfo()
Dim lclUtil As New clUtility
Dim genInfo As New clGenInfo
Try
Dim dt As Integer
'Update Data for 1-2
dt = genInfo.UpdateGenInfo_E1_01_02(Session("ConnStrEP"), Me.varLastUpdate, Session("AppNo"), Session("RevNo"), _
Me.txtPrName.Text, Me.txtPrAddr1.Text, Me.txtPrAddr2.Text, _
Me.txtPrCity.Text, Me.txtPrState.Text, Me.txtPrZip.Text)
Catch ex As Exception
'Display error
lclUtil.DisplayMsg(Me.lblErrMsg, String.Format("Error Location: Sub LoadGenInfo (ctlE1_01_02) {0}", ex.Message))
End Try
End Sub
The most likely cause is that the control instance stored in the session is not the control instance on the current page. For example, if you're storing the control instance in the session when the page is first loaded, and retrieving it on post-back, it will be a different instance.
If you can't give Control A a direct reference to Control B, then change your code to store the reference in the Page.Items collection:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
Page.Items("SelectedQstnCtl") = TheSelectedQstnCtl
End Sub
Protected Sub btnSave_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSave.Click
Dim lctlControl = DirectCast(Page.Items("SelectedQstnCtl"), YourControlClass)
lctlControl.UpdateGenInfo()
End Sub
I see you are using reflection which might be an overkill for that task.Try referencing the method in the control directly.Make then method UpdateGenInfo public and then reference it like this.
Protected Sub btnSave_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSave.Click
Try
Dim lctlControl = CType(Session("SelectedQstnCtl"),YourControlClass)
lctlControl.UpdateGenInfo()
Catch ex As Exception
End Sub
Public Function UpdateGenInfo()
'your code here
Catch ex As Exception
End Try
End Function
This way you can easily trace where your values are getting lost.Let me know how it goes.
Try yet another simple approach working demo here
In control a
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim testb1 = CType(Me.NamingContainer.FindControl("testb1"), testb)
testb1.UpdateGenInfo()
End Sub
In control b
Public Function UpdateGenInfo()
Try
Dim a = Me.TextBox1.Text
Catch ex As Exception
End Try
End Function
Aspx Parent Page
<uc1:testa ID="testa1" runat="server" />
<uc2:testb ID="testb1" runat="server" />
The controls in testb are in an update panel.Try this and let me know if this works.

client side script for treeview events

I have a Treeview with "populateOnDemand" set to true. I want this treeview to keep its state (nodes expanded/collapsed) from one page to another. Viewstate doesn't work because the treeview is different for each page. Here is my code at the moment.
ASPX page :
<asp:TreeView
ID="arbre"
EnableViewState="true"
PopulateNodesFromClient="true"
runat="server" />
Code behind :
Protected Sub arbre_TreeNodeCollapsed(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.TreeNodeEventArgs) Handles arbre.TreeNodeCollapsed
CType(Session("listeNoeudsOuverts"), Hashtable)(e.Node.Value) = True
End Sub
Protected Sub arbre_TreeNodeExpanded(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.TreeNodeEventArgs) Handles arbre.TreeNodeExpanded
CType(Session("listeNoeudsOuverts"), Hashtable)(e.Node.Value) = False
End Sub
Protected Sub arbre_TreeNodePopulate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.TreeNodeEventArgs) Handles arbre.TreeNodePopulate
// code to populate nodes
CType(Session("listeNoeudsOuverts"), Hashtable)(e.Node.Value) = True
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Session("listeNoeudsOuverts") Is Nothing Then
Session("listeNoeudsOuverts") = New Hashtable()
End If
// other stuff
End Sub
This works well, buf I wish I could avoid the postback everytime the user expands or collapses a node. I know I can set EnebleClientScript to true and manage the events client side in Javascript but I won't be able to use my session variable anymore. Is there a way to achieve this ?
Thank you
I will answer myself to a certain extent.
I've done some tests and research, EnableClientScript is true by default, and indeed means that expand and collapse actions are processed client side, by Javascript code that is automaticalt generated by the .Net framework. You can't edit it.
Apparently, if you need to add custom actions when a user expands or collapses anode, you have to use TreeNodeExpanded and TreeNodeCollapsed events, like i did above, and can't avoid postbacks because they are triggered server-side.

Resources