1

Using ASP.NET Core 3.1 I created a Middleware as follows:

public class SitemapMiddleware {
  
  private readonly RequestDelegate _next;

  public SitemapMiddleware(RequestDelegate next) {
    
    _next = next;

  }

  public async Task InvokeAsync(HttpContext context, ISitemapService sitemapService) {

    if (context.Request.Path.StartsWithSegments("sitemap.xml")) {

      Sitemap sitemap = await sitemapService.GetAsync();

      context.Response.ContentType = "application/xml";

      context.Response.Headers.Add("Cache-Control", "public,max-age=20");

      await context.Response.WriteAsync(sitemap.Build(), Encoding.UTF8);

    } else {

      await _next(context);
    
    }

  }

}

When I access "sitemap.xml" in the browser the response I get has the correct content.

But when I access it again within the next 20 seconds the code is executed again.

I am adding the "Cache-Control" header and I checked and it is in the response.

Why is the code executed again?

Métoule
  • 13,062
  • 2
  • 56
  • 84
Miguel Moura
  • 36,732
  • 85
  • 259
  • 481
  • Is it possible that you need to add the [Caching Middleware](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/middleware?view=aspnetcore-3.1)? – Martin Drozdík Aug 10 '20 at 14:32
  • I have `services.AddResponseCaching();` in ConfigureServices and `applicationBuilder.UseResponseCaching();` in Configure method. I have no idea if something is missing ... – Miguel Moura Aug 10 '20 at 14:56
  • On browsers under developer options (on chrome F12/Network) there is usually a "Disable cache" option. Worth a check. – Martin Drozdík Aug 10 '20 at 15:11
  • I know about that option and I enabled cache ... – Miguel Moura Aug 10 '20 at 15:50

2 Answers2

2

It's probably your browser that ignores the cache control header. The question Is Chrome ignoring Cache-Control: max-age? states:

Google Chrome ignores the Cache-Control or Expires header if you make a request immediately after another request to the same URI in the same tab (by clicking the refresh button, pressing the F5 key or pressing Command + R).

Firefox appears to do the same thing.

After a quick test, loading the same URL on another tab does load the cached content, and doesn't execute the code again.

Métoule
  • 13,062
  • 2
  • 56
  • 84
  • You are completely right. I tried to call the url in another tab and the code is not executed and the cached version is returned. – Miguel Moura Aug 10 '20 at 15:49
1

If you do not want to rely on HTTP caching, you can use ASP.NET caching, for example, memory cache. I put together a little example similar to what I use. Might help.

public class SitemapController : Controller
        {
            const string SITEMAP_CACHE_KEY = "SitemapNodesCacheKey";
    
        readonly IMemoryCache cache;

        public SitemapController(IMemoryCache cache)
        {
            this.cache = cache;
        }

        /// <summary>
        /// Returns sitemap of this web.
        /// Handles caching etc.
        /// </summary>
        /// <returns></returns>
        protected string GetSitemap()
        {
            //Cache not found
            if (!cache.TryGetValue(SITEMAP_CACHE_KEY, out var cacheEntry))
            {
                cacheEntry = "SOME CACHE TEXT/STRUCTURE HERE";

                //Set cache options
                var cacheEntryOptions = new MemoryCacheEntryOptions()
                    .SetSlidingExpiration(TimeSpan.FromHours(8))
                    .SetAbsoluteExpiration(TimeSpan.FromHours(24));

                //Save data in cache
                cache.Set(SITEMAP_CACHE_KEY, cacheEntry, cacheEntryOptions);
            }


            return cacheEntry as string;
        }

        [HttpPost("/sitemap/update")]
        public IActionResult UpdateSitemap()
        {
            cache.Remove(SITEMAP_CACHE_KEY);

            return Ok();
        }

        [Route("/sitemap.xml")]
        public IActionResult SitemapFile()
        {
            return Content(GetSitemap(), "text/xml");
        }
    }
Martin Drozdík
  • 351
  • 3
  • 7
  • I was also using MemoryCache but I wasn't sure if that was the best option. In fact "sitemap.xml" is going to be called by Google and Bing sitemaps. Not by the browser. Do you think I should use MemoryCache instead of Cache Control? – Miguel Moura Aug 10 '20 at 15:49
  • 1
    If you have a static sitemap.xml file I believe there is absolutely no need for a cache system. If your sitemap is generated for example from a database and you are worried about performance, I personally would suggest using a memory cache (IMemoryCache) since as you stated, the sitemap file is usually requested by a search engine and it gives you more "control" – you exactly know how it will behave. No unexpected shenanigans. However, it might be a different story if we were to talk about for example images, pages, etc. – Martin Drozdík Aug 10 '20 at 17:32