Are VB.NET shared properties a good way to store global variables?

I am currently using the VB.NET code shown below to save various global variables for each visitor to my ASP.NET 3.5 website. However, some of these globals seem to be losing their values part way through a session (they are set when the user logs on). My
first thought is that there is a bug in my code (and I'm still looking for such a bug) but I was wondering if there is any other cause for this behaviour - or to put it another way, are there good reasons for using another method such as session state for
storing global variables?

David

===========================================

Public Class MyGlobals
Public Shared CurrEntrantID As Integer
Public Shared nonUK As Boolean
Public Shared CurrEmail As String
Public Shared CurrTotCost As Double
Public Shared CurrPaymentID As Integer
Public Shared MostRecentIPNPost As String
Public Shared ClassA As Boolean
Public Shared ClassB As Boolean
Public Shared ClassC As Boolean
Public Shared ClassD As Boolean
Public Shared ClassE As Boolean
Public Shared ClassF As Boolean
Public Shared C1Changed As Boolean
Public Shared C2Changed As Boolean
Public Shared C3Changed As Boolean
Public Shared C4Changed As Boolean
Public Shared D1Changed As Boolean
Public Shared D2Changed As Boolean
Public Shared D3Changed As Boolean
Public Shared D4Changed As Boolean
Public Shared E1Changed As Boolean
Public Shared E2Changed As Boolean
Public Shared E3Changed As Boolean
Public Shared E4Changed As Boolean
End Class

Re: Are VB.NET shared properties a good way to store global variables?

First, Shared variables are not per-user or per-session. They are global (and shared) through the entire app domain. So they are not a good way to store any type of session information

Second, their lifetime is the lifetime of the app domain. So, they are re-initialized when the app domain recycles (which does occur in ASP.NET applications as a part of the health monitoring). The default ASP.NET Session model (in proc) has this same limitation.

I tend to encourage folks to look for alternatives to using Sessions. While they are better than they were in the ASP Classic world, their are still some scalability limitations and implications to using sessions, especially if you aren't careful about what
you are doing. At least some of the items above look like they would be persistant properties per-user ... in that case, it's really ideal to use the ASP.NET Profile object for them. The rest ... ClassA, etc ... well, I'm not sure what they are. If they are
transitive (and don't persist between visits) and aren't sensitive, you could put them in cookies rather than in session. If they do persist between visits, look at the profile again.

Re: Are VB.NET shared properties a good way to store global variables?

JSawyer

Shared variables are not per-user or per-session. They are global (and shared) through the entire app domain. So they are not a good way to store any type of session information....

Hi Jay,
Aaaargh! Thanks for pointing out that huge mistake on my part. Luckily I've not yet gone live with this app. Testing by other people so far has all been done one at a time and thus has not highlighted this error.

Only the first 3 items on my list are persistent properties per user. They are referenced by several pages on my site and I only put them into shared variables to save repeated database calls. With the exception of the system-assigned EntrantID, these items
and all other personal user information is gathered via a form on my site and stored in one of my SQL Server tables (rightly or wrongly, I chose not to use the ASP.NET Profile object for this).

None of the other items on the list (apart from MostRecentIPNPost) need to persist between visits, though all are user-specific. What are the pros and cons of using cookies versus sessions for such transient data?

Re: Are VB.NET shared properties a good way to store global variables?

haggis999

Aaaargh! Thanks for pointing out that huge mistake on my part. Luckily I've not yet gone live with this app. Testing by other people so far has all been done one at a time and thus has not highlighted this error.

Glad to help. [:)] And I'm really glad that you got this before rolling to production!

haggis999

What are the pros and cons of using cookies versus sessions for such transient data?

Cookies Pros: Well, since they are passed by the browser, they are definitely per user. They will also pass across servers, should you ever scale out to a farm environment. They also persist between app domain recycles. Cookies also do not
consume very much server resources - only in the processing of the request.

Cookies Cons: The user can turn off cookies, though this could very well break other aspects of the application that relies on cookies. By default, sessions require cookies, though this can be put into the query string. Cookies are also
to be considered user input and can be tampered with by the client, so you will need to do validation on them. As an alternative, you can also encrypt them. Depending on what is in the cookies, they can also significantly increase request and response size,
increasing the bandwidth used by the application.

Session Pros: Server-side, so you don't have to worry as much with tampering. They are also inherently per-user and do expire (the default is after 20 minutes of inactivity).

Session Cons: Sessions, however, unless you are careful and use the SessionState="ReadOnly" attribute with the page directive, can lead to serialization of requests (that is, one request is processed at a time) to prevent concurrent writes
to the session variables. Sessions also consume server resources and, depending on what you put in the session, this can be quite expensive. The default session behavior (InProc) will lose sessions between app domain recycles and won't be shared across servers
in a farm, though this can be mitigated by using the State Server or Sql Server for your sessions. Also, sessions will live longer than the active client connection - as mentioned above, the timeout is 20 minutes - since there is no persistent connection from
the client to the server with HTTP (the nature of the protocol). As a result, they will continue to consume server resources, even if they are no longer required. This can be mitigated by using Session.End(), but there is no guarantee that the client would
necessarily hit the code running this. Alternatively, they can also expire if the user spends too much time on a single page, though you can increase the session timeout (which also has consequences ... see above).

Properties that are persistant per user are typically best stored as a part of the user profile. This provides strong typing of the profile properties (sessions are not strongly typed; the return System.Object, which needs to be cast to your specific type),
handles the persistance for you and are loaded on demand. Also, once loaded, they won't go back to the database. On the flip side, this behavior can be problematic if you are in a server farm environment. And yes, profiles can be used with anonymous users;
this requires the allowAnonymous attribute on the properties that you wish to use with anonymous users. And, of course, Profiles are built into ASP.NET 2.0, making life easier. You can also group profile properties for a better model.

Transitive properties can be stored in the Profile, but (IIRC) will be persisted anyway, so the won't really be transitive. You can use the ViewState for transitive stuff as well, but that can be lost if the user navigates to a different page. If you use
Cross-Page postbacks, you can move it between pages, but that won't help with old-fashoined hyperlinks or if the user just types a new URL in the address bar. ViewState is, therefore, best used for properties/data that is specific to a page and a user.

I think that about covers it. Let me know if you have any further questions.

Re: Are VB.NET shared properties a good way to store global variables?

Jay,
A few minutes after your extremely helpful reply arrived yesterday afternoon, a highways maintenance contractor cut through our telephone cable! I've been cut off from cyberspace for 24 hours, which is very frustrating when you have a website to design. Anyway,
thanks for all the very useful advice for state management - a topic that gets a whole chapter in one of my more advanced ASP.NET textbooks, but which I have only just started to read (I'm hoping that this rather complex topic will become clearer once I complete
it).

Some further questions:

<div mce_keep="true">Is there any way to tell if a user has turned off cookies, and thus enable me to give the user a warning that the site will not work unless he turns them back on? If not, then cookies seem a bit risky for vital parts of your application
logic (and the variables under discussion are all vital).</div>

<div mce_keep="true">If I use session state then I would need to deal with the expiration issue. I've no way of knowing how long the user may stay on a page that needs the session variables. Is the solution to have my own timer that will divert the user
away from such a page just before the predefined session expiration? Alternatively, can I reinitialise the session variables just before they expire?</div>

<div mce_keep="true">Being fairly new to ASP.NET (this is my first app), I've never heard of app domain recycling and this topic is not mentioned in the index of any of my ASP.NET textbooks. I found a couple of articles online a few minutes ago on this
subject but they were way over my head. Does an app domain recycle trigger an event that I could use to refresh the session variables?</div>

<div mce_keep="true">You are obviously keen to recommend the use of Profile for user-persistent data that is referred to frequently in various pages. Does Profile offer any benefit over simply retrieving such data from one of my own SQL Server tables (which
I think will get cached automatically)?</div>

BTW, all of my variables are either integers or fairly short strings. There is no likelihood of my site ever being hosted in a server farm environment - its purpose is to host an annual international photographic competition that usually attracts less than
1000 entrants, so we're not quite in the same league as Amazon and eBay!

Re: Are VB.NET shared properties a good way to store global variables?

2) Again, you could do this with javascript and force a page refresh or have some sort of user prompt. There is no way to do this server-side - the nature of HTTP is that it is connectionless ... so the browser gets the response and then there is no persistant
connection to the server.

