So yesterday I applied the windows update to install IE9, and discovered that my ajax calls to update a grid stopped working. Chrome & Firefox gave the expected results (i.e. my grid showed changes), but in IE9 seemed to display whatever the first load was.
IE9, it turns out, makes 2 different kinds of requests, conditional and unconditional requests (for more checkout http://blogs.msdn.com/b/ie/archive/2010/07/14/caching-improvements-in-internet-explorer-9.aspx). Unconditional requests occur when the browser doesn’t have a cached copy, and so the browser makes a new request to the server, and using details in the response header, determines how to cache the document. Conditional requests occur when a cached copy is available. It first evaluates whether the document is still fresh, and if so, serves the cached copy of the document.
Many people seem to counter this by passing a date time stamp string as a URL parameter, making each request unique, and thus the browser is always making an unconditional request, and always getting a new copy. This just seems dirty, as you’re passing up a parameter thats not required. It’s also quite error prone, as if you forget to add the parameter you’ll run into caching problems that often aren’t easy to spot.
Luckily ASP.NET MVC makes it relatively straight forward to control the “Cache-Control” section of the HTTP 200 response header field, which is what IE9 uses to determine its caching strategy.
A normal MVC response header looks something like this:
By default, MVC responses set the Cache-Control setting to private, which the HTTP specification (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1) describes as:
Indicates that all or part of the response message is intended for a single user and MUST NOT be cached by a shared cache. This allows an origin server to state that the specified parts of theresponse are intended for only one user and are not a valid response for requests by other users. A private (non-shared) cache MAY cache the response.
The result of this is that IE9 will cache the page in the current user’s private store, and will conditionally serve the cached copy until it reaches it’s default expiry time.
To change this setting, we simply add an attribute to our MVC controller.
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")] public class CacheTestController : Controller
We’ve set “no-store” to true (meaning don’t cache), and the “duration” to 0 (so it immediately expires). This will ensure that every subsequent request for this page will result in a new trip to the server, and a fresh copy being served.
A much neater solution, that requires no changes to our URL’s, or the parameters passed to it.
I did a fair bit of searching on the internet and this is by far the simplest and cleanest solution.
Instead of using it on the controller I added it to a PartialViewResult and it worked great!!!
Thank’s a lot!!
Thank you. This killed me, until I found your post.
Amazing solution, thank God that I found your blog.
This one had me completely baffled and your fix has saved the day!
Nice work my friend. Fixed the exact issue I had and it’s a solid solution.
Thanks so much for this.
You sir are a genius…I was not looking forward to adding a random query string parameter to all my URLs. This solution is clean and elegant.
thank sir your super…………………………
this post is good
In any browser this problem. I had insert attributes.. but – nothing.. ie9. chrome, ff..
any ideas?
Thanks a bunch, Saved me a lot of tinkering
I don’t know how many ppl actually tried this but you cannot set the Duration = 0. It will throw an error. I had a similar problem and all I did was set the cache property in the .ajaxSetup({ cache: false; }); and this cleared up my IE 9 issue.
Classy Example,Gave me huge relief
Thank you, helped me to solve the same issue.
I just did this and it seems to work on all Ajax Request
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (Request.IsAjaxRequest())
{
Response.CacheControl = “no-cache”;
Response.Cache.SetETag(Guid.NewGuid().ToString());
}
base.OnActionExecuted(filterContext);
}
Thanks for some other fantastic post. Where else may anybody get that
kind of info in such an ideal means of writing?
I have a presentation subsequent week, and I am on the search for such information.