Click here to Skip to main content
15,867,308 members
Articles / Web Development / ASP.NET / ASP.NET Core

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

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
21 Mar 2019CPOL5 min read 5.7K   4  
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.

C#
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.

C#
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)].

C#
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:

C#
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.

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
United States United States
Benktesh is a senior software engineer at Sony where he is a software developer/architect. His main focus when coding is quality, simplicity, and scalability and he is experienced in a broad range of subjects (software design, software development process, project management, testing, UI, multithreading, database, mobile development, and more).

Outside of professional work, there are always some side projects he is working on such as simulation modeling of financial, energy and emissions data and writing articles both technical and non-technical (see his blog at https://benktesh.blogspot.com/). While not coding, he is either reading books fiction and/or non-fiction, watching tv shows, trading stocks, and discussing climate change, global warming, emission trading, and traveling to meet people, place, and culture.

Comments and Discussions

 
-- There are no messages in this forum --