3) The app domain will recycle based on a number of factors and how the server is configured. They will typically recycle after a certain amount of non-activity or a certain amount of memory is consumed by the app domain (app domain is like the process
in .net). Also, ASP.NET can also be configured to recycle the app domain after a period of time regardless of non-activity. An app domain can also recycle after too many exceptions or if you change any of the code/configuration files on the site. When the
app domain reycles, all of your state is lost and there's really no way to transfer it to the new app domain on the server.

4) Yes, I am keen on the Profile. Why recreate the wheel when it's already there? Even if it's not necessarily referenced frequently, if it's persistant and per-user, the Profile offers a very easy way to handle it. If you are using your own Sql tables,
the query plan would be cached on the Sql Server, but not in the process space of the web site unless you write the code to cache it. Now, that said, the default Profile provide does have its own schema that isn't very transparent. If you have tables
for the profiles, that's OK ... you can use the Table Profile Provider (http://www.asp.net/downloads/sandbox/table-profile-provider-samples/).

I do need to point out that the issues with app domain recycling and sessions are relevant to the default InProc Session state. You can avoid these by using one of the out-of-process session state providers - either the State Server or the Sql Server State
providers.

Now ... integers and fairly short strings do go well into cookies ... and cookies are an easy way to get around some of the server-side state management issues that you may run in to. The app domain recycling can be particularly problematic if you are in
a hosted environment where all of the hosted applications are running in the same IIS application pool (which also recycles). And, not to belabor the point, HTTP itself is stateless - things like Sessions are basically a method to get around this fact, but
they don't change it and there are some considerations when contemplating using them because of that.

