.NET MVC What is the best way to disable browser caching? - asp.net-mvc

As far as my research goes, there are several steps in order to make sure that browser caching is disabled. These HTTP headers must be set:
Cache-Control: no-cache, no-store, must-revalidate, proxy-revalidate
Pragma: no-cache
Expires: -1
Last-Modified: -1
I have found out that this can be done in two ways:
Way One: use the web.config file
<add name="Cache-Control" value="no-store, no-cache,
must-revalidate, proxy-revalidate"/>
<add name="Pragma" value="no-cache" />
<add name="Expires" value="-1" />
<add name="Last-Modified" value="-1" />
Way Two: use the meta tags in _Layout.cshtml
<meta http-equiv="Cache-Control" content="no-cache, no-store,
must-revalidate, proxy-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="-1" />
<meta http-equiv="Expires" content="-1" />
My Question: which is the better approach? Or, alternatively, are they equally acceptable? How do these all relate to different platforms? Which browsers would honor what headers?
In addition, please feel free to add anything I've missed, if any.

Okay folks, seems I made a blunt mistake. There is a best way and that is not using meta tags. The only correct way is to use headers.
Why not use meta tags? Because they are guaranteed not to work with
proxies, which do not read (not supposed to read) the HTML body; they
rely on the headers.
When both Cache-Control and Expires are present, Cache-Control takes
precedence. Source here.
Cache-Control general-header field is used to specify directives that
MUST be obeyed by all caching mechanisms along the request/response
chain. Source here.

Related

Reducing the number of HTTP requests for cached resources

I have an ASP.NET MVC 4 application running in IIS 8.5 / Windows 8.1.
I enabled caching for pretty much everything.
I used YSlow plugin for Google Chrome to see the number of HTTP requests for Primed Cache.
I managed to reduce HTTP requests for javascript and css files, but don't know how to do the same for .png and .ico files.
I tried to add this section in web.config under system.webserver
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00" />
<!-- Image types -->
<remove fileExtension=".jpg" />
<mimeMap fileExtension=".jpg" mimeType="image/jpeg" />
<remove fileExtension=".png" />
<mimeMap fileExtension=".png" mimeType="image/png" />
...
But that didn't work.
Any help would be greatly appreciated!
I've increased the cacheControlMaxAge value from 1.00:00:00 to 180.00:00:00 and that did the trick.

ASP.NET MVC 5 an error occurs when calling the *.less in windows Azure

