A class in my ASP.NET website needs to access a database table multiple times for every request. The database table should rarely change, if ever. Maybe a couple times a month.
In the static constructor of the class, the table is fetched from the DB and cached in a static local variable. Whenever the class needs to access the table, then, it just uses the cached, static version.
My question concerns the lifespan of this cached, static version of the table.
I understand that it's fetched the first time the class is instantiated or a static method in the class is used. But how often does this occur on the web server? What if the table changes and we want to reset this static version of the table?
Basically, I'm wondering, is this table fetched once and then only refetched each time I restart IIS? What, with regard to the site and IIS, will trigger this static class to reset, causing the static table to be refetched?
Rather than a static variable on a class, why not make add this to the 'Application' collection? It's lifetime is well understood (the life of the website) and can easily be recycled by touching web.config. Populate it in your Application_Start method of global.asax.
I'd recommend using the ASP.NET cache itself, rather than having variables for each particular cache item (a single table right now, but I'm sure there's room for growth); this way you can specify expiration, among other things, such as dependencies.
You can get information on the cache here, and more specifically, using the cache here.
To answer your question about the life-cycle, or expectancy of a local variable, see this link, which should do a better job of explaining the innards than I.
Basically, I'm wondering, is this
table fetched once and then only
refetched each time I restart IIS?
Yes, you've got that spot on. Essentially, restarting IIS will cause your static variable to be "refreshed". If you use a static variable to store this kind of thing (which may not be the best solution, but I'm trying to directly answer your question without getting sidetracked), I would advise you build some code into your data layer so that your static variable is updated each time the database table in question is written to. This will mean that you dont need to bounce the server each time you update it.
Its also worth remembering that static variables are shared across all client requests, this can often lead to some unpredictable multi-threading errors.
Related
I'm using VS2010,C# to develop my ASP.NET web app, sometimes I need to declare public or even public static variable at start of my codebehind files, so that I can access them globally in the file and also they preserve their value between postbacks, everything works fine on my local server (as I'm the only person who runs the code). But I don't know exactly what happens when this page (and therefor its codebehind) are run by several web site visitors at the same time, I want my program to run the same for all users, but I think in this way something will cause problems, I can remember from my previous ASP.NET experience that using variable (public or public static) in codebehind can cause misunderstanding for different users of web site, for instance:
user A runs program, (public static int) my_int that had the value of -1 at startup has taken value of 100, and at this time user B runs the same page, so my_int is 100 and it will cause problems, also suppose that user A leaves the page while my_int has value of 100, then user B will visit the page my_int would be initially 100 (while that should be -1) so I think unexpected behaviors would occur
is it right? will this happen at all? if so, how can I prevent it? should I use session instead of variables? how can I have a better understanding about the whole situation
thanks friends
A simple rule - you need to choose storage as per the scope of data being stored. And for any mutable (read/write) shared state, you have worry about concurrent access (thread safety). For example, if a variable is a static then it would available through-out application (correctly speaking app-domain) but it also means you have ensure thread-safety while reading/writing the variable. Here are few tips
For per request scope, use local variables. No need for thread-safety (as only request thread would access it).
For per page scope (over repeated post-backs), use view-state. No need for thread-safety (as only request thread would access it).
For per user scope, use session state. A good thing about session state is that you don't have to worry about thread-safety (ASP.NET take care of that).
For application wide scope (strictly speaking app-domain wide scope), use application state or static variables. Application State offers lock/unlock API for thread-safety while for static variables, you have put your own locking mechanism. Static variables are good bet for application wide read-only data i.e. you initialize them at the start of application and then use the information whenever needed w/o locking because there are no writes.
For any scope larger than this, use database (or any other persistent data store). For database, transactions are used to ensure consistency.
I have two separate web applications:
The "admin" application where data is created and updated
The "public" application where data is displayed.
The information displayed on the "public" changes infrequently, so I want to cache it.
What I'm looking for is the "simplest possible thing" to update the cache on the public site when a change is made in the admin site.
To throw in some complexity, the application is running on Windows Azure. This rules out file and sql cache dependencies (at least the built in ones).
I am running both applications on a single web role instance.
I've considered using Memcached for this purpose. but since I'm not really after a distributed cache and that the performance is not as good as using a memory cache (System.Runtime.Caching) I want to try and avoid this.
I've also considered using NServiceBus (or the Azure equivalent) but again, this seems overkill just to send a notification to clear the cache.
What I'm thinking (maybe a little hacky, but simple):
Have a controller action on the public site that clears the in memory cache. I'm not bothered about clearing specific cached items, the data doesn't change enough for me to worry about that. When the "admin" application makes a cache, we make a httpwebrequest to the clear cache action on the public site.
Since the database is the only shared resource between the two applications, just adding a table with the datetime of the last update. The public site will make a query on every request and compare the database last update datetime to one that we will hold in memory. If it doesn't match then we clear the cache.
Any other recommendations or problems with the above options? The key thing here is simple and high performance.
1., where you have a controller action to clear the cache, won't work if you have more than one instance; otherwise, if you know you have one and only one instance, it should work just fine.
2., where you have a table that stores the last update time, would work fine for multiple instances but incurs the cost of a SQL database query per request -- and for a heavily loaded site this can be an issue.
Probably fastest and simplest is to use option 2 but store the last update time in table storage rather than a SQL database. Reads to table storage are very fast -- under the covers it's a simple HTTP GET.
Having a public controller that you can call to tell the site to clear its cache will work as long as you only have one instance of the main site. As soon as you add a second instance, as calls go through the load balancer, your one call will only go to one instance.
If you're not concerned about how soon the update makes it from the admin site to the main site, the best performing and easiest (but not the cheapest) solution is to use the Azure AppFabric Cache and then configure it to use a a local (in memory) cache with a short-ish time out (say 10 minutes).
The first time your client tries to access an item this would be what happens
Look for the item in local cache
It's not there, so look for the item in the distributed cache
It's not there either so load the item from persistent storage
Add the item to the cache with a long-ish time to live (48 hours is the default I think)
Return the item
Steps 1 and 2 are taken care of for you by the library, the other bits you need to write. Any subsequent calls in the next X minutes will return the item from the in memory cache. After X minutes it falls out of the local cache. The next call loads it from the distributed cache back into the local cache and you can carry on.
All your admin app needs to do is update the database and then remove the item from the distributed cache. The next time the item falls out of the local cache on the client, it will simply reload the data from the database.
If you like this idea but don't want the expense of using the caching service, you could do something very similar with your database idea. Keep the cached data in a static variable and just check for updates every x minutes rather than with every request.
In the end I used Azure Blobs as cache dependencies. I created a file change monitor to poll for changes to the files (full details at http://ben.onfabrik.com/posts/monitoring-files-in-azure-blob-storage).
When a change is made in the admin application I update the blob. When the file change monitor detects the change we clear the local cache.
In Web application, I am using static variable, when more than one user accessing the same page where static variables declare, it could be conflict variables?, for example i am storing the session value in static variable, if the two employee are accessing the same page at a time it could wrong process na?.
Yes, there can be conflicts. You can end up with a lot of unexpected behaviors. Avoid them as you may have concurrency issues.
Yes conflicts will likely occur, the state of the variable is shared across the entire app domain.
A static variable has only one value for each appDomain. It means the same will be shared by all the request in the application . This may lead to conflicts . So never user static variable until and unless you are very sure about the behavior , use session instead.
Yes, that's why you should be VERY careful when you use static variables in a web app. You will run in concurrency issues as more than one thread servicing a request can modify the value of the variable.Static Variables Scope is Application Level. If you store some thing in it, then its a wrong thing. If one user saves the data, Same time another user accessed the same page then he will also get the same data. So try to store the values in Sessions.
While this works in single-user environment, What happens in a multi-user environment, if there are 2 users simultaneously logged in from two computers, User 1 sets the value as 200, then User 2 sets the value as 400. after that user 1 invokes the Get Value button. What will he see as the value?
I'm trying to create a sort of global settings for a website and store this data on the database, however I keep thinking that may not be very efficient as these settings will have to be read on every request.
The type of settings like 'how many records to show per page', enable/disable things, I plan to store this on the database but don't want the overhead of having to call the database on every request to get the settings, specially when they don't change. Surely this is done all the time on CMS's, how do you think it should be done. I am thinking SqlCacheDependency but never set that up. Is there another way?
Also on the cards is the possibility to store those settings on web.config and create a GUI for it, the problem is that the administration of the site runs on it's own namespace and has it's own web.config, so the question here is if it's possible to manipulate a web.config outside the application namespace.
Thanks guys.
I would suggest to you to read the values from the DB in the Application_Start and store these values in the Application object. In this way you will not need to go to the DB to read the values every time. It will only read and store values once when the application starts.
void Application_Start(object sender, EventArgs e)
{
Application["name"] = ""; Value from DB
......................
......................
}
Note: It is not recommend to manipulate values in the web.config using UI, because once a user tries to modify any value from the UI, that changes the value in the web.config, all your User session will be terminated.
Another Note: Every time you change the information and update your DB, you will need to update the Application level object as well.
First, I wouldn't start worrying about counting database calls until you have an idea that your database calls are actually hurting performance. Modern databases are quick, especially for well-designed queries for scalar values. Lots of popular packages read config on every request and they seem to scale pretty well.
As for updating these values, you can pretty easily update a web.config file from another app presuming you've got the right permissions -- this will definitely require Full Trust which leaves out most hosting scenarios. Thing to remember is that, while VS treats the file special, it is just an XML file so the normal tricks for updating an XML file will apply. Because you are doing this from a different application, it will work. But Muhammad's warning about dumping user sessions would apply to the "victim" of the update. Which might be OK depending on what you are changing.
In order to improve speed of chat application, I am remembering last message id in static variable (actually, Dictionary).
Howeever, it seems that every thread has own copy, because users do not get updated on production (single server environment).
private static Dictionary<long, MemoryChatRoom> _chatRooms = new Dictionary<long, MemoryChatRoom>();
No treadstaticattribute used...
What is fast way to share few ints across all application processes?
update
I know that web must be stateless. However, for every rule there is an exception. Currently all data stroed in ms sql, and in this particular case some piece of shared memory wil increase performance dramatically and allow to avoid sql requests for nothing.
I did not used static for years, so I even missed moment when it started to be multiple instances in same application.
So, question is what is simplest way to share memory objects between processes? For now, my workaround is remoting, but there is a lot of extra code and I am not 100% sure in stability of this approach.
I'm assuming you're new to web programming. One of the key differences in a web application to a regular console or Windows forms application is that it is stateless. This means that every page request is basically initialised from scratch. You're using the database to maintain state, but as you're discovering this is fairly slow. Fortunately you have other options.
If you want to remember something frequently accessed on a per-user basis (say, their username) then you could use session. I recommend reading up on session state here. Be careful, however, not to abuse the session object -- since each user has his or her own copy of session, it can easily use a lot of RAM and cause you more performance problems than your database ever was.
If you want to cache information that's relevant across all users of your apps, ASP.NET provides a framework for data caching. The simplest way to use this is like a dictionary, eg:
Cache["item"] = "Some cached data";
I recommend reading in detail about the various options for caching in ASP.NET here.
Overall, though, I recommend you do NOT bother with caching until you are more comfortable with web programming. As with any type of globally shared data, it can cause unpredictable issues which are difficult to diagnosed if misused.
So far, there is no easy way to comminucate between processes. (And maybe this is good based on isolation, scaling). For example, this is mentioned explicitely here: ASP.Net static objects
When you really need web application/service to remember some state in memory, and NOT IN DATABASE you have following options:
You can Max Processes count = 1. Require to move this piece of code to seperate web application. In case you make it separate subdomain you will have Cross Site Scripting issues when accesing this from JS.
Remoting/WCF - You can host critical data in remoting applcation, and access it from web application.
Store data in every process and syncronize changes via memcached. Memcached doesn't have actual data, because it took long tim eto transfer it. Only last changed date per each collection.
With #3 I am able to achieve more than 100 pages per second from single server.