Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Handling Caching with ResponseCache attribute in the .NET Core MVC web application

0.00/5 (No votes)
21 Mar 2019 1  
The caching of HTTP response implies that when an HTTP request is made, the response generated by the server is stored in some place by the browser or the server for potential re-use in successive HTTP request for the same resource.

The caching of HTTP response implies that when an HTTP request is made, the response generated by the server is stored in some place by the browser or the server for potential re-use in successive HTTP request for the same resource. In essence, we are storing the generated response and reusing that response to the subsequent requests for a certain duration. The storage can take place in the client side such as a browser or server side itself. When stored at client caching of an HTTP response reduces the number of requests a client such as a browser or proxy makes to a web server. The browser caching behavior in a web-application is generally controlled by HTTP headers that specify how or not the client must cache responses.

In a web application, there is a need to cache certain request for performance. For example, the performance of the application improves by caching resources that rarely change or changes infrequently as this would remove the unnecessary work from the server. On the other hand, certain resources that are likely to change frequently must not be cached to provide the up-to-date resource to the client. Thus, there is a need to cache certain resource and disallow caching of some other resources.

In a typical HTTP request and response, caching is controlled by 'Cache-Control" header. The headers can tell what to cache and for how long to both the client and the server. In a .NET Core MVC, the caching can be specified using ResponseCache attribute.

A simple way to add a caching behavior to an action method is to decorate the method with ResponseCache attribute. In order for the client to cache a response, an action method within the controller can be decorated with [ResponseCache(Duration = 30)]. This attribute will flag the client to cache the response for 30 seconds. The caching of the response can be disabled by decorating the method with [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)] attribute in which NoStore flag is set to true and CachingLocation is set to None.

The example below shows that the responses from the Index() and Privacy() methods are cached for 30 seconds. The idea is that the content generated by these methods are expected to remain static. The response from GetValue() method is not supposed to cache as the response from this method is expected to change from one request to another. Thus,disabling of cache is indicated by NoStore = true and Location = ResponseCacheLocation.None.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace Web.Controllers
{
    public class HomeController : Controller
    {
        [ResponseCache(Duration = 30)]
        public async Task<actionresult> Index()
        {
            return View();
        }
        [ResponseCache(Duration = 30)]
        public async Task<actionresult> Privacy()
        {
            return View();
        }

        [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
        public async Task<actionresult> GetValue()
        {
            return View();
        }
    }
}

In order to use the same caching behavior for all the action method of a class, the [ResponseCache] attribute can be decorated at the class level. For example, in the code below, responses from each of the action methods would be cached for 30 seconds.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace Web.Controllers
{
    [ResponseCache(Duration = 30)]
    public class HomeController : Controller
    {
        public async Task<actionresult> Index()
        {
            return View();
        }

        public async Task<actionresult> Privacy()
        {
            return View();
        }

        public async Task<actionresult> GetValue()
        {
            return View();
        }
    }
}

It is also possible to override the caching behavior for one or more methods. For example, in the code below, the class level caching behavior is to allow caching of response for 30 seconds, but by decorating a single method with [ResponseCache], the caching of method's response can be altered. In this case, the response of GetValue() is never cached because of the [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)].

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace Web.Controllers
{
    [ResponseCache(Duration = 30)]
    public class HomeController : Controller
    {
        public async Task<actionresult> Index()
        {
            return View();
        }
        public async Task<actionresult> Privacy()
        {
            return View();
        }

        [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
        public async Task<actionresult> GetValue()
        {
            return View();
        }
    }
}

In the examples above there were two primary caching behaviors, one that indicates caching and another that indicates no-caching. The parameters ResponseCachelocation, NoStore and Duration can be put into a profile and used in the .NET Core MVC and reuse those within the attribute. Let's assume that there are types of behavior for caching in an application as follow:

  • Default - every response is cached for 60 seconds
  • Never - no response is ever cached.

These two behaviors can be made into a caching profile. The ResponseCache can be set-up in the StartUp.cs file in the MVC middleware inside ConfigureServices(IServiceCollection services) method shown below:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace Web
{
    public class Startup
    {
        //....
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<cookiepolicyoptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
            services.AddTransient<iwebmanager webmanager="">();
            services.AddMvc( options =>
            {
                options.CacheProfiles.Add("Default",
                       new CacheProfile()
                       {
                           Duration = 60
                       });
                options.CacheProfiles.Add("Never",
                    new CacheProfile()
                    {
                        Location = ResponseCacheLocation.None,
                        NoStore = true
                    });

            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

         ///....
    }
}

In the code above, two caching profiles were configured respectively named “Default’ and “Never”. The "Default' caching profile is intended to cache the response for 30 seconds as indicated by the following line:

{
       Duration = 30
}

The "Never" caching profile is intended to request that no caching of response should occur where are specified by the following:

{
       Location = ResponseCacheLocation.None,
       NoStore = true
}

Now that the caching profiles are set up at MVC, their action methods can start using it by specifying the name of the profile rather than by supplying caching related parameters. For example, for allowing caching, the attribute is [ResponseCache(CacheProfileName = "Default")] and for not allowing caching, the attribute is [ResponseCache(CacheProfileName = "Never")]. The HomeController class from the example above, can now be modified by decorating the HomeController class with [ResponseCache(CacheProfileName = "Default")] at and GetValue() method with [ResponseCache(CacheProfileName = "Never")] attribute.

using Microsoft.AspNetCore.Mvc;
namespace Web.Controllers
{
    [ResponseCache(CacheProfileName = "Default")]
    public class HomeController : Controller
    {
        private IWebManager _manager;
        public HomeController(IWebManager mgr)
        {
            _manager = mgr;
        }
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Privacy()
        {
            return View();
        }

        [ResponseCache(CacheProfileName = "Never")]
        public IActionResult GetValue()
        {
            return Content(_manager.GetValue());
        }
    }
}

With this change above, all the methods inside the home controller will start using ‘Default’ cache profile which essentially will cache the response for sixty seconds.

We have two get methods in the HomeController. The first method is Index() which returns a list of products and another method is Privacy() which returns a view with privacy-related content, and finally a third method, GetValue() which returns some values. In these cases, let's also assume that product types are relatively constant i.e., their data do not change often. However, the products keep changing depending on inventory and therefore not suitable for caching. Because, if we cache the product and the inventory of the product increased or decreased in the database, then the cached response would be incorrect.

We can verify that the caching is working, by doing the following:

  • Run the app locally and go to the index method.
  • Open PostMan or ARC to get the request and see the response header. The response header says that the caching has been used.
  • Now comment out the attribute response related.
  • Recreate the request in PostMan and review the response header.

Resources: Response caching in ASP.NET Core. Available at: https://docs.microsoft.com/en-us/aspnet/core/performance/caching/response?view=aspnetcore-2.2

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here