If you cache pages in a HttpHandler with
_context.Response.Cache.SetCacheability(HttpCacheability.Public);
_context.Response.Cache.SetExpires(DateTime.Now.AddSeconds(180));
is it possible to clear a certain page from the cache?
is it possible to Clear a certain page
from the Cache?
Yes:
HttpResponse.RemoveOutputCacheItem("/pages/default.aspx");
You can also use Cache dependencies to remove pages from the Cache:
this.Response.AddCacheItemDependency("key");
After making that call, if you modify Cache["key"], it will cause the page to be removed from the Cache.
In case it might help, I cover caching in detail in my book: Ultra-Fast ASP.NET.
more simple one...
public static void ClearCache()
{
Cache cache = HttpRuntime.Cache;
IDictionaryEnumerator dictionaryEnumerators = cache.GetEnumerator();
foreach (string key in (IEnumerable<string>) dictionaryEnumerators.Key)
{
cache.Remove(key);
}
}
The following code will remove all keys from the cache:
public void ClearApplicationCache(){
List<string> keys = new List<string>();
// retrieve application Cache enumerator
IDictionaryEnumerator enumerator = Cache.GetEnumerator();
// copy all keys that currently exist in Cache
while (enumerator.MoveNext()){
keys.Add(enumerator.Key.ToString());
}
// delete every key from cache
for (int i = 0; i < keys.Count; i++) {
Cache.Remove(keys[i]);
}
}
Modifying the second loop to check the value of the key before removing it should be trivial.
Hope this helps.
Related
I have been scratching my head for this from last one week, i will really appreciate any help here, so here we go:
I have a website running on Dnn 7.4 and i want to add caching functionality on it. On first attempt it reads from database and on second attempt onwards it should read from cache, the problem is on first attempt it reads as expected, on 2nd attempt it reads from cache also, but then again on 3rd attempt it fetches from database. Here's my simple code:
if (Cache["Something"] != null)
{
Response.Write("Cache" + Cache["Something"]);
}
else
{
Cache["Something"] = "Cool";
Response.Write("Latest" + Cache["Something"]);
}
DataCache implementation:
using DotNetNuke.Common.Utilities;
string dCache = DataCache.GetCache("test") as string;
if (String.IsNullOrEmpty(dCache))
{
DataCache.SetCache("test", "cache content");
Response.Write("From Database: cache content");
}
else
{
Response.Write("From Cache: " + dCache);
}
You do not show what kind of cache you are using and your policies of the cached items. Here a sample on how it might work with a MemoryCache:
ObjectCache cache = MemoryCache.Default;
string something = cache["Something"] as string;
if (something == null){
CacheItemPolicy policy = new CacheItemPolicy();
//Configure your expire policy here
cache.Set("Something", "Cool", policy);
something = "Cool";
}
return something;
Now you only have to configure the policy for the cache item handling.
I suggest to use DataCache from DotNetNuke.Common.Utilities
//Get Cache
string str = DataCache.GetCache("something") as string;
//Remove cache
DataCache.RemoveCache("something");
// Set Cache
DataCache.SetCache("something", "value of something");
I have to create a mechanism to store and read preferences (controls default values and settings) per user. I have a problem related to network traffic, as the database can be accessed over the internet and the application server sometimes is connected to a poor 512Kbps internet connection.
My application can have around 50 simultaneous users and each page/form can have up to 50 items (preferences). The amount of pages is around 80.
So, considering a performance perspective, which should I choose to decrease network traffic? Session or cache?
UPDATE
I've created two sample pages, one using cache and another using session.
Load test
90 users
Stored content
1000 elements
20 characters on each element's value
Here are the results from each test case:
MemoryCache
330,725,246 total bytes allocated
Functions Allocating Most Memory
Name Bytes %
System.Runtime.Caching.MemoryCache.Set(string,object,class System.Runtime.Caching.CacheItemPolicy,string) 34,74
System.Web.UI.Page.ProcessRequest(class System.Web.HttpContext) 18,39
System.String.Concat(string,string) 12,65
System.String.Join(string,string[]) 5,31
System.Collections.Generic.Dictionary`2.Add(!0,!1) 4,42
Source code:
protected void Page_Load(object sender, EventArgs e)
{
outputPanel.Text = String.Join(System.Environment.NewLine, ReadEverything().ToArray());
}
private IEnumerable<String> ReadEverything()
{
for (int i = 0; i < 1000; i++)
{
yield return ReadFromCache(i);
}
}
private string ReadFromCache(int p)
{
String saida = String.Empty;
ObjectCache cache = MemoryCache.Default;
Dictionary<int, string> cachedItems = cache["user" + Session.SessionID] as Dictionary<int, string>;
if (cachedItems == null)
{
cachedItems = new Dictionary<int, string>();
}
if (!cachedItems.TryGetValue(p, out saida))
{
saida = Util.RandomString(20);
cachedItems.Add(p, saida);
CacheItemPolicy policy = new CacheItemPolicy();
policy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(30);
cache.Set("user" + Session.SessionID, cachedItems, policy);
}
return saida;
}
Session
111,625,747 total bytes allocated
Functions Allocating Most Memory
Name Bytes %
System.Web.UI.Page.ProcessRequest(class System.Web.HttpContext) 55,19
System.String.Join(string,string[]) 15,93
System.Collections.Generic.Dictionary`2.Add(!0,!1) 6,00
System.Text.StringBuilder.Append(char) 5,93
System.Linq.Enumerable.ToArray(class System.Collections.Generic.IEnumerable`1) 4,46
Source code:
protected void Page_Load(object sender, EventArgs e)
{
outputPanel.Text = String.Join(System.Environment.NewLine, ReadEverything().ToArray());
}
private IEnumerable<String> ReadEverything()
{
for (int i = 0; i < 1000; i++)
{
yield return ReadFromSession(i);
}
}
private string ReadFromSession(int p)
{
String saida = String.Empty;
Dictionary<int, string> cachedItems = Session["cachedItems"] as Dictionary<int, string>;
if (cachedItems == null)
{
cachedItems = new Dictionary<int, string>();
}
if (!cachedItems.TryGetValue(p, out saida))
{
saida = Util.RandomString(20);
cachedItems.Add(p, saida);
Session["cachedItems"] = cachedItems;
}
return saida;
}
I forgot to mention that I'm creating a solution to work with ASP.Net and WPF projects, however, if the Session is far better than the MemoryCache option, I can have different solutions for each platform.
both are really the same, they are in memory... If you are using DB session and you have a poor connection then you should use cache if present, load from DB if not and then cache.
I would consider the session a cache mechanism, unlike the others it is just specific to a specific browser session. My approach would consider the following questions.
Is this site load balanced? If it is, using the session will force persistent sessions, possibly causing issues if you take down a server.
Is this data user specific? If it is, the session is an easy way to segregate data without lots of key manipulation. It also has the benefit that when a user's session times-out it automatically gets cleaned up. If it isn't, I'd recommending using the MemoryCache feature added .NET 4.0. It supports expiration.
How will this cache become outdated? If user A can modify data cached for user B, you're now serving dirty data with Session cache. This prompt a shared cache mechanism.
Edit: Once these questions have been answered, you should be able to decide what type of cache mechanism is appropriate for your situation. Then you can evaluate that subset for performance.
I have a simple site that I want to enable output caching for, but it uses ASP.NET Web Pages (http://asp.net/web-pages, not Web Forms or MVC). Any guidance?
You can put this at the top of any page you want to cache on the server:
Response.Cache.SetCacheability(HttpCacheability.Server);
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetValidUntilExpires(true);
Response.Cache.VaryByParams.IgnoreParams = true;
Of, if you want to cache all pages in a folder, put the code in a _PageStart file.
More information on MSDN: http://msdn.microsoft.com/en-us/library/system.web.httpresponse.cache.aspx
The following code does everything you need, and has several overloads to fine tune your output cache for a given page:
#{
var seconds = 600; //10min
Response.OutputCache(seconds);
}
Behind the scenes, this is an extension method contained in System.Web.WebPages.dll assembly that do this:
internal static void OutputCache(HttpContextBase httpContext, HttpCachePolicyBase cache, int numberOfSeconds, bool sliding, IEnumerable<string> varyByParams, IEnumerable<string> varyByHeaders, IEnumerable<string> varyByContentEncodings, HttpCacheability cacheability)
{
cache.SetCacheability(cacheability);
cache.SetExpires(httpContext.Timestamp.AddSeconds((double) numberOfSeconds));
cache.SetMaxAge(new TimeSpan(0, 0, numberOfSeconds));
cache.SetValidUntilExpires(true);
cache.SetLastModified(httpContext.Timestamp);
cache.SetSlidingExpiration(sliding);
if (varyByParams != null)
{
foreach (string index in varyByParams)
cache.VaryByParams[index] = true;
}
if (varyByHeaders != null)
{
foreach (string index in varyByHeaders)
cache.VaryByHeaders[index] = true;
}
if (varyByContentEncodings == null)
return;
foreach (string index in varyByContentEncodings)
cache.VaryByContentEncodings[index] = true;
}
I'm developing a web site in which the site manager can change dinamically the MetaTags for the web site in a cms, storing those MetaTags in a MySql database.
In the public master.page, in the Page_Load event, I get those MetaTags from the database
sTitle = get_from_data_base();
using (HtmlMeta mTag = new HtmlMeta())
{
mTag .Name = "Title";
mTag .Content = sTitle;
Page.Header.Controls.Add(mTag);
}
The problem is everytime a page loads, the load event of the master.page is loading from database those MetaTags.
How can I keep in cache or something similar the metatags once they have been loaded so the site doesn't access the database on every request?
How can the site knows when those MetaTags have changed to load them again?
Please, could you provide an example.
Thanks so much.
One of the solutions to do is to load the data once in the global.asax application start event and add the result in application object then in each page you need it, load it from the application object.
When the data is changed in the database, access the application object and update it as well.
If you don't know how to deal with global.asax or application object, i will post code.
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
string sTitle = get_from_data_base();
Application.Add("sTitle", sTitle);
}
public string get_from_data_base()
{
//update this to call the database and get the data
return "Your data";
}
In your pages write the following:
string sTitle = Application["sTitle"].ToString();
using (HtmlMeta mTag = new HtmlMeta())
{
mTag.Name = "Title";
mTag.Content = sTitle;
Page.Header.Controls.Add(mTag);
}
While your manage is updating the metatag append the following line
Application["sTitle"] = "You manager entered string";
Finally, after your answers and reading on the Internet I went for the Cache object instead Application object. I have read is better, so my final aproach for this would be to add this on the global class and access this method from my master.pages
public static MetaTagsDN get_meta_tags()
{
MetaTagsDN oTags;
if (HttpRuntime.Cache["MetaTags"] == null)
{
MetaTagsLN ln = new MetaTagsLN();
oTags = ln.get_metatags();
HttpRuntime.Cache["MetaTags"] = oTags;
}
else
{
oTags = (MetaTagsDN)HttpRuntime.Cache["MetaTags"];
}
return oTags;
}
What do you think?
Thanks for helping me...
I'm using the OutputCache on my webuser control (.ascx)
<%# OutputCache Duration="1000" VaryByParam="none" %>
I would like to retain the cache for next 1000 seconds, but when a specific page on my site is loaded, I would like to remove/flush/refresh the cache. Like, I want to clear the cache when MyPage.aspx is loaded. Can i flush the cache programmetically?
Its only one page being cache so there are no paramatrized versions to flush cache with.
Thanks for your help in advance.
You can use the VaryByCustom parameter for this.
In your user control you would have the following:
<%# OutputCache Duration="1000" VaryByParam="None" VaryByCustom="MyKey" %>
Then you would override the GetVaryByCustomString method in your Global.asax like so:
public override string GetVaryByCustomString(HttpContext context, string arg)
{
if (arg == "MyKey")
{
object o = context.Current.Application["MyGuid"];
if (o == null)
{
o = Guid.NewGuid();
context.Current.Application["MyGuid"] = o;
}
return o.ToString();
}
return base.GetVaryByCustomString(context, arg);
}
Finally in MyPage.aspx you would do this:
Application["MyGuid"] = Guid.NewGuid();
How does this work?
Whenever your control is cached, it is associated with a string (the string returned from the GetVaryByCustomString method when your control's VaryByCustom key is passed into it).
Whenever the control is subsequently used, GetVaryByCustomString is called again. If the returned string matches a cached version of the control, then the cached version is used.
In our case, "MyKey" is passed into GetVaryByCustomString and it returns whatever is stored in Application["MyGuid"].
Whenever MyPage.aspx is called, it changes Application["MyGuid"] to a new random value.
When your control is next used the GetVaryByCustomString method will return the new value, and because there is no cached version of the control associated with that value, the control will be regenerated. (The control will then be cached and associated with the new value, to persist until the next call to MyPage.aspx etc)
There's an overview here.
You can use HttpResponse.RemoveOutputCacheItem or HttpResponse.AddCacheItemDependency to invalidate output cache entries.
It's a bit of a sledgehammer to crack a nut sort of approach but it was the simplest and most effective way to completely clear/flush the cache of an application that I found find.
Simply call:
HttpRuntime.UnloadAppDomain();
This has the same impact as recycling the app pool. Not suitable in every situation but it will definitely get the job done.
By taking inspiration on other post, the following snippet removes successfully every page cached by OutputCache in asp.net by using reflection:
public static void ClearOutputCache()
{
var runtimeType = typeof(HttpRuntime);
var ci = runtimeType.GetProperty(
"CacheInternal",
BindingFlags.NonPublic | BindingFlags.Static);
var cache = ci.GetValue(ci, new object[0]);
var cachesInfo = cache.GetType().GetField(
"_caches",
BindingFlags.NonPublic | BindingFlags.Instance);
var cacheEntries = cachesInfo.GetValue(cache);
var outputCacheEntries = new List<object>();
foreach (Object singleCache in cacheEntries as Array)
{
var singleCacheInfo =
singleCache.GetType().GetField("_entries",
BindingFlags.NonPublic | BindingFlags.Instance);
var entries = singleCacheInfo.GetValue(singleCache);
foreach (DictionaryEntry cacheEntry in entries as Hashtable)
{
var cacheEntryInfo = cacheEntry.Value.GetType().GetField("_value",
BindingFlags.NonPublic | BindingFlags.Instance);
var value = cacheEntryInfo.GetValue(cacheEntry.Value);
if (value.GetType().Name == "CachedRawResponse")
{
var key = (string)cacheEntry.Value.GetType().BaseType.GetField("_key", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(cacheEntry.Value);
key = key.Substring(key.IndexOf("/"));
outputCacheEntries.Add(key);
}
}
}
foreach (string key in outputCacheEntries)
{
HttpResponse.RemoveOutputCacheItem(key);
}
}
Edit: If you have enabled kernel caching on II6+ then you will need to go with Luke's advice and use a VaryByCustom header, as clearing ASP.NET cache will not affect kernel cache.
OutputCache is stored in the ASP.NET Cache, so you can just call Cache.Remove:
List<string> keys = new List<string>();
foreach(string key in HttpRuntime.Cache)
{
keys.Add(key);
}
foreach(string key in keys)
{
Cache.Remove(key);
}
This will, however, remove ALL cache entries, including custom entries added by your code.
Sinсe this answer no longer works, and this answer only clears custom cache items (not the pages/MVC-actions stored in cache), I digged through ASP.NET reference source codes and came up with this:
public static void ClearAllCache()
{
var runtimeType = typeof(System.Web.Caching.Cache);
var ci = runtimeType.GetProperty(
"InternalCache",
BindingFlags.Instance | BindingFlags.NonPublic);
var cache = ci.GetValue(HttpRuntime.Cache) as System.Web.Caching.CacheStoreProvider;
enumerator = cache.GetEnumerator();
while (enumerator.MoveNext())
{
keys.Add(enumerator.Key.ToString());
}
foreach (string key in keys)
{
cache.Remove(key);
}
}
More info in my blog post here
you can add HttpResponse.RemoveOutputCacheItem("/YourCachePageName.aspx"); line of code in the page load event of the page, loading of which you expect the cached page's cache to go off.