How can I make sure that static content is cached client-side? - asp.net

How can I make sure that static content (images, css, javascript) is cached? What is the best approach?

Will recommend you to go through this tutorial to understand how caching happens on web (HTTP) in general.
Simply speaking, the web server needs to generate appropriate HTTP headers while sending the content to the client in order to control client-side caching. In ASP.NET/IIS environment, its IIS that typically handles the static file contents and therefore, you must configure IIS appropriately to control caching static files as per you needs. See below links for more information about configuring IIS caching for static content:
http://www.iis.net/ConfigReference/system.webServer/staticContent/clientCache
How to configure static content cache per folder and extension in IIS7?
EDIT: As you have asked about the best approach, the most prevalent approach that I see now days is to version static content (say by appending some version identifier at the end of file or URL). Once version-ed, you can treat it as immutable and then emit cache headers for caching it for infinite duration. In ASP.NET application, you can probably append the assembly version (or product version) to each static content URL. So essentially, you will invalidating the cache for every build (or every product release).

You can also make use of the HTML5 Offline web applications manifest. It allows you to set up a manifest where you define which files will be cached locally.
It is a nice, clear to understand broadly implemented, way of avoiding having to learn about IIS and HTML Caching.
http://www.w3schools.com/html/html5_app_cache.asp
(you should totally read up about those things)

Related

Loading src files once per session in asp.net

I have way too many pages in the application that basically load the same set of xml and js files for client side interaction and validation. So, I have about dozen lines like this one <script type="text/javascript" src="JS/CreateMR.js"></script> or like this one <xml id="DefaultDataIslands" src="../XMLData/DataIslands.xml">.
These same files are included in every page and as such browser sends request to read them every time. It takes about 900ms just to load these files.
I am trying to find a way to load them on just the login page, and then use that temp file as source. Is it possible to do so? If yes, how and where should I start?
P.S. A link to a tutorial will work too, as I have currently no knowledge about that.
Edit:
I can't cache the whole page, because the pages are generated at runtime based on the different possible view modes. I can only cache the js and xml file. Caching everything might be a problem.
Anyway, I am reading through the articles suggested to figure out how to do it. So, I may not be able to accept any answer right away, while I finish reading and try to implement it in one page.
Edit:
Turns out caching is already enabled, it is just that my server is acting crazy. Check the screenshot below.
With Cache
Without cache
As you see, with cache, it is actually taking more time to process some of the requests. I have no idea what that problem is, but I guess I should go to the server stack exchange to figure this out.
As for the actual problem, turns out I don't have to do anything to enable caching of xml and js files. Had no idea browsers automatically cache js files without using specific tag.
Totally possible and in fact recommended.
Browsers cache content that have been sent down with appropriate HTTP caching headers and will not request it again until the cache has expired. This will make your pages faster and more responsive and your server's load much lighter.
Here is a good read to get you started.
Here is ASP.NET MVC caching guide. It focuses on caching content returned from controllers.
Here is a read about caching static content on IIS with ASP.NET MVC.
Basically, you want to use browser caching mechanism to cache the src files after the first request.
If you're using F12 tools in your browser to debug network requests, make sure you have disable cache option unchecked. Otherwise, it forces browser to ignore cached files.
Make sure your server sends and respects cache headers - it should return HTTP status 304 Unmodified after first request to a static file.
Take a look at Asp.Net Bundling and minification - if you have for example multiple js source files, you could bundle them into one file that will be cached on the first request.
Additionally, if you use external js libraries, you could download them from a CDN instead of your server - this will both offload your server and enable user browser to use cached script version (meaning - if some other page that user has visited also used the same script, browser should already have it cached).
One approach is caching static files via IIS by adding <clientCache> element in web.config file. The <clientCache> element of the <staticContent> element specifies cache-related HTTP headers that IIS and later sends to Web clients, which control how Web clients and proxy servers will cache the content that IIS and later returns.
How to configure static content cache per folder and extension in IIS7?
Client Cache
for more info on client side caching read this part of Ultra-Fast ASP.NET 4.5 book:
Browser Cache and Caching Static Content
Other approach is caching portions of page.
if your are using Web Form:
Caching Portions of an ASP.NET Page
and if you are using MVC, use Donut Hole Caching
ASP.NET MVC Extensible Donut Caching
Donut Caching and Donut Hole Caching with Asp.Net MVC
The browser has to ask the server if the file has been modified or not since it put it to the cache, therefore the http statuscode 304. Read more from https://httpstatuses.com/304.
As this is asp.net please make sure you are first running it with
<compilation debug="false"/>
as enabling debugging has some side effects which include.
"All client-javascript libraries and static images that are deployed via
WebResources.axd will be continually downloaded by clients on each page
view request and not cached locally within the browser."
More read from https://blogs.msdn.microsoft.com/prashant_upadhyay/2011/07/14/why-debugfalse-in-asp-net-applications-in-production-environment/

Dependencies that must be done away with for using CDN

I wanted to know that, is there some special requirement for a website to make use of CDN ?
i mean is there some special scheme(or atleast considerations) on which your website must be build right from the start to make use of CDN (Content delivery network).
is there anything that can stop a website from making use of CDN, for example the way it references the content files, static file paths or any other thing conceivable.
Thanks
It depends.
You have two kinds of CDN services:
Services like AWS Cloudfront that require you to upload the files in some special place that they read from (eg. AWS S3) - In this case you need have a step in your build process to correctly upload the files and handle the addresses somehow inside your application
Services like Akamai that just need you to change and tweak your DNS records so they will serve the request to your users instead of you - In this case you would have two domains (image.you.com and image2.you.com) and have the image.you.com pointing to Akamai and image2.you.com pointing to the original source of the file. Whenever a user requested an image in Akamai, they would come to you through the "back door", fetch it and starting serving that file always.
If you use the second approach it's really simple to have a CDN supporting your application.
There are a whole bunch of concerns when dealing with CDN solutions.
The first one is that a CDN can't serve a dynamic page - i.e. a page that is unique to every user. Typically, that includes PHP, ASPX, JSP, RubyOnRails etc. - so if you're hoping to support lots of users for a dynamic site, you have to come up with another solution. Some CDN providers support "Edge Side Includes" - this allows you to glue dynamic pages together with cached content on the CDN, but this creates quite a complex application.
Of course, even on a dynamic application, a CDN can still serve static files - images, stylesheets, javascript files, videos etc.
#Tucaz explains the two major options here (actually, Akamai also provides a "filestore" CDN option). If you select the second option - effectively, the CDN becomes a caching reverse proxy in front of your website - it makes sense to tweak the cache headers on your HTTP server, and tell the CDN to honour those. Make sure you set your .ASPX files to not cache!

ASP.NET MVC Bundles debug = true and result is still cached

In my development environment the Javascript isn't showing the changes I've made, Why is it still caching, What else can I do?
The only documentation I've seen on this is the web.config, compilation debug=true setting,
When you set debug="true", the bundler will emit script or link tags to each resource individually, rather than a one for a single (optionally) optimized resource. As such, the resource will be accessed from the static handler directly by the browser. So, if your application or IIS settings have aggressive settings for caching static content, that would be your problem.
Use Control+F5 to force a re-download of content. This should work in most browsers.

IIS7: Differences between static and dynamic content compression

IIS supports two types of compression: static content compression and dynamic content compression. According to applicationHost.config, they are handled by different modules: DynamicCompressionModule (compdyn.dll) and StaticCompressionModule (compstat.dll), and they are configured to compress different types of requests. Also, I’m guessing that the dynamic compression does not cache the compressed requests as opposed the static compression (by default, the compressed files are saved to %SystemDrive%\inetpub\temp\IIS Temporary Compressed Files).
However, besides those obvious differences, I suspect that there is something else. I think that they hook to the IIS pipeline to a slightly different way. Would anybody have an inside into the some more details?
The way I found out was that I was toying with a custom module for modifying CSS files on fly. When the static compression was turned on (and set to handle the default set of files, i.e. also text/css), on cached request my custom module was served the already gzipped content. When I moved text/css to the list of dynamically compressed request, it all started working. But I would like to have a more solid proof that it is really the correct way to do it. Are there some other known consequences / problems?
Update: I think I may have a theory as to why it’s happening. It may not be 100% correct, but it at least it may explain the observed behavior. I think that the static compression module registers itself to the following events (among some others):
RQ_MAP_REQUEST_HANDLER
RQ_EXECUTE_REQUEST_HANDLER
Then when a request for a static file is served, the static compression module in OnMapRequestHandler checks whether the file has been compressed before and whether the actual file has not been changed. If so, it will re-map the request to itself (returning the appropriate redirection using IMapHandlerProvider). When it later actually serves the response in OnExecuteRequestHandler, it sends the compressed file. If, on the other hand, the file has not been compressed before or if it has changed, it does not do the mapping redirect and lets the static content module serve the request and then later in OnPostExecuteRequestHandler compresses the content (and updates its cache). As mentioned above, I'm not saying that this is exactly what's happening (I don't know the source code), it may be only an approximation. Also, the dynamic compression module does not most likely do any of this. It simply compresses the outgoing responses sometimes after RQ_EXECUTE_REQUEST_HANDLER.
Your question is not quite clear, so I will answer a question and hope that it is your question.
The intent of static compression is to compress files that would otherwise be served direct from the hard drive (Css/images/javascript) and as such it compresses each file once and saves the compressed file to disk. This enables very quick very cheap serving of compressed content for static files that change infrequently. It is a pretty safe recommendation to say most website should have static compression enabled.
The intent of dynamic compression is to compress the dynamic responses from ISS modules (asp, asp.net, php, etc.). As this response can be different for each request the compressed output can not be cached. This feature is new from IIS6, though the effect has been achievable in some environments, e.g. by implementing a HttpFilter in ASP.Net. As each request needs to be compressed on the fly this is far more CPU intensive then static compression. So if a server is CPU bound this may not be a good option. Most sites are network and/or database bound so the is often a good idea.
So the dynamic and static refer to the content and effect what strategies can be used.
Some References
http://www.iis.net/overview/DynamicCachingAndCompression
http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/92f627a8-4ec3-480c-b0be-59a561091597.mspx?mfr=true
Experimenting with IIS compression feature, it appeared to me that dynamic module and static module are not so tied to dynamic or static content (especially for dynamic module).
Activate compression for text/html (or text/*) mime type on dynamic module, and not on static module. Access a .html file. Checks the http response in browser: it is compressed. (Tested on IIS 7.5 on 2008R2 server.)
It appears dynamic compression module is not limited to dynamic content. It does compressed static content providing it matches its mime types list and is not already compressed. So I consider it should be understood as a dynamic "compression module", in the sense it gets triggered on each response (based on its mime type criteria, and on accept-encoding request header).
While the static compression module gets triggered a bit like a background process working on files, and starts serving compressed output only once it has them in its cache. Since static compression module does execute farer in the modules stack, it does handle the response prior to dynamic compression module, and so take precedence over dynamic one if it has compressed output to serve.
So for your specific use case, you should disable static compression module on text/css mime type (beware of removing text\* too if present) in order to avoid caching issues defeating your custom css patching module.
You may in addition activate compression of text/css in dynamic compression module for replacing static compression module on this case. But of course, it will then not leverage the static compression module caching ability.
Unfortunately, I have not found any documentation for backing up above statements.
Another option could be trying to alter IIS module execution order. You would have to remove them all in your site configuration, then re-add them, inserting your custom module maybe before the static compression one. But this could be a tricky path.

Browser Caching in ASP.NET application

Any suggestions on how to do browser caching within a asp.net application. I've found some different methods online but wasn't sure what would be the best. Specifically, I would like to cache my CSS and JS files. They do change, however, it is usually once a month at the most.
Another technique is to stores you static images, css and js on another server (such as a CDN) which has the Expires header set properly. The advantage of this is two-fold:
The expires header will encourage browsers and proxies to cache these static files
The CDN will offload from your server serving up static files.
By using another domain name for your static content, browsers will download faster. This is because serving resources from four or five different hostnames increases parallelization of downloads.
If the CDN is configured properly and uses cookieless domain then you don't have unnecessary cookies going back and forth.
Its worth bearing in mind that even without Cache-Control or Expires headers most browsers will cache content such as JS and CSS. What should happen though is the browser should request the resource every time its needed but will typically get a "304 Unmodified" response and the browser then uses the cached item. This is can still be quite costly since its a round trip to the server but the resource itself isn't sent so the bytes transfered is limited.
IE left with no specific instructions regarding caching will by default use its own heuristics to determine if it should even bother to re-request an item its cached. This despite not being explicitly told that it can cache a resource. Its hueristics are based on the Last-Modified date of the resource, the older its the less likely it'll have changed now is its typical reasoning. Very wooly.
Frankly if you want to make a site perfomant you need to have control over such cache settings. If you don't have access to these settings then don't wouldn't worry about performance. Just inform the sponsor that it may not perform well because they haven't facilitated a platform that lets you deliver that.
You best bet to do this is to set an Expires header in IIS on the folders you want the content cached. This will tell most modern browsers and proxies to cache this static content. In IIS 6:
Right click on the folder (example CSS or JS) you want to be cached by the browser.
Click properties
Go to the HTTP Headers Tab
Check "Enabled content expiration"
Set some long period for expiration, like "Expires after 90 days"
Yahoo Developer's Blog talks about this technique.
Unless you configure IIS to give asp.net control of js/css/image requests it won't see them by default, hence your best plan (for long term maintainability) is to deliberately tweak the response headers at your firewall/trafficmanager/server or (better and what most of the world does at this point) to version your files in path, i.e:
Instead of writing this in your mark-up:
http://www.foo.com/cachingmakesmesad.css
Use this:
http://www.foo.com/cachingmakesmesad.css?v1
..and change the version number when you need to effectively clear cache. If that's every time then you could even append a GUID or datestamp instead, but I can't think of any occasion where I would want to do that really.
I thought your question was anti-cache but re-reading it I see I wasted a good answer there :P
Long story short, browsers are normally very aggressively pro-caching "simple" resources so you shouldn't have to worry about this, but if you did want to do something about it you would have to have access to a firewall/trafficmanager/IIS for the reasons above (ASP.NET won't be given a chance by default).
However... there is no way you can absolutely force caching, and nor should you. What is and isn't cached is rightfully the decision of the end-user, all you can do is strongly request.
In .net you can set up your JavaScript, CSS and Images as embedded resources.
.Net will then handle the file expiration for you.
The downside to this approach is that you have to do a new build for each set of changes (this might be an upside, depending on your deployment and workflow).
You could also use ETags, but from what I understand in some cases it doesn’t work well if you have mix of IIS and apache Webservers hosting your images, (or if you plan to switch in the future).
You can just make sure the file date is newer, and let the server handle it for you, but you’ve got to make sure the server is configured correctly.
You can cache static content by adding following code in web.config
<system.webServer>
<staticContent>
<clientCache httpExpires="Tue, 12 Apr 2016 00:00:00 GMT" cacheControlMode="UseExpires" />
</staticContent>
</system.webServer>
See the clientCache documentation for more details.

Resources