IIS7 + ASP.NET MVC Client Caching Headers Not Working - asp.net-mvc

I've deployed an ASP.NET MVC app on IIS7 and Windows Server 2008.
I've read posts on here, and around the web, but can't get the darn client-side caching to work.
I'm trying to cache everything in the /Content folder. So far I've select that folder in IIS manager, and set the appropriate HTTP Response Headers (under Common Headers). I've also checked the web.config file in the /Content folder and the values there are being set.
All resources in /Content come back with this (from FireBug):
Cache-Control no-cache, no-store, must-revalidate
Pragma no-cache
Content-Type image/png
Expires -1
Last-Modified Sun, 11 Oct 2009 19:01:40 GMT
Accept-Ranges bytes
Etag "f318d643a54aca1:0"
Server Microsoft-IIS/7.0
X-Powered-By ASP.NET
Date Sun, 11 Oct 2009 20:40:01 GMT
Content-Length 620
Note the Cache-Control and Expires values for this static image being requested.
The site is currently compiled in Debug (this will change), but surely that wouldn't make a difference?
Obviously I'm overlooking something, any ideas would be appreciated.
Thanks

If you can't get it working using the IIS admin tool, try Jeff Atwood's recommendation from
this thread:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
</staticContent>
</system.webServer>
</configuration>

Related

Azure-hosted ASP.NET MVC site drops client cache-related HTTP headers

We have recently begun moving some of our ASP.NET MVC websites from our own managed environment to Azure. One of the issues we have seen is that client side caching does not seem to be working properly when delivering dynamically created content. Specifically, the cache-related headers added to the HTTP response in code are stripped.
For example, the following headers are returned on the old environment in order to advise the client that the content may be cached:
Cache-Control: public, max-age=31533144
Content-Disposition: attachment; filename=picture.png
Content-Length: 64326
Content-Type: image/png
Date: Tue, 23 Jul 2013 15:44:57 GMT
Etag: "845D3DD630A7AEF5B68EA7A09B670A4D"
Expires: Fri, 23 Aug 2013 14:57:22 GMT
Last-Modified: Tue, 23 Jul 2013 14:57:22 GMT
Server: Microsoft-IIS/7.5
But on Azure, the following headers are returned instead:
Content-Disposition: attachment; filename=picture.png
Content-Length: 64326
Content-Type: image/png
Date: Tue, 23 Jul 2013 15:44:57 GMT
Server: Microsoft-IIS/8.0
X-Powered-By: ARR/2.5, ASP.NET
As you can see, the Cache-Control, Etag, Expires and Last-Modified headers have been dropped.
I have seen a number of suggestions regarding the caching of static content, but I do not believe that these will help in this case. Is it a case that the structure of the Azure CDN prevents caching in this way? Should Azure blobs be used instead? Is there a basic configuration change that may have been overlooked?
Thanks in advance
X-Powered-By: ARR/2.5, ASP.NET
ARR stands for Application Request Routing.
Go to inetmgr UI and click on the server name and you will find the option 'Application Request Routing Cache'.
You'll see 'Cache configuration', check options there. Also, check 'Cache control rules' there. Click 'Add rule...' and try play around with it.
Azure Websites site behind ARR. ARR will drop some HTTP headers and add its own, it's not something you have direct control over. A better fit for your problem may be using Azure CDN for static content. This does pay attention to and use the cache control headers. You can run a CDN on top of a blob storage container.

GZIP compression not working in IE 8 ASP.NET

I'm using IIS6 and Windows 2003 server where I enabled gzip compression for my MVC project. I thought I got it working, but once I tested in IE it did not work. I feels like it does not recognize the gzip compression or something. It works fine in Fire Fox (version 13).
Do I need to configure something?
I do a HTTP post to get some data.
Header:
HTTP/1.1 200 OK
Cache-Control: private
Date: Tue, 13 Nov 2012 21:33:19 GMT
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
X-AspNetMvc-Version: 3.0
Content-Encoding: gzip
Vary: Accept-Encoding
Transfer-Encoding: chunked
If you need anything else please let know.
Thanks
IIS does not perform HTTP compression on "dynamic" resources by default, only "static" files. This is because it caches the compressed results in IIS's temporary files directory, whereas dynamic content compression means it has to compress it every time its requested, which can burden the server if it's handling a lot of requests.
I also note that you're using IIS6 which is very antiquated at this point, but check out the documentation here: http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/502ef631-3695-4616-b268-cbe7cf1351ce.mspx?mfr=true

