We are thinking about using the enterprise library caching framework in our asp.net 3.5 application to store small datatables of our most hit products.
Is there a way to write an outside process, like a console application, to remove these datatables, if needed? For example, a client can come in and update the data for a product, which will make the datatable stored in cache out of date. When this happens, I would like an outside application go into the cache and remove or even update the cache with the new data.
I can think of two approaches to remove cache items from out of process.
The first is to use a FileDependency when adding items to your cache. When you want to expire a cache item then modify the file.
DataTable books = GetTopBooks();
ICacheManager cacheManager = CacheFactory.GetCacheManager();
cacheManager.Add("books", books, CacheItemPriority.NotRemovable, new BookCacheRefreshAction(),
new FileDependency("books.xml"));
Then an external process can expire your DataTable by modifying the appropriate file on disk (in this case books.xml). You can also configure an ICacheItemRefreshAction to refresh the cache (e.g. from the database) when it is expired.
If for some reason the file based approach is not sufficient then the second approach would be to create a custom interface that could be invoked by the out of process application. e.g. create a web service which will remove items from the cache and potentially refresh the cache item.
Related
I have implemented a disk based Custom Cache Provider which works fine except from one problem. When i use the provider in aspx Pages the generated key is of the from "a2/../../default.aspx" which is fine. When I use the same provider in User Controls the generated key is of the form "lfffffff40e80...." and this is fine till the application pool recycles. Then for the same user control a similar key is generated (but not the same) meaning that the cashed user control cannot be accessed with the new key and a new entry is generated in the Disk Cache for the same user control.
Is this the way Custom Cache Providers work with User Controls? How can I generate the same key for the User Control when the application pool recycles?
Thank you in advance!
I don't believe that there is a way to control how cache keys are created - for a user control, its an involved process that included combining multiple hash codes and/or including stack trace hash etc. Because invariably, hash code of some factory object is used in the computation of cache key, you will get a different key in fresh app-domain (after app pool recycle) because hash code of object would differ.
As such I don't see any major issue even if new cached copy is created after app pool recycle - because you need to tune that time as well as (you cannot have tow frequent app pool recycles because application start code will need to be run after each recycle).
BTW, you can have a Shared copy of cache for multiple instances of user controls on different pages.
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.
I have an Asp.Net MVC 3 site. The following is the call stack
Web page/jQuery: $(document).Ready(.... Ajax calls... render the page...)
=> MVC Control methods
=> Entity framework 4.1
=> mapped store procedures (SQL Server 2008)
Question:
Where is the best place to implement cache?
How to let the page know that the underline SQL server tables have been updated?
Not sure about the "best" way to do it but one way to do it would be to have an MVC controller action which calls to the db to check and see if the data has been updated. (You can do it by time-stamp.)
The resulting function will then retreive the data from cache or from the server.
http://davidwalsh.name/cache-ajax
The only interesting thing to note however; is that you should make sure that the call to first find out if you can use cached content is faster than not caching content at all.
Try to add caching as close to the source as possible. This way more of your app could gain benefits from the improved speed.
If you control the code that is modifying the underlying tables you could invalidate the cache from there. You could also place a short timeout on your cache. If its a heavily used query caching it only a second could increase speed many fold. Make sure to test the performance gain so that you can tweak timeouts.
For question #2, you may want to look into Query Notifications. Setting everything up is a bit complicated, but that will enable you to do things such as caching until the data in your database has been updated.
One way is to cache rendered views some specified time.
Let's say that you have page that is not updated often. So instead of hitting database on every visit you can store rendered view in cache. This is achieved using OutputCaching - http://www.asp.net/mvc/tutorials/improving-performance-with-output-caching-cs.
Another way could be to store data.
Here again You can cache it for some specified time. In ASP.NET (MVC) it can be achieved using Cache object - http://msdn.microsoft.com/en-us/library/aa478965.aspx.
Cache object let's you specify how long data is to be cached when You put it in cache. For example:
Cache.Insert("key",
myTimeSensitiveData,
null,
DateTime.Now.AddMinutes(1),
TimeSpan.Zero);
Or you can cache until it is 'invalidated'.
Say you have GetCustomers and UpdateCustomer methods. In GetCustomers you check if data is in Cache. If not you hit the database, put it in cache and return. It is in cache until someone calls UpdateCustomer. In that method you write modified customer to database and invalidate data stored in Cache. You can just remove it. That way when GetCustomers is called again it will hit the database and populate Cache again. But remember that Cache has global scope and is accessible for many threads at the same time. You will need some synchronization code around access to Cache.
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.
I'm using the SqlProfileProvider on one of my websites and in one page I need to fetch the whole list of profiles (it is an intranet).
The method that I use is the ProfileManager.GetAllProfiles(). The problem is that its performance is really bad and it slows down the website considerably.
Therefore, I was thinking of caching the result of the method call in the Application scope as a DataTable (so I could filter/search on it as well).
My problem is that I have several servers running this webapp, and I would like the cache to be in sync. I started using memcached but I was put off by some problems (hence going back to thinking in caching in the Application scope).
So, here are my questions:
Would it be efficient to store the DataTable containing the profiles in the Application object? Or, is it possible to store objects in the Cache and have them available for all clients/browsers?
Is it possible to add a (SQL) Cache Depedency to this cache?
You could cache portions of the web page which will depend on the list of profiles by putting them in a user control and marking it as cacheable. SqlCacheDependency cache policy expiration could be defined as well. As for the cache location, every web server in the farm will have it's own version in memory but using cache expiration will make sure that this version is not out of sync with the data in the DB.
Page or fragment caching is the most effective caching technique because contrary to caching your model (a DataTable or whatever) you don't pay the price of HTML rendering.