How do I get IIS to return a Custom-Cache Control Header from WebApi 2, IIS 10 returns private every time

** UPDATE Jan 27, 2021 **
I have been working with Microsoft on this issue and we did a request trace and reviewed the FREB log and confirmed that the code is outputting the correct headers but in the END_REQUEST handler they are replaced with cache-control private. After building several virtual machines from scratch we learned that out of the box, this problem doesn’t happen. However when we install the latest version of STACKIFY AGENT (4.29.29) once we put the agent on this behavior happens. Older versions of Stackify agent (RETRACE profiler and APM) don’t do this, but so far, this is irreversible: once we install 4.29.29 of Stackify, uninstalling or installing older versions doesn’t undo this issue, the environment is somehow permanently modified.

STACKIFY responded with a solution which works (but suggests something is left behind after uninstall): Set the environment variable STACKIFY_ENABLERUM = false .. we tried this and IIS returned our correct header without replacing it with cache-control: private.


I want to use CloudFront CDN to cache traffic to my API, so that requests are offloaded to the content delivery network.

I’m trying to set the Cache-Control header to return: Cache-Control: “public, max-age=10”. When I run my code in Visual Studio 2019 to debug it, I get the correct header. However, when I deploy it to IIS, I always get back:

Cache-Control: private

I am running Windows Server 2019 with IIS version 10.0.17763.1. I am using ASP.NET MVC with Web API 2 to operate a REST API.

In my code I created this attribute:

Code:

 public class CacheControlAttribute : System.Web.Http.Filters.ActionFilterAttribute
    {
        public int MaxAge { get; set; }

        public CacheControlAttribute()
        {
            MaxAge = 0;
        }

        public override void OnActionExecuted(HttpActionExecutedContext context)
        {
            // Don't set the cache header if there was an error or if there was no content in the response
            if (context.Response != null && context.Response.IsSuccessStatusCode)
            {
                context.Response.Headers.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue
                {
                    Private = false,
                    Public = true,
                    MaxAge = TimeSpan.FromSeconds(MaxAge)
                };                

            }

            base.OnActionExecuted(context);
        }
    }

I then decorate my method with this attribute:

[CacheControl(MaxAge = 10)]

I read several articles on StackOverflow but was not able to solve this issue. I also tried adding this to web.config:

It did not help.

I have this working successfully on one IIS server, same version of IIS but older version of my code. I’m having the problem setting it up on a new IIS server and I think its an IIS configuration issue but I am not certain. Maybe its something in my web.config.

Thank you for any help with this.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Cache-control is divided into request and response directives. I guess you are talking about the cache-control in the response, because the request cache-control cannot be set in IIS.

For security reasons, IIS will set cache-control to private by default, so you will encounter this problem. This is default behaviour for .NET when there’s no output cache used for a request (and you have output cache enabled). If you set the sendCacheControlHeader to false in web.config, you will not get the Cache-Control: private header.

So an easy way is set sendCacheControlHeader false and add cache-control will remove private. You also don’t need to custom cache-control filter in MVC.

<system.web>
   <httpRuntime sendCacheControlHeader="false" /> 
</system.web>

<httpProtocol>
 <customHeaders>
   <remove name="X-Powered-By" />
    <add name="Cache-Control" value="max-age=30,public" />
 </customHeaders>
</httpProtocol>

Another idea is to add cached output for each action or controller. .NET has a defined filter to control maxage, you don’t need to define it yourself. You can use [OutputCache(Duration = 0)]

OutputCache

Method 2

You need to implement your own on top of the existing output cache like so

public static class MyCustomCacheConfig
{
    public static int Duration = 600; //whatever time you want
}

public class CdnCacheCacheAttribute : OutputCacheAttribute
{
    public CdnCacheCacheAttribute()
    {
        this.Duration = MyCustomCacheConfig.Duration;
    }
}

[CdnCacheCacheAttribute(Duration = 100, VaryByParam = "none")]
public ActionResult YourActions()
{
    return View();
}

VaryByParm in output cache from Microsoft.. which controls the HttpCaching

// Get the current VaryByParam.
String varyByParamValue =  outputCacheProfile.VaryByParam;

// Set the VaryByParam.outputCacheProfile.VaryByParam = string.Empty;


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x