I am trying to set a variable on every page load automatically from the Global.asax file.
I thought I could do this from Application_BeginRequest but it doesn't seem to be working.
The variable is set from a database, essentially I am doing a very quick call to the DB to check if I need to do something else. I can't go into the detail now but can't use a cache for this.
So, I have tried many ideas, but not getting anywhere, here are two most logical to my mind:
1: Setting the variable in Application_BeginRequest
Public Class Global_asax
Inherits System.Web.HttpApplication
Shared Property MyVar as String
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
MyVar = CallToDatabase()
End Sub
End Class
2: Setting the variable at the start of the Global.asax file:
Public Class Global_asax
Inherits System.Web.HttpApplication
Shared Property MyVar as String = CallToDatabase()
End Class
Of these two, these are the problems:
Version (1) doesn't seem to set the variable at all, when trying to access I am getting an empty value.
Version (2) does work, but the value is static across page loads, meaning that if I refresh or move to another page, the value remains the same even when I know it should have changed.
You can use inheritance. Create a class (BasePage) and every page can inherit this base page. In the Page_Load (or Pre_Init) of the base page, put your DB check. This will allow you to check on some pages, but not all (if that is ever necessary).
Related
I have some Ajax on a web page that feeds some data to a server-side VB.Net method. Once that data is in the server-side method, I need to call another server-side method to use the data I just collected. Here is a really simplified example:
' This method gets the input from the Ajax code on the web page.
<System.Web.Services.WebMethod> _
Public Shared Sub GetAwesome(VBInputText As String)
Dim strTest As String = VBInputText
' Now that we have collected input from the user,
' we need to run a method that does a ton of other stuff.
DisplayAwesome(VBInputText)
End Sub
Protected Sub DisplayAwesome(AwesomeIn As String)
' The real app does a lot more than this. For this example, it
' just sets the text of a literal.
litAwesomeResult.Text = AwesomeIn
End Sub
Of course, in the above example DisplayAwesome(VBInputText) gives me the 'Cannot refer to an instance member...' error. So, is it possible now to call Protected Sub DisplayAwesome from Public Shared Sub GetAwesome? I'm hoping to stay close to this sort of solution because it would play very well with the app as it is already written by another coworker.
unfortunately you cannot do this, Since the page method DisplayAwesome is defined as Protected and you requires an instance of the class to access the Protected method. But changes in another instance will not reflect in the current UI. another thing you can do is Make DisplayAwesome as Shared, but this time you cannot access the UI elements inside the shared function.
The thing you can do in this situation is, return data to the called method(in front end) and handle the litAwesomeResult.Text there
Call sub with name of Form Class like this:
FormName.DisplayAwesome(VBInputText)
In VB.Net, you can call the method not shared from a shared method with Name of Form Class by default instance, because The default instance is an object Form type that the VB application framework create and manage it, when the form is added to the project.
For more info see this :
VB.NET Default Form Instances
I have a session variable with a datatable assigned to it. For some reason the results from the datatable (display to user in a GridView) are being shared accross multiple users who are logged in. I thought each session was independent? So when one user makes changes then the other users see those results added to their results. Not sure why. I am not using Application variables.
I initialize the Session variable in Global_asax, then populate it on a button command after the user has filled out the required entries.
Imports System.Web.SessionState
Public Class Global_asax
Inherits System.Web.HttpApplication
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
Session("RDDT") = New DataTable
End Sub
End Class
As it stands, I did overlook something. There was a usercontrol that someone else had created that had Public variables. The application was treating them as static. All I did was remove them and changed where in use to Session varibles. The Application works as intended now.
I have created an ASP.NET class derived from the standard WebControls.TextBox, with the intention of adding extra properties that will persist between post-backs. However, I cannot figure how to get the values in these properties to persist.
I have tried setting the value of the properties into the controls ViewState as part of the PreRender handler, but the value is then not accessible in the Init handler on the post-back, because the ViewState has not yet been setup.
I could look for the ViewState value in the Load handler of the control, but if the page/usercontrol that is using the control asks for the properties value during its Load handler, the control hasn't yet reached it's Load handler, and it therefore not there.
My current class looks something like this...
Public Class MyTextBox
Inherits TextBox
Private _myParam As String = ""
Public Property MyParam As String
Get
Return _myParam
End Get
Set(value As String)
_myParam = value
End Set
End Property
Private Sub MyTextBox_Init(sender As Object, e As EventArgs) Handles Me.Init
If Page.IsPostBack Then
_myParam = ViewState("myParam")
End If
End Sub
Private Sub MyTextBox_PreRender(sender As Object, e As EventArgs) Handles Me.PreRender
ViewState("myParam") = _myParam
End Sub
End Class
I must be missing something really simple, such as whether there is an attribute I can set against the property.
UPDATE
Thanks to #AVD pointing out that I really had very little clue about the ViewState and the Init / Load stages, I finally figured it all out.
If you have the time (and if you're doing any major ASP.NET work, you need to make the time) please read the Understand ASP.NET View State document that #AVD pointed me to. It will explain a lot.
However, what it didn't explain is if you place your control within a <asp:Repeater>, you may as well throw all the rules out of the window... and that is exactly the problem I was experiencing.
In the end, the way I managed to get it to work was to use a <asp:PlaceHolder> control within the repeater, create an instance of my control within the ItemDataBound handler of the repeater, and then add the control to the <asp:PlaceHolder>... all done within the Init section (which fortunately I'm able to do).
As Andrew found out in this previous question you can end up in a chicken/egg situation, where you need to create the controls in the Init, but you won't know what controls you need until the Load.
(I have still made AVD's answer the correct one, because in the context of my original question, it is absolutely correct).
You have to store/retrieve value to/from ViewState within the properties accessors.
Public Property MyParam As String
Get
If IsNothing(ViewState("myParam")) Then
return string.Empty
End IF
Return ViewState("myParam").ToString()
End Get
Set(value As String)
ViewState("myParam") = value
End Set
End Property
I've taken over the maintenance of the website (ASP.NET VB) and on one particular page I noticed the below code
Inherits System.Web.UI.Page
Public Shared UserNumber As String
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
UserNumber = Session("UserNumber")
...
End Sub
My question is whether the variable UserNumber can be accessed or changed by any other user than the current one?
Many thanks
A Shared variable is the same as a static variable in C#.
These can be shared across all instances, therefore different users would share the same variable.
Looking at the variable name, I would assume you would need to remove this Shared
You are applying a Session variable value to the Shared String on Page_Init.
Therefore each time the user loads the page, their session variable will override the current value.
If you are not using this variable outside of this class, then I would recommend changing it to:
Protected UserNumber As String
EDIT My initial answer was incorrect. Trying again...
Technically, as #Curt indicated, a Shared variable is shared across instances of the class.
However, with the code as is, it is less likely that the value will be shared amongst users as it is set to each user's local copy of the value in their Session in Page_Init.
There is a possible "race condition" where after the shared variable UserNumber has been initialised in Page_Init, and another user submits a request which updates the value of that variable from their session, the first user will then see the second user's value. i.e. users can see other user's values for concurrent requests.
Instead, I recommend using a ReadOnly non-shared property to get the value from the Session once:
Private mUserNumber As String
Public ReadOnly Property UserNumber As String
Get
If String.IsNullOrEmpty(mUserNumber) Then
mUserNumber = Session("UserNumber")
End If
Return mUserNumber
End Get
End Property
This uses a pattern called "Lazy-loading", which I use in read-only properties a lot on pages to improve performance and readability of code.
I am using this example I found to learn how to load class files and access variables through them. This is in a file called Class1.vb in the App_Code folder (this is not an app project):
Imports Microsoft.VisualBasic
Public Class my_class
Public Shared Sub my_sub()
Dim vartest As String
vartest = 10
HttpContext.Current.Session("myvar") = vartest
End Sub
End Class
This is the codebehind on the aspx file:
Imports my_class
Partial Public Class test
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
my_class.my_sub()
Label1.Text = HttpContext.Current.Session("myvar")
End Sub
End Class
How could I access the vartest variable without using a session, since if this is accessed by multiple functions at the same time the variable can be overwritten I assume. Is it possible to go the other way, where a variable is sent to a class file?
It sounds like you need a quick overview of some basic ASP.Net Webforms concepts. Up first I'll counter a common newbie misconception:
Your Page class does not hang around on the web server for very long
I think many new ASP.Net developers have this idea of the web server keeping a single instance of their page class for every user session that hits their site, and each postback or event uses this same page class instance. That's just not how it works. ASP.Net page class instances are nearly always created and destroyed again in well under a second, and most experienced developers see it as a big problem if it takes longer.
ASP.NET relies on the HTTP protocol
The thing to remember here is ASP.Net still relies on the HTTP protocol, and http boils down to requests and responses. When you view a web page, your browser first sends a request to a server. The server responds, usually with an html document. The browser will then parse the html; based on what it sees in the html the browser may send more requests to the server for additional resources, such as javascript, images, or css files. Each request results in a separate response, and the browser uses all these resources to render the page to the screen. However, the ASP.Net runtime normally does not have to process the additional requests (that would make things slower) — ony the initial html needs ASP.Net support; you want the other resources to be basic files that can be cached.
The ASP.Net runtime creates a new instance of your class for every request.
When the ASP.net runtime processes a request for a page, it will create a new instance of your page class. The runtime will follow the ASP.Net Page lifecycle (this should really be named the "ASP.Net Page Request Lifecycle"), and call certain methods or raise certain events in this class instance, in a specific order defined by the lifecycle.
This means every postback or event runs in a different instance of your class.
It also means every postback or event is rebuilding and transmitting all of the html the goes into your page, and not just the portions you want to change. For your server code, the consequence is the only thing class-level variables are really good for in ASP.Net is things that will be used within a single http request. For the browser, the consequence is you're working with a brand new DOM after every event.
To understand all of that, it's important here to also have a good understanding of the difference between a class and an instance of a class. A couple items in your question make me unsure whether you have this understanding yet.
The ASP.Net runtime shares one application instance among all users of your site
The web server typically only has one instance of your application for the entire web site and all it's users. Therefore, anything with a Shared/static scope is common to every user. It's rarely appropriate in ASP.Net for anything to be Shared/static.
So how do you handle data that should live with a single user or visit to your site?
This is exactly what the Session is for. A session will always be unique to an individual request at any given time. You're worried about multiple functions accessing the session at the same time, but this does not happen. The ASP.Net Page Lifecycle ensures that unless you manually spawn additional threads, only one function at a time is running for a given HttpContext and Session. If a user somehow sends two requests at about the same time that should have the same Session/HttpContext, one will be held by the ASP.Net runtime until the other is completed. If you don't want to reference the session all the time, you can build properties in your class that wrap session variables. See #Pankaj's answer for an example.
First, a Session has user-scope, so it will not be overwritten by another Request.
Is it safe to access asp.net session variables through static properties of a static object?
You could encapsulate the access into a property:
Public Shared Property MyVar() As String
Get
If HttpContext.Current.Session("MyVar") Is Nothing Then
HttpContext.Current.Session("MyVar") = ""
End If
Return DirectCast(HttpContext.Current.Session("MyVar"), String)
End Get
Set(value As String)
HttpContext.Current.Session("MyVar") = value
End Set
End Property
Then you can get the variable by:
Label1.Text = my_class.MyVar
In addition to the "Tim Schmelter" reply....
You can create a BaseClass which will inherit from
System.Web.UI.Page
Place the property as suggested by "Tim". The only change you need to do is to change the access modifier to Protected and you should remove Public and Shared
You can also keep other common functions, properties that can we reused in other classes also... Similarly you can create BaseControls as well for your User controls
Finally, inherit this class in the web form....
Hope this will help you...
Base Class code
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web
Public Class BaseClass
Inherits System.Web.UI.Page
Protected Property MyVar() As String
Get
If HttpContext.Current.Session("MyVar") Is Nothing Then
HttpContext.Current.Session("MyVar") = ""
End If
Return Convert.ToString(HttpContext.Current.Session("MyVar"))
End Get
Set
HttpContext.Current.Session("MyVar") = value
End Set
End Property
End Class
Sample Code "Behind Code" - Showing the usage of Protected member Data from Base Class
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Public Partial Class Default5
Inherits BaseClass
Protected Sub Page_Load(sender As Object, e As EventArgs)
If Not Page.IsPostBack Then
Dim str As String = Me.MyVar
End If
End Sub
End Class
Generally you can use different places to store application state: Application (application wide, saves state into application domain), Session (there can be saved everything what will be accessed by current browser session), ViewState (variables stored in hidden input field and will be posted on every postback). Of course you can also save state to database or file. I'm not sure what you want to achieve, but looks like you looking for something like ViewState.
Read ASP.NET State Management