How to get a public variable (in a Module) to NOT share value between users - asp.net

I'm working in an ASP.NET (VB) Web Application with Windows/Active Directory Authentication
I am using a module so that I can call public subroutines and functions, and reference variables, without having to instantiate a new object to access them on each page.
Within that module, I have some Public variables that I am using in multiple pages throughout the web application. I've recently realized that the values for these public variables in the module get shared between all users.
THE GOAL:
I want the value for these global variables to be specific to a single user and not shared between all sessions, and I do not want to have to instantiate a new object/class on every page that uses the variable.
THE CATCH:
I don't want to store the value in a client-side variable such as a cookie or session. I want the value to be stored on the SERVER but specific to each client/user.
The only thing I can think to do is setup a global collection/dictionary and store the variables with the authenticated user names, but then I need to have specific functions to get and set the values. While this will work, it requires all the references to these variables on all pages in the application to be updated.
EXAMPLE OF THE PROBLEM:
The below code shows how I am creating the public variable within the module and how the value is being set from one page and used on another. I'd like to continue to use this variable in the same way and share it's value between pages, but the value of the variable needs to NOT be shared between users.
-- MODULE.VB --
Public Module MyMod
Public myVariable as String = ""
End Module
-- MAINPAGE.VB --
Partial Class _Default
Sub Page_Load() Handles MyBase.Load()
myVariable = "HELLO WORLD"
End Sub
End Class
-- NEXTPAGE.VB --
Partial Class _Default
Sub Page_Load() Handles MyBase.Load()
Response.Write(myVariable)
End Sub
End Class
There are a LOT of pages in this application that will need to be manually updated if I have to use my userID-indexed collection solution, so I'm hoping there is a way to simply scope these variables differently or a way to disable the sharing between sessions.
Thanks in advance!

You didn't indicate whether or not the variables need to be persisted across page round trips or whether they are just used within each page's lifecycle.
If they are not persisted across pages, then perhaps the easiest solution is to have all of your pages inherit from a based page class and then move the values from the module into the base page. This way you won't have to change any variable references, only page inheritance.
If you do want to persist the values, completing the above changes makes it much easier to implement. You can then turn the member variables on the base page into properties and embed your user specific caching and fetching in the getter and setter.
For example, instead of:
Public MyVariable As String = ""
You would have something like:
Public Property MyVariable As String
Get
Return GlobalMyVariableCache(UserNameKey)
End Get
Set (Value As String)
GlobalMyVariableCache(UserNameKey) = Value
End Set
End Property

The problem you are coming across is a very common one in web programming. A Module's members are static - meaning there is one instance of them across the entire AppDomain of your application. Every user that accesses these will get the same object - you have already learned this.
Your options are exactly what you described. You could possibly replace the public variable in your module with a property whose getter you write to access a user-specific field in a dictionary (please remember thread safety when writing this getter code).
The much easier solution would be to use the Session. Session values are stored server-side and are user specific. The only thing that get's sent client side is the session key, and if you are using .Net authentication, this is likely already getting sent.
Good luck,

Related

using VB.NET Shared Property in inline-code: `<% =<property> %>`