Defined client cache seems to get ignored

I'm not sure what I'm doing wrong but despite of everything I've tried, I don't seem to be able to get the clients to cache my static resources.
In my web.config, I've added the following entry:
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="30.00:00:00" />
</staticContent>
According to the documentation, this should send a response header to the client browser to let it know we want to keep static content cached for 30 days.
If I use fiddler to see what the client is receiving, it looks like my web.config addition gets ignored completely.
Below is what fiddler is reporting:
Cache-Control: no-cache
Date: Mon, 05 Dec 2011 14:09:44 GMT
Expires: -1
Pragma: no-cache
Vary: Accept-Encoding
I don't have any headers in IIS overriding this so I'm not sure what is it that I am missing. Any help would be greatly appreciated.
I cracked this but it took a while. You're trying to force 304s from the server (no change). It differs with IIS versions.
It's best achieved by having all you're static content in one directory
(e.g. content so you'd have /content/css /content/js etc)
Then you just have to ensure everything under that directory doesn't expire for, say, 30 days.
IIS7
Much easier. Easiest way - add a web.config to the content directory referred to above. This web.config will have just the expires directive:
<system.webServer>
<staticContent>
<clientCache
cacheControlMaxAge="30.00:00:00"
cacheControlMode="UseMaxAge" />
</staticContent>
</system.webServer>
IIS6
You'll need to manipulate the metabase. It's not XML in IIS6, follow the instructions here: IIS6 ETags metabase commands
We used both the above and simple viewing of firebug shows 304s coming through.

Expires headers in ASP MVC Development Server

I am currently changing from LABjs to YepNope, and as part of this change YepNope requires that the static content files have an "expires" header set with an absolute date/time.
I am currently using VS2010 with .net 4 and ASP MVC 3, and have tried putting the staticContent section in the web.config:
<staticContent>
<clientCache cacheControlCustom="public" httpExpires="Sun, 1 Mar 2020 00:00:00 GMT" cacheControlMode="UseExpires" />
</staticContent>
However it never pumps out the header... should I just use a HttpHandler and set that up in the web config to route all static content folders to this and add the headers in code?
If you are hosting your site on IIS, you could use the built in Output Caching functionality. It will assure your content has an expiration.
If you are not familiar with it, here is a good walk-through: http://learn.iis.net/page.aspx/710/configure-iis-7-output-caching/
Hope this helps,
-covo

Why is Chrome searching for my favicon.ico when I serve up a file from ASP.NET MVC?

I have a controller in MVC serving up images from a database.
EDIT: This still happens if I serve up a file over completely standard means in MVC.
Every time I request my image, Google Chrome also searches for my favicon.ico.
To avoid unnecessary discussions about other things "I should also care about" let us assume I do not care for caching whatsoever in this example and I shall always return HTTP response 200 with the file.
In my controller I return the following:
return File(fileBytes, contentType);
After inspecting Fiddler 2, the following response is generated:
HTTP/1.1 200 OK
Cache-Control: public
Content-Type: image/gif
ETag: oYu19wKo+KEHkyxZQ2WXAA==
Server: Microsoft-IIS/7.0
X-AspNetMvc-Version: 1.0
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
Date: Tue, 16 Jun 2009 18:48:45 GMT
Content-Length: 29344
By comparison, this is the response in Fiddler from Google when I request (for the first time) the Google logo:
HTTP/1.1 200 OK
Content-Type: image/gif
Last-Modified: Wed, 07 Jun 2006 19:42:34 GMT
Date: Tue, 16 Jun 2009 18:50:54 GMT
Expires: Wed, 16 Jun 2010 18:50:54 GMT
Cache-Control: public, max-age=31536000
Server: gws
Content-Length: 8706
Age: 2
However, in Chrome after getting my image Chrome attempts to find my favicon.ico. It does not try this after requesting the Google logo.
Any ideas why this might be happening? From my understanding on HTML, the answer must be in the response header because surely that is all the client has to go on? Please correct me!
EDIT 2: It seems a lot of people have completely misunderstood the problem. The problem is not the lack of a favicon and the erroring requests in MVC - it's the problem of requesting a favicon when only an image is being loaded, with a content type of "IMAGE/JPEG", as opposed to a webpage with a content type of "TEXT/HTML"!!
This has nothing to do with MVC. I am using webforms with a custom built log service and I stumbled upon this post wondering why I had continuous 'File does not exist' errors in my logs. This is locally on my development machine, I have no favicon.ico files in my projects, and I have tried IE, Firefox and Google trying to see which browser is the guilty party.
Every request from Google Chrome to my apps makes a request for a favicon.ico. I had to start logging browser locally to determine that it was in fact googles browser that is the culprit. I'd contact google if it bothers you. I just wanted to make sure it wasn't some new trojan infecting my chrome.
The actual answer: It's a known, verified bug. *(recently fixed!... maybe?)
Looks like a known, longstanding issue with Chrome:
http://crbug.com/39402
If you want it fixed sooner, star the issue. More people starring the issue will likely increase its priority and possibly get it fixed faster.
****UPDATE 1***: As of May 15 of this year (2013)--four years after this question was asked--it looks like the issue has been fixed in version 29:
http://crbug.com/39402#c47
Feel free to undo all your hacks and workarounds. :]
****UPDATE 2 (2015-01)***: This is apparently still an issue for some users, according to the same issue link. :/
Do you have a favicon? If not, perhaps that's why Chrome is attempting to find it every time for your website. For google it already has the favicon cached.
one thing you could do is have MVC ignore any request for *.ico so that you don't get any exceptions while debugging.
Should be something like this:
routes.MapRoute("ignore-favicon", "{*path}", null, new {path = ".*/favicon\\.ico"});
That URL pattern matches everything, but then we constrain it to only match anything ending in favicon.ico. (I haven't tested this)
I ran into this problem a while back and got around it by ignoring the specific route by adding
routes.IgnoreRoute("{*favicon}", new { favicon = ".*/favicon\\.ico" });
into the RegisterRoutes method in Global.asax.
It appears for me that Chrome requests a favicon for its own tabs - I kept getting 404s (because my favicon is somwhere else and my pages know it) till I did some tests and realized it was Chrome making direct requests to the favicon file. No real fix except making a rewrite to the real file I guess
You can add something like this within your web.config file to make sure that the favicon.ico is cached on the client and is not being requested every time.
<location path="favicon.ico">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="public, max-age=31536000" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
You can/should do the same for any images / .js and css files
You should set the Expires header to tell the browser how long it should use its local copy.
If you check your project setting it says default icon somewhere. Remove that?
Chrome browser could work with Google site in another way than with any other site, so, at first, I would recommend to check if it looks for favicon.ico every time somewhere else, for example, on StackOverflow.
I would also check if Firefox does the same with your site. I think favicon.ico should be requested only one time per browser run even if it isn't present on site. This could be bug in Chrome version you use.
This SO question/answer explains how to serve the Favicon to the browser by using routes.
Its important to put in an ICON link into your masterpage or some browsers will try to find favicon.ico for all directories and not just globally once per done.
<link rel="SHORTCUT ICON" href="<%= Url.Content("~/content/images/rr-favicon.ico") %>"/>
It seems google toolbar is the guilty party judging by my logs (and IE6 of course). They both will make requests for directories other than the root
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Mozilla/4.0 (compatible; GoogleToolbar 6.2.1910.1554; Windows 6.0; MSIE 8.0.6001.18828)

Resources