11

I try to implement Response cache in asp.net core project but its not working.This is startup.cs:

public void ConfigureServices(IServiceCollection services) 
{
  services.AddResponseCaching();
  services.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
{
    app.UseResponseCaching();

    if (env.IsDevelopment()) 
    {
      app.UseDeveloperExceptionPage();
    }

And this is my controller.

[ResponseCache(Duration = 30)]
public IActionResult Index() 
{
  ViewBag.IsMobile = RequestExtensions.IsMobileBrowser(ContextAccessor.HttpContext.Request);
  return View();
}

But still cache control header id

cache-control →no-cache, no-store

Where I am lacking please help. This response cache is not working and I take guidance from Microsoft document.

J.F.
  • 13,927
  • 9
  • 27
  • 65
Devloper
  • 133
  • 1
  • 8
  • Is there any demo to reproduce your issue? Try to make a test with CacheController [https://github.com/Edward-Zhou/AspNetCore/blob/master/MVCPro/Controllers/CacheController.cs#L12] to check whether it is related with your environment. – Edward Dec 28 '18 at 05:49

5 Answers5

14

Beware that for the cache to work must meet a number of requirements:

The request must result in a 200 (OK) response from the server.

The request method must be GET or HEAD.

Terminal middleware, such as Static File Middleware, must not process the response prior to the Response Caching Middleware.

The Authorization header must not be present.

Cache-Control header parameters must be valid, and the response must be marked public and not marked private.

The Pragma: no-cache header/value must not be present if the Cache-Control header is not present, as the Cache-Control header overrides the Pragma header when present. The Set-Cookie header must not be present.

Vary header parameters must be valid and not equal to *.

The Content-Length header value (if set) must match the size of the response body.

...

See this website: aspnet-core-response-cache

And beware also that if the request is being made from Postman disable the option "do not send the cache header".

See this post (image of end post): ASP.Net Core 2.0 - ResponseCaching Middleware - Not Caching on Server

sanmolhec
  • 396
  • 3
  • 11
4

To set up response caching in dotnet core follow these steps:

  1. In Startup.cs locate the ConfigureServices method and add the following line:

    services.AddResponseCaching();

  2. Ins Startup.cs locate the Configure method and add the following lines:

        app.UseResponseCaching();
    
        app.Use(async (context, next) =>
        {
            context.Response.GetTypedHeaders().CacheControl =
                new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
                {
                    Public = true,
                    MaxAge = TimeSpan.FromSeconds(10)
                };
            context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] =
                new string[] { "Accept-Encoding" };
    
            await next();
        });
    
  3. Apply the [ResponseCache] attribute to the action which requires caching:

    [ResponseCache(Duration = 300, VaryByQueryKeys = new string[] { "id" })]
    [HttpGet]
    public async Task<IActionResult> Index(int id)
    {
        return View();
    }
    
Denys Wessels
  • 16,829
  • 14
  • 80
  • 120
  • Can you please take a look at the question I posted? https://stackoverflow.com/questions/72755972/netcore-responsecache-does-not-work-for-some-routes – Offir Jun 25 '22 at 19:14
2

I tried this Microsoft document and successfully cached.

Cache-Control: public,max-age=30
Date: Thu, 27 Dec 2018 07:50:16 GMT

I think you are missing the app.Use(async => ) part.

darcane
  • 473
  • 3
  • 14
1

There are a few steps to getting the ResponseCaching to function:

  1. You need to call AddResponseCaching() and UseResponseCaching() in Startup.cs correctly
  2. The page must return a Cache-Control header e.g. Cache-Control: public,max-age=60 (Note that it MUST contain the public directive). You can do this via the [ResponseCache] attribute, manually adding it to the response headers, etc.
  3. Method must be GET or HEAD, status code must be 200
  4. Authorization request header must not be present
  5. If the client sends up their own cache-control header in the request, it must be valid - i.e. if the client passes up Cache-Control: max-age=0 (which Chrome/Firefox/etc do if the user presses F5) then the response will never be served from the cache because anything cached is by definition older than 0 seconds
  6. Various other conditions. I recommend making sure you can see debug-level logs from Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware which will output the reason it isn't caching the request

In my case, I wanted to ignore the client request Cache-Control header, so I added a subclass of ResponseCachingPolicyProvider like so:

    /// <summary>
    /// By default, <see cref="ResponseCachingPolicyProvider"/> will not return a cached response
    /// if the client sends up a Cache-Control header indicating the client wants a fresh
    /// response. This is according to HTTP spec but is not the behavior we want, so
    /// we will remove the client's specified Cache-Control header while evaluating whether
    /// or not we should return the cached response for this request.
    /// </summary>
    public class CustomResponseCachingPolicyProvider : ResponseCachingPolicyProvider
    {
        public override bool IsCachedEntryFresh(ResponseCachingContext context)
        {
            var reqCacheControl = context.HttpContext.Request.Headers[HeaderNames.CacheControl];
            context.HttpContext.Request.Headers.Remove(HeaderNames.CacheControl);
            var result = base.IsCachedEntryFresh(context);
            context.HttpContext.Request.Headers.Add(HeaderNames.CacheControl, reqCacheControl);
            return result;
        }
    }

If the request is being served from the memory cache, it will add an Age header to the response which you can check to verify the caching is functioning as expected.

Zout
  • 821
  • 10
  • 18
0

Must your action is GET method

Add HttpGet attribute for your action

[ResponseCache(Duration = 30)]
[HttpGet] // <---- 
public IActionResult Index() 
{
  ViewBag.IsMobile = RequestExtensions.IsMobileBrowser(ContextAccessor.HttpContext.Request);
  return View();
}
Zanyar Jalal
  • 1,407
  • 12
  • 29