i'm using Shared Property to add some text to a Div.
step of my procedure is:
define a Shared Property submitted= "not submitted" in myclass.vb .
create a mymasterpage.Master with a div:
<div><%=submited%></div>
create a page1.aspx with this code-behind:
Protected Sub Page_Load (...)
If action="submitted" then
submitted="submitted"
End If
End Sub
So far, everything is fine, but the problem is that when Master loads again , the submited keeps its value and will show:
<div>submitted</div>
i need to one time that specified submitted to "submitted" ,next time that submited called, it returns "not submited" (i.e. it's orginal value)
<div>not submitted</div>
Don't use a Shared variable or property for this.
A Shared (static in C#) variable is shared across all users of your web application. Imagine two users A and B accessing your web site at the same moment. What you are doing could cause user A to see something that was supposed to be for user B, and vice versa. You wouldn't want that, do you?
The solution is simple: Don't make the property Shared. If you have trouble accessing an instance (= non-shared) property from within your code, I suggest that you open a separate question on that. Making the property shared is not a good solution.

Create Unique Session Variable per Browser Window or Tab

Having a slight problem with creating a .Net Session based variable.
I know i can just use the Session extension and be done with it but i am looking more for a Multiple Browser (either Window or Tab, for IE) situation on a single desktop.
Currently, i have a Module declared in the Web-App and when i open up two individual Windows of IE they initially load the custom PageRouting design, as expected but once i go to the next step with both windows open, the last one to be opened is the design/logic used for the rest of the application.
Module.vb
Namespace classes
Module Globals
Public Brand As Brand
Public Test As Test
Public Results As Results
Public Primary As String = "#FFFFFF"
Public Secondary As String = "#FFFFFF"
Public Terteruary As String = "#FFFFFF"
End Module
End Namespace
In code, i reference the objects as Globals.Brand or Globals.Primary but in either case a situation where the same desktop could open up the same website with different PageRouting address, it assumes the last opened browser window.
The Brand & Test variables are initialized in the Session_Start event in Globals.asax. All references to these objects are explicit references using Globals.<variable> annotation when used. Results is initialized on first use during the execution of the website.
Question
How do i make sure that each individual browser window is loaded with its own unique session cache for use with the site?
Updated - 2012-12-03
What about a design like this?
Public Class Class1
private _sess as HTTPSessionState
...
private readonly property Session as HttpSessionState
Get
if _sess is nothing then
_sess = httpcontext.current.session
end if
return _sess
End Get
end property
...
public property Primary as string
Get
return cstr(session("primary"))
end get
Set(value as string)
session("primary") = value
end set
end property
...
end class
With Class1 being instantiated at the Master/Content page level?
Update #2 - 2012-12-03
Modified the module, let me know if this is a viable session control setup
Module Globals
'Dictionary Collection of type (SessionID:String, Quiz:classes.Quiz)
Public Quizzes As Dictionary(Of String, classes.Quiz)
Public Property Quiz(session As String) As Quiz
Get
Return Quizzes(session)
End Get
Set(value As Quiz)
Quizzes(session) = value
End Set
End Property
End Module
Final Form 2012-12-10:
Module.vb
Module Globals
'Get/Set a Quiz object into the SessionState.
Public Property Quiz(sess As HttpSessionState) As Quiz
Get
Return CType(sess("quiz"), Quiz)
End Get
Set(value As Quiz)
sess("quiz") = value
End Set
End Property
End Module
Web.config
<system.web>
...
<sessionState mode="InProc" cookieless="UseCookies"
regenerateExpiredSessionId="true" timeout="20"
cookieName="ASPNET_Quiz" />
...
</system.web>
The above form worked as expected utilizing the indexer aspect of a Property. Havent had any user instance problems. One side note, is that in order for this to work effectively the user must close all browser windows and open a new window for the session to clear out
The problem you are coming across is a very common one in web programming. A Module's members are static - meaning there is one instance of them across the entire AppDomain of your application. Every user that accesses these will get the same object.
You could possibly replace the public variable in your module with a property whose getter you write to access a user-specific field in a dictionary (please remember thread safety when writing this getter code).
The much easier solution would be to use the Session. Session values are stored server-side and are user specific. The only thing that get's sent client side is the session key, and if you are using .Net authentication, this is likely already getting sent.
Check this source:
How to get a public variable (in a Module) to NOT share value between users

Aspx, global instance of class, possible bug in code structure

I am tracking down a bug in some old aspx code. The problem is that one some very rare occations (1/10.000 pageviews or so) two users are mixed up, ie. user A sees user B data.
Here is how the code is structured: We have a user class which is defined in a module like this:
Public Module MyGlobals
Public myUser As CMyUser
End Module
On the loginpage, we validate the username/password and if valid then the coorosponding userid is loaded from db, and we do:
FormsAuthentication.SetAuthCookie(userid, False)
Then we redirect to the secure area. In the secure areas MasterPage, on event Page_Init, we then have:
If Context.User.Identity.IsAuthenticated then
' Initialize the user class (user data is loaded)
MyGlobals.myUser = New CMyUser(Context.User.Identity.Name)
Else
' Redirect to loginpage
End If
Hereafter, is it safe to access the
MyGlobals.myUser
instance from every page which has the secure masterpage as masterpage, or could there be issues with this structure?
A VB.Net Module is like a static class with a private constructor and only static fields in C#.
That means, all variables declared in a module are shared across all threads. Hence every request(User) that's using this module will overwrite the old value.
I would strongly recommend to use Session to store user-sensitive data.
But i'm not sure why you want to store the Username because it's already stored when using FormsAuthentication(as you've shown yourself above).
If you really need this wrapper, you could easily achieve it even in a static context via HttpContext.Current.Session:
Module MyGlobals
Public Property myUser As CMyUser
Get
If HttpContext.Current.Session("CurrentUser") Is Nothing Then
Return Nothing
Else
Return DirectCast(HttpContext.Current.Session("CurrentUser"), CMyUser)
End If
End Get
Set(ByVal value As CMyUser)
HttpContext.Current.Session("CurrentUser") = value
End Set
End Property
End Module

ASP.NET - protected variable

If I use a protected variable, does the variable exist for the whole web application or does it get removed when the user move to other page by get or post? I do know that it is not accessible in other pages unless I use static variable, but I am curious as to if it exists for the whole application. Please let me know!
when you move to other page and return, a new instance of your page class will be created and so all non static variables will be reset.
The value will be valid in a one request process life time (starts with request start and ends with request end)
making a variable protected, just means that this variable is access-able in inherited class. for example in asp.net you can use it in inherited class like inside your markup (because it inherits code behind class)
this is the meaning of protected variable
if you want to keep a value saved between pages you can use one of these items depending on your requirement :
Cookie
Query String
Session States
Application States
Cache
and ViewState keeps state variable between postback in a same page or control while it is not redirected to another page.
protected keyword does not determine how long a variable exists nor does it determine whether it will be available in the next post back.
What you are probably looking for is state management.
Take a look at this webpage to see how you can maintain state between post backs, different pages etc.
Also take a look at this page to determine which state management feature to use in which situation.
In general, "page" variables only live through the duration of the request. If your variable is static, there will only be one instance of the variable for all the requests until the app domain unloads.
If your variable is private or protected, no other classes will have access to it.
Your question, however, seems a little strange. What's your concern?

Need to store a static value for the duration of a request. How?

I have an ASP.NET MVC application. I have come to an idea of generating autoincremented values to be used as unique element ids. The question is, how can I have and work with a global variable which should be there for the duration of a request (page generation) but no longer?
I thought of using TempData for this shared variable and then just delete this key when the page is done. But then, where in code to purge this TempData key? Obviously it has to be some very last piece of code where the page has been rendered already.
Any input is highly appreciated.
EDIT: I have a number of HTML helpers that can be called from various views and partial views, so declaring a variable on a page and passing it to each helper is obviously not a good solution. I wish to just use the helpers and know they all are getting unique ids behind the scenes.
Okay, I have googled a little bit and found a solution on ASP.NET forums.
http://forums.asp.net/t/1401685.aspx
Obviously, I can use the HttpContext.Current.Items collection to have my little static variable for the duration of a request.
If all you need is to store a number, the resources that would take to manage its lifestyle would take a lot more than just having a one static integer and always reusing it.
Do not bother deleting the key after each request. Just use a static (I think this is shared in visual basic) integer, use and increment it every time you need a unique value. Also take its mod with a ridiculously high number each time to make sure it will not be reused in a single request and it will never overflow.
Why don't you define your integer variable at the top of the page view file?
Use it throughout the view rendering execution and at the end of it you can easily leave it as is. You don't have to explicitly destroy anything. Your variables live for the duration of request only. IIS is stateless service (if you subtract Session, Cache and Application variables) so it doesn't really remember anything explicitly.
I would imagine you could use the Application_BeginRequest and Application_EndRequest methods in global.asax.cs; Note I can't double check the method names currently, but I think they are close.
You could create a member variable in your controller which would be regenerated for each request:
public class ItemController : Controller
{
private int _UniqueID = 0;
public ActionResult Index()
{
foreach (var item in items)
{
item.UniqueID = _UniqueID++;
}
// etc...
}

Resources