I have a project in "ASP.NET MVC 5" and use "less" for files "bootstrap", use the following libraries:
http://www.nuget.org/packages/BundleTransformer.Core/
http://www.nuget.org/packages/BundleTransformer.Less/
http://www.nuget.org/packages/JavaScriptEngineSwitcher.Core/
http://www.nuget.org/packages/JavaScriptEngineSwitcher.Msie/
http://www.nuget.org/packages/MsieJavaScriptEngine/
in my BundleConfig.css I have this:
BundleTable.EnableOptimizations = false;
bundles.UseCdn = true;
CssTransformer cssTransformer = new CssTransformer();
JsTransformer jsTransformer = new JsTransformer();
NullOrderer nullOrderer = new NullOrderer();
Bundle cssBundle = new CustomStyleBundle("~/bundles/css");
cssBundle.Include("~/Content/bootstrap/bootstrap.less");
cssBundle.Include("~/Content/font-awesome.css");
cssBundle.Include("~/Content/site.less");
cssBundle.Transforms.Add(cssTransformer);
cssBundle.Orderer = nullOrderer;
bundles.Add(cssBundle);
in my environment works fine and if I use IIS works fine, but when I make the publush in "Windows Azure" for "less" files get this error:
HTTP/1.1 500 Internal Server Error
Content-Length: 75
Content-Type: text/html
Server: Microsoft-IIS/8.0
X-Powered-By: ASP.NET
Date: Wed, 21 May 2014 11:56:01 GMT
The page cannot be displayed because an internal server error has occurred.
Only with files less, others file like css o js return rigth
(I think I have another problem that does not display errors but that's another question). Web.config for error:
<system.web>
<customErrors mode="Off">
</customErrors>
edit
configuration for less in web.config like this template
<bundleTransformer xmlns="http://tempuri.org/BundleTransformer.Configuration.xsd">
<less>
<jsEngine name="MsieJsEngine" />
</less>
<core>
<css>
<minifiers>
<add name="NullMinifier" type="BundleTransformer.Core.Minifiers.NullMinifier, BundleTransformer.Core" />
</minifiers>
<translators>
<add name="NullTranslator" type="BundleTransformer.Core.Translators.NullTranslator, BundleTransformer.Core" enabled="false" />
<add name="LessTranslator" type="BundleTransformer.Less.Translators.LessTranslator, BundleTransformer.Less" /></translators>
</css>
<js>
<minifiers>
<add name="NullMinifier" type="BundleTransformer.Core.Minifiers.NullMinifier, BundleTransformer.Core" />
</minifiers>
<translators>
<add name="NullTranslator" type="BundleTransformer.Core.Translators.NullTranslator, BundleTransformer.Core" enabled="false" />
</translators>
</js>
</core>
</bundleTransformer>
<jsEngineSwitcher xmlns="http://tempuri.org/JavaScriptEngineSwitcher.Configuration.xsd">
<core>
<engines>
<add name="MsieJsEngine" type="JavaScriptEngineSwitcher.Msie.MsieJsEngine, JavaScriptEngineSwitcher.Msie" />
</engines>
</core>
</jsEngineSwitcher>
Remove from your code the following line:
cssBundle.Transforms.Add(cssTransformer);
This line is redundant and may cause errors when using the CustomStyleBundle class.
BundleTransformer only works while bundling. In other words, the *.less files are never actually used by the client, but rather, transformed into CSS and then combined and minified before actually being sent down. Requesting the *.less file directly won't work unless IIS has a mime-type to handle it, but even setting that doesn't really help you, because again, IIS is not typically serving this file.

WebHarvest can't find response headers

I'm working with WebHarvest to fetch data from a site that requires logging in.
It's setup like this:
Page 1 = Login page
Page 2 = Login validation page
Page 3 = Statistics page
On page 2 a cookie is set. When monitoring the opening of Page 2 with Firebug I get these headers:
Connection Keep-Alive
Content-Type text/html; charset=UTF-8
Date Tue, 23 Oct 2012 18:25:12 GMT
Keep-Alive timeout=15, max=100
Server Apache/2.0.64 (Win32) JRun/4.0 SVN/1.3.2 DAV/2
Set-Cookie SESSION=hej123;expires=Thu, 16-Oct-2042 18:25:12 GMT;path=/
Transfer-Encoding chunked
When calling the same page with WebHarvest I only get these headers:
Date=Tue, 23 Oct 2012 18:31:51 GMT
Server=Apache/2.0.64 (Win32) JRun/4.0 SVN/1.3.2 DAV/2
Transfer-Encoding=chunked
Content-Type=text/html; charset=UTF-8
It seems that three headers (Set-Cookie, Connection and Keep-Alive) are not found by WebHarvest. Page 1, 2 and 3 are dummys so no actual validation is done. The cookie is always set on the serverside for Page 2.
Here is the WebHarvest code I am currently using:
<var-def name="content2">
<html-to-xml>
<http method="post" url="http://myurl.com/page2.cfm">
<http-param name="Login">sigge</http-param>
<http-param name="Password">hej123</http-param>
<http-param name="doLogin">Logga in</http-param>
<loop item="currField">
<list>
<var name="ctxtNewInputs" />
</list>
<body>
<script><![CDATA[
item = (NvPair) currField.getWrappedObject();
SetContextVar("itemName", item.name);
SetContextVar("itemValue", item.value);
]]></script>
<http-param name="${item.name}"><var name="itemValue" /></http-param>
</body>
</loop>
<script><![CDATA[
String keys="";
for(int i=0;i<http.headers.length;i++) {
keys+=(http.headers[i].key + "=" + http.headers[i].value +"\n---\n");
}
SetContextVar("myCookie", keys);
]]></script>
<file action="write" path="c:/kaka.txt">
<var name="myCookie"/>
</file>
</http>
</html-to-xml>
</var-def>
Edit:
when checking I noticed that the cookie is set in WebHarvest, even if the http header can't be found programatically. Is it possible that some response headers are hidden from usage?
Does anyone know a work-around for this problem?
Thank you and best regards,
SiggeLund
The way to get http header value into user-defined variable scoped for the whole config is the following:
<http url="your.url.here" method="GET">
<!--Any settings you apply for the POST/GET call-->
</http>
<!--Now you've got your http object you are going to get header value from -->
<!--At it simplest the acquisition of value goes like the below-->
<var-def name="fifth_header_val">
<script return="http.headers[5].value"/>
</var-def>
The above is just to give a clue. You can iterate over http.headers index and collect keys and values you need for your particular task.

Disable client side caching

I've been searching for info on how to disable client side caching on project level.
I know I can add the following before an action method:
[System.Web.Mvc.OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
I also read something about making profiles for caching, but that would also mean refering to them in several places. I would like a single setting in web.config, or maybe in IIS?
The project I'm working on contains a lot of partial views
Thank you in advance for any advice in this matter.
You can disable browser caching via Web.Config:
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="no-cache, no-store" />
<add name="Pragma" value="no-cache" />
<add name="Expires" value="-1" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
Source: http://blog.jamesjones.name/2009/11/how-to-disable-browser-caching-in.html
Edit: added no-store to Cache-Control for Chrome ( http://code.google.com/p/chromium/issues/detail?id=28035 )
You can set this at the project level or at the subdirectory level to control browser caching as desired. For example, in a primarily data-driven/dynamic site, I may set these headers at the project level, but in a /static directory (which contains my .js, .css, images), add another web.config which includes the appropriate </clear> directive, and perhaps set a far-future-expires header instead.
You could make BaseController and set your cache profile to it.
Then make all of your controllers to inherit from this BaseController.
Update:
Here is what I've :
// Here is my custom OutputCaheAttribute to prevent cache at all.
//Whatever you may put anything you want.
//Of course i don't use it here but i put it to show you how it's going.
[NoCache]
public class BaseController : Controller
{
protected override ViewResult View(string viewName, string masterName, object model)
{
// I do some stuffs here to change MasterPage depending on current culture.
// Don't care about it i just wanna show you why BaseController is good idea.
}
}
Then ALL my controllers inherits from this BaseController instead of normal Controller.
Hope this was helpful ;)
Expanding on #Tom's answer, for per file or per directory based cache busting :
<configuration>
<!-- disable cache for every file in this directory -->
<location path="dist">
<system.webServer>
<staticContent>
<clientCache cacheControlMode="DisableCache" />
</staticContent>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="no-cache, no-store, must-revalidate, pre-check=0, post-check=0, max-age=0, s-maxage=0" />
<add name="Pragma" value="no-cache" />
<add name="Expires" value="-1" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
</configuration>
You can define cache profiles in web.config, however, using cache profiles doesn't seem to work with OutputCache attribute in mvc 3. Read this question: Caching ChildActions using cache profiles won't work?
The OutputCache attribute is used for server side output action output caching. To turn it off, you just don't apply the attribute to the action/controller. If you want to disable client side, then that is taken care of by adding a header informing the browser not to cache the result.
If you need to cache files in a subfolder for 1 day (24 hours), you can add a separate web.config to these sub folders (requires clearing client cache the first time).
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="00:24:00" />
</staticContent>
</system.webServer>
</configuration>
Try this
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]

With Rails, How can I expire the Browser's cache?

I have an issue with my Rails application and the browser's cache: When a user logs out of the authenticated section of the site, they are still able to use the back button on the browser to see the authenticated page. I do not want to allow this.
How can I expire the cache and force it to reload.
Thank you
The following headers should do that. Whatever page you're trying protect, add them there.
Expires: Sat, 26 Jul 1997 05:00:00 GMT
Last-Modified: "now"
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Obviously, the now needs to be dynamic.
Just to be safe, you might also want to specify
<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<META HTTP-EQUIV="EXPIRES" CONTENT="0">
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
in your pages.

Resources