ASP.NET Core Response Cache

Where is output cache in ASP.NET Core? Is it gone? No, it’s there but in new and better extensible form and it is called now response caching. This blog post shows how to use response caching on ASP.NET Core and provides tips about some internals of it.

In ASP.NET Core caching is solved as middleware service that comes with Microsoft.AspNetCore.ResponseCaching NuGet package. In MVC caching is driven by ResponseCache attribute. It’s possible to use ResponseCache attribute also without response caching middleware to just set response headers. This way it is possible to tell browser to cache content and also cache or proxy servers on the way can read these headers to find out how to cache page.

By default response caching uses memory based cache but there are extension points that allow to use custom cache storage providers. This blog post doesn’t cover extensibility. It covers just basics and focuses on stateless public sites.

Using respone caching

After adding package reference to Microsoft.AspNetCore.ResponseCaching we can register response caching middleware in Startup class using AddResponseCaching() and UseResponseCaching() extension methods.


public void ConfigureServices(IServiceCollection services)
{
   
// ...
 
    services.AddResponseCaching();
    services.AddMvc();
 
    // ...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// ...

    app.UseResponseCaching();

    app.UseMvc(routes =>
    {

        routes.MapRoute(
            name:
"Default",
            template:
"{controller=Home}/{action=Index}/{id?}"
,
            defaults:
""
        );

    });           
}

For MVC controller action we add ResponseCache attribute. The following example shows primitive controller action that returns just a simple view it has.


[ResponseCache(Duration = 30)]
public IActionResult Article(
)
{
    return View();
}

This is enough to get caching work with minimal effort. When we run our application and request controller action that is cached we get the following result:

ASP.NET Core response caching output

NB! For full list of cache settings available check out the following pages from official documentation:

Caching profiles can be defined in application Startup class and they are supported by ResponseCache attribute.

Conditions for caching

Response caching middleware page by Microsoft lists conditions that request must meet for caching:

  • 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.
  • The HttpSendFileFeature is not used.
  • The response must not be stale as specified by the Expires header and the max-age and s-maxage cache directives.
  • Response buffering is successful, and the total length of the response is smaller than the configured limit.
  • The response must be cacheable according to the RFC 7234 specifications. For example, the no-store directive must not exist in request or response header fields. See Section 3: Storing Responses in Caches of the RFC document for details.

Problems with cookies

Currently it is not possible to use cookies with response caching. As soon as cookies header is present the caching of request is considered as impossible. Services like Application Insights and Antiforgery system by ASP.NET Core doesn’t work with response caching because they use cookies or set cache headers.

For Application Insights and services like this it is technically possible to create custom middleware based on default one if cookies are still needed for client-side libraries and there are no dependencies with application or session state.

Troubleshooting caching

To some point it is possible to monitor response caching. The library uses ASP.NET Core logging framework to log some activities by response caching middleware. Screen fragment below shows some response caching middleware logs.

aspnet-core-response-caching-log

Sadly it does not report reasons why response was not added to cache. It would greatly help us when testing our response caching in different environments.

If logs are not enough then we can always include projects from response caching GitHub repository to our solution and run these on debugger to see what’s going on.

NB! When debugging response caching with browser make sure that developers tools that come with browser doesn’t set any cookies or cache headers that may affect response caching.

Getting rid of ARR affiinity cookie on Azure Web Sites

If your site doesn’t need Application Request Routing (ARR) you can disable ARR affinity cookie by adding the following block of settings to web.config of your web application.


<system.webServer>
   <httpProtocol>
    <
customHeaders
>
      <
add name="ARR-Disable-Session-Affinity" value="true"
/>
    </
customHeaders
>
  </
httpProtocol
>
</
system.webServer
>

After this modification there is no more ARR cookie in your site available anymore.

Wrapping up

Although I got response caching work I didn’t got it work with Application Insights and other services that work in browser and that use cookies. Still I was able to create simple prototype of public facing application that is cookieless and uses ASP.NET Core response caching. In this example I used memory based cache as I wrote proof-of-concept code. It was easy to set ResponseCache attributes to controller actions I wanted to cache. Troubleshooting was a little bit tricky because response cache logs are limited and browser tools may get to the way with their handling of cache headers. As a conclusion I can say that response caching works okay but needs some improvements to be easier to use.



See also

9 thoughts on “ASP.NET Core Response Cache

Leave a Reply

Your email address will not be published. Required fields are marked *