Re: Are VB.NET shared properties a good way to store global variables?

JSawyer

The app domain recycling can be particularly problematic if you are in a hosted environment where all of the hosted applications are running in the same IIS application pool (which also recycles).

Thanks once again for all the help. Not being too clued up on such matters, I've no idea if my ISP has an IIS application pool ....

BTW, where would I find an explanation of why shared members such as my MyGlobals variables are the same value for all users? I was trying to educate myself on this topic but so far I've failed to find anything that addresses that particular issue.

Re: Are VB.NET shared properties a good way to store global variables?

All IIS hosters have application pools. It's not an option; they are a part of IIS. Some hosters do offer dedicated (as in, non-shared, isolated) application pools. That may be an additional charge - it depends on your hoster.

How safe is it to assume that users have JavaScript enabled? Well, if they don't have JS enabled, they'll have a darn hard time getting much of anything done on the Internet these days. But ... here's one suggestion on how to handle checking ...
http://www.tizag.com/javascriptT/javascript-enable.php.

Re: Are VB.NET shared properties a good way to store global variables?

Ah yes, that rings a bell. I'm in a shared hosting arrangement with my ISP.

Unless I'm going blind, your link ref Shared members makes no mention at all of them being the same value for all users of a website - like every other source I have already consulted. It's a very important point so I'm finding it surprising that I can't
yet find a reference to it. How certain are you that Shared members are not defined per user?

Ref your earlier post, the only totally safe way to use Session state appears to be to use an out-of-process session state provider. However, I get the impression that plenty of developers do not go down that route and therefore have to cope with the expiration
of Session variables. If you do this, what is your normal method of preventing the code on a page failing because a vital Session variable has expired?

Re: Are VB.NET shared properties a good way to store global variables?

Jay,
I withdraw my question about whether Shared members are defined per-user. Firstly, I've just roped in two friends to use my app at the same time as me and lots of strange things started to happen (entirely consistent with Shared members
not being defined per-user). Secondly, I've looked more closely at your blog and realised that you are a Microsoft Developer Evangelist, and should therefore know what you are talking about. Apologies for doubting you!

However, I am still puzzled as to why I have had difficulty in finding any reference to this key point in the online help .....