Expiration date for Cached static content - iis

I use asp.net c# 4 and IIS 7.5.
I need to set the header for my static content on my website for caching PUBLIC for 14 days.
At the moment I use this setting in my web.config
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
</staticContent>
As result I get a header Cache-Control:max-age=1209600
I'm testing my site with https://developers.google.com/pagespeed/ and I still get an (expiration not specified)
What I missing in my web.config to get the "Expires" attributes us output?
Thanks

The "Expires" HTTP header was deprecated in HTTP 1.1 -- it's only needed by old HTTP 1.0 clients (or to satisfy tools that don't know any better).
If you really want it, you could create a simple HttpModule that identifies requests for static content and calls:
Response.Cache.SetExpires()

Related

How to Use eTag on IIS for text/html Pages

I have a website which sits on a non-public domain and is delivered via a proxy through on a different domain. We're having some trouble with caching of content - this is an Umbraco site and making changes updates the pages if you hit the domain directly, but not through the proxy.
I've been informed that the proxy honours response headers and setting an eTag would fix the issue. Having looked into this I can see that IIS sets the eTag by default, and I can see this is working on static content i.e. .js, .css files like so:
However, if I visit a page on the site, for example /uk/products/product I don't see the eTag header.
Is this expected behaviour, should it only be working with those static content files or can I set this on the page to tell the proxy that it should recache?
The ETag HTTP response header is an identifier for a specific version of a resource. It lets caches be more efficient and save bandwidth, as a web server does not need to resend a full response if the content has not changed. Additionally,etags help prevents simultaneous updates of a resource from overwriting each other ("mid-air collisions").
If the resource at a given URL changes, a new Etag value must be generated.
Static content does not change from request to request. The content that gets returned to the Web browser is always the same. Examples of static content include HTML, JPG, or GIF files.
IIS automatically caches static content (such as HTML pages, images, and style sheets), since these types of content do not change from request to request. IIS also detects changes to the files when you make updates, and IIS flushes the cache as needed.
to enable caching in iis you could use iis output caching feature:
1)open iis manager. select site.
2)select the output caching feature from the middle pane.
3)select edit feature setting from the middle pane.
4)check the enable cache and enable kernel cache box and click ok.
if you want to set the ETag as blank you could also do by adding below code in web.config file:
<httpProtocol>
<customHeaders>
<add name="ETag" value="" />
</customHeaders>
</httpProtocol>
refer this below article for more detail:
Caching
To use or not to use ETag, that is the question.
Configure IIS Output Caching
I've read that IIS after version 7 automatically enables E-tags, however, I ran a Pingdom speed test and the report advised me to enable E-tags. I'm not sure that report is accurate, or the information I read about IIS 7 and newer may not be correct.

IIS 8.5 Not honoring Web API [EnableCors] attribute. Not setting Access-Control-Allow-Origin Header

Rundown
So I've continued tinkering with this. This is a new Windows Server with IIS 8.5. I've never had any problems getting CORS to "just work" in IIS so I've never really needed to care about the fiddly bits in the server config. The immediate fix was the shotgun approach; I enabled CORS server-wide with the following modification to applicationhost.config
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
but removing this customHeader and setting [EnableCors(origins: "*",headers: "*", methods: "*")] inside my controllers does not cause the server to send back Access-Control-Allow-Origin response headers (yes, I made sure to call config.EnableCors() in my HttpConfiguration.
An additional complication is that using this method, I have to allow all origins because I need several origins to be able to access this server. Browser implementations do not permit multiple origins to be sent back from the server in this header. I could always write my own EnableCors logic within my application, but would rather understand and fix the server config to stay on the res.
Original Question
So I'm running into a bit of an issue trying to get a Web Application deployed to IIS 8.5 on a fresh Windows Server 2012 R2 straight from our server provisioning team. My application is a Web API with Cors Enabled, (currently allowing all origins) but the server is not returning an Access-Control-Allow-Origin header to calling clients. I've never had an issue with Web API Cors "just working."
I found this resource, but confirmed that the OPTIONSVerbHandler had already been removed within my application's web.config.
I tried to add a customHeader to IIS, but whenever I did that, the server started returning 500s.
Is there anything that I can do to force IIS 8.5 to send Access-Control-Allow-Origin headers from ASP.NET?
Edit1
So I apparently installed the ASP.NET Cross Origin Resource Sharing NuGet package into my solution rather than the ASP.NET Web API 2.2 Cross Origin Resource Sharing NuGet package. I swapped these out and I have limited (but still unexpected) CORS functionality. I'll describe the weirdness I'm experiencing now.
So before I realized I had the wrong NuGet package, I had gone into applicationHost.config and added
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
in an attempt to get the server to push the header back manually. Without the NuGet update, this did not set the header on preflight responses but at this point I'm not quite sure if that was due to me forgetting an iisreset;I was trying to move fast.
At any rate, when I added the Web API 2.2 Cors NuGet package, my server responses started emitting an Access-Control-Allow-Origin header with wildcard origins rather than the ones that I had set in my EnableCors attributes inside my Web API routes. So with that value, I knew that it was the configured customHeader rather than the EnableCorsAttribute that is now controlling the value.
(Here's where the weirdness comes in)
So I would actually prefer to be able to directly control the CORS whitelist directly at the server level, so I went ahead and set the customHeader to
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://segment.mydomain.com" />
</customHeaders>
where http://segment.mydomain.com also matches one of the allowed origins inside my API routes.
I now get the proper Access-Control-Allow-Origin sent back from IIS in the PreFlight request, but the subsequent POST returns a 500. If I remove the EnableCors attribute from my Api Route, the POST succeeds (confirmed by directly querying the database that persists the posted data)
...wt*?
Edit2
So that hopeful approach (statically defined origins inside a customHeader in IIS rather than allowing developers to list their origins directly inside controllers) won't actually work. I need to whitelist multiple origins and Chrome's implementation only allows one origin to be set in the ACAO header. It also will not allow wildcard segments in origins, so...that sucks.

Windows Azure WebSites maxQueryStringLength

I'm trying to use jquery dataTables with a few extras on Azure Websites. It generates a sizeable query string (2121 characters in testing). This returns a bad code on Azure websites (The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.).
To get it working locally I edited the web.config with this:
<httpRuntime maxQueryStringLength="4000" maxUrlLength="4000"/>
(I believe only the maxQueryStringLength is really needed).
Anyway, all is fine locally and on another server but on WA Web Sites I can't get it working. Any ideas?
Try customizing IIS Request Filtering parameters.
I suspect you're using Cassini (Visual Studio development server) to develop locally.
Limitations related to Query String and/or URL max lengths occur at two levels on Azure Websites (or any IIS environments) :
ASP.NET Runtime : These limits are lifted using the httpRuntime node and its associated attributes
IIS Requests Filtering module : IIS also applies its own filtering rules regarding URL and Query String length, even before the request is processed by the ASP.NET Runtime. By default, the maximum allowed length for a query string is 2048 (see here). You should set the appropriate values in your Web.config, under the requestLimits subnodes, eg :
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxQueryString="4096"/>
</requestFiltering>
</security>
</system.webServer>
See also this question

How do I prevent default IIS compression on a response that is already compressed?

TLDR
I have an IHttpHandler that performs compression. It works fine on its own. But then I added an IHttpModule that performs a completely unrelated task on those (and all other) responses, and now IIS is re-compressing the already-compressed responses. How can I prevent this?
The Whole Story
I have an IHttpHandler implementation that performs combination and compression (among other things) for CSS and JS files. Everything in the IHttpHandler works exactly like I want it to.
But then I added an IHttpModule implementation that removes unnecessary response headers (Server, X-AspNet-Version, etc.) from all responses (including the dynamic responses that are generated by the IHttpHandler) during the PreSendRequestHeaders event.
However, it seems that simply registering an IHttpModule, regardless of what it actually does, causes IIS to apply compression to the response, even if the response is already compressed.
So, my IHttpHandler explicitly compresses the response and sets the Content-Encoding header, then (if and only if) the IHttpModule is also registered, IIS re-compresses the response (so there's a doubly-compressed response that browsers can't read).
I don't want to disable all default compression. I still want HTML from views to be compressed (and I want any CSS and JS that doesn't go through the IHttpHandler to also be default-compressed).
I'm guessing there's no easy solution to my problem because it seems like a bug in IIS. IIS should not compress a response that is already compressed.
I tried adding the following to my web.config, but it had no effect:
<httpCompression>
<dynamicTypes>
<add mimeType="text/css" enabled="false" />
<add mimeType="application/javascript" enabled="false" />
</dynamicTypes>
</httpCompression>
(From my interpretation of the documentation, that should disable compression for dynamically generated CSS and JS.)
I also tried this, to no effect:
<httpCompression>
<dynamicTypes>
<clear/>
</dynamicTypes>
<staticTypes>
<clear/>
</staticTypes>
</httpCompression>
(From my interpretation of the documentation, that should disable all default compression.)
Update
In my IHttpHandler, I call context.Response.Flush at the very end. If I remove this call, the response doesn't get double-compressed. I'm fine with this as a solution. Can anyone explain why this is happening?
Update 2
My best guess is that calling Flush puts the response into such a state that IIS doesn't think the response is already compressed (and so it applies default compression). Even though in my module I can check both...
that Response.Headers contains a Content-Encoding header and
that Response.Filter is non-null and is one of the System.IO.Compression types.
Not sure why IIS can't determine that the response is already compressed from those facts.

How can I get IIS to publish cache headers for my favicon.ico?

Our site's favicon.ico file hasn't changed in years - and isn't going to change any time soon - so I'd like to configure IIS to serve it with a far-future cache expiry header. The rest of the content in the root folder of my site is dynamic pages that shouldn't be cached - but as far as I can tell, IIS only allows you to set content expiry cache on a per-folder basis - so is there any way to set a cache header for favicon.ico without affecting the rest of the content in the home directory as well?
Yep - drill down to the file.
In IIS Manager (on IIS6), navigate to the file, right click, properties, HTTP Headers tab, check Enable Content Expiration; party on with the other settings.
Kudos to Dylan (below) for IIS7 instructions and this snippet.
This creates the following section in web.config, so you can probably achieve the same thing just by editing the file directly.
<configuration>
<location path="favicon.ico">
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="90.00:00:00" />
</staticContent>
</system.webServer>
</location>
</configuration>

Resources