IIS/ASP.NET responds with cache-control: private for all requests

Adding my bit to the great answers, given by community;

1. http caching header attrubute Cache-Control: private is added by default by IIS/ASP.NET ?

Cache request directives

Standard Cache-Control directives that can be used by the client in an HTTP request.

    Cache-Control: max-age=<seconds>
    Cache-Control: max-stale[=<seconds>]
    Cache-Control: min-fresh=<seconds>
    Cache-Control: no-cache 
    Cache-Control: no-store
    Cache-Control: no-transform
    Cache-Control: only-if-cached

Cache response directives

Standard Cache-Control directives that can be used by the server in an HTTP response.

    Cache-Control: must-revalidate
    Cache-Control: no-cache
    Cache-Control: no-store
    Cache-Control: no-transform
    Cache-Control: public
    Cache-Control: private
    Cache-Control: proxy-revalidate
    Cache-Control: max-age=<seconds>
    Cache-Control: s-maxage=<seconds>

IIS uses the secure and more obvious/useful one for default, which happens to be private

2. how to prevent it from being added by default?

IIS/asp.net allows this to be configured from the day it was introduced like this, ref1, ref2, ref3, ref4 and

System.Web Namespace

The System.Web namespace supplies classes and interfaces that enable browser-server communication. This namespace includes the System.Web.HttpRequest class, which provides extensive information about the current HTTP request; the System.Web.HttpResponse class, which manages HTTP output to the client; and the System.Web.HttpServerUtility class, which provides access to server-side utilities and processes. System.Web also includes classes for cookie manipulation, file transfer, exception information, and output cache control.

protected void Application_BeginRequest()
{
  Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
}

what adds this header?

The IIS 7 and later (included in the default installation) sends it to Web clients as one of the cache-related HTTP headers.

and how can I prevent it from being added by default?

I describe two ways of disabling cache mechanism (server-side approach and client-side approach) with a focus on server-side based on your question:

Server-Side Approach

Follow this steps Inside the Internet Information Services (IIS) Manager to change Cache-Control value (while I think this works for static contents):

  1. In the Connections pane, go to the site, application, or directory for which you want to disable caching.
  2. In the Home pane, double-click HTTP Response Headers.
  3. Click Set Common Headers ... in the Actions pane.
  4. Check the box to expire Web content, select the option to expire after a specific interval or at a specific time, and then click OK.

One way is to annotate your controller as follows which is quite powerful and the response headers contain a Cache-Control: public, max-age=0 header.:

[OutputCache(Duration = 0)]
public class SomeController : Controller  {

}

You can also Define a cache profile in your application's Web.config file and in the profile, include duration and varyByParam settings:

<caching>
  <outputCacheSettings>
    <outputCacheProfiles>
      <add name="nocache" duration="0" 
        varyByParam="none" />
    </outputCacheProfiles>
  </outputCacheSettings>
</caching>

Then use it by the [OutputCache CacheProfile="nocache"] before the action/controller.

Note that there is a configuration in web.config file (following) which won’t prevent caching. Instead it just indicates that no kind of caching mechanism should be applied. By just disabling the output cache we get the default cache headers used by ASP.net MVC which falls back to Cache-Control: private, thus again opening the browser the possibility to cache requests.

<caching>
    <outputCache enableOutputCache="false" />
</caching>

Client-Side Approach

Using cache: false inside your js request like:

$.ajax({
    type: 'GET',
    cache: false,
    url: '/nation',
    ...
});

For additional information, visit:

  • Client Cache <clientCache>
  • How to: Set the Cacheability of an ASP.NET Page Declaratively
  • output-caching-in-aspnet-mvc

TL; DR

  1. Caching is not used by default for dynamic ASP.NET pages. You need to make an efforts to enable caching in ASP.NET.
  2. Presence of 'Cache-Control: private' header does not mean at all that cached version of the page will be used on repeated requests.

--

There is a very simple test to validate above statements. Create an action that returns current time:

public ActionResult Index()
{
    ViewBag.CurrTime = DateTime.Now.ToString("T");
    return View();
}

View:

@{
    ViewBag.Title = "Home Page";
}

<h1>@ViewBag.CurrTime</h1>

If you refresh such page in abrowser, you'll see fresh time on every request:

enter image description here

enter image description here

There is a possibility to use caching with ASP.NET MVC but you should make some efforts to enable it. See this article for details.

If in spite of this you still for some reason want to exclude any possibility of the caching, you could do it by setting specific HTTP headers. There is a great SO answer that lists which headers should be set:

Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0

You could use action filter to set those headers in every ASP.NET response:

public class CachingHeadersFilterAttribute : ActionFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        var response = filterContext.HttpContext.Response;

        response.Cache.SetCacheability(HttpCacheability.NoCache);
        response.Cache.AppendCacheExtension("no-store, must-revalidate");
        response.AppendHeader("Pragma", "no-cache");
        response.AppendHeader("Expires", "0");

        base.OnResultExecuted(filterContext);
    }
}

In FilterConfig.cs (crated automatically in ASP.NET MVC template):

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new CachingHeadersFilterAttribute());
    }
}

Here are result headers from the response:

HTTP/1.1 200 OK
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Expires: -1
Vary: Accept-Encoding
Server: Microsoft-IIS/10.0
X-AspNetMvc-Version: 5.2
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcRHJvcGJveFxwcm9nXFN0YWNrT3ZlcmZsb3dcUTQ3MjI0NTYxQ2FjaGVcUTQ3MjI0NTYxQ2FjaGU=?=
X-Powered-By: ASP.NET
Date: Mon, 13 Nov 2017 17:44:33 GMT
Content-Length: 837

As you see there is no 'Cache-Control: private' header.

But again, I don't see a reason why you should add such filter to your application.