In ASP.NET MVC, there is an OutputCache filter attribute that you can apply and this is the same concept as output caching in web forms. The output cache enables you to cache the content returned by a controller action.

What is caching?

Now before we proceed further, if you are new to web development you may like to know what is caching, so Caching provides a way of storing frequently accessed data and reusing that data. Practically, this is an effective way for improving web application’s performance. The content, which includes HTML pages, images, files and Web objects, is stored on the local hard drive in order to make it faster for the user to access it, which helps improve the efficiency of the computer and its overall performance.

As we are going to discuss caching related to asp.net MVC means a web application, here caching improves the performance of our web application by storing file, images etc on cache and not hitting the server for the same query again and again, for some duration of time(this duration is defined by us).

So, Web caching works by caching the HTTP responses for requests according to certain rules. Subsequent requests for cached content can then be fulfilled from a cache closer to the user instead of sending the request all the way back to the web server.

Caching in ASP.NET MVC using OutputCache ActionFilter

In ASP.NET MVC, Output caching basically allows you to store the output of a particular controller in the memory. Hence, any future request coming for the same action in that controller will be returned from the cached result. That way, the same content does not need to be generated each and every time the same controller action is invoked.

For example, you have an ASP.NET MVC application, which displays a list of employees, these set of database records must be retrieved from the database by executing a database query, each and every time a user invokes the controller action it returns the EmpList view.

Now, suppose we already know these records are not going to change for a certain interval of time, let's say 50 seconds, hence you can take advantage of the output cache to avoid executing a database query every time a user invokes the same controller action. In this case, the view will be retrieved from the cache instead of being regenerated from the controller action.

[OutputCache(Duration = 50,VaryByParam="none")]
public ActionResult EmpList(){
   var employees = from e in db.Employees
   orderby e.ID
   select e;
   return View(employees);
}

Let's create a project in Visual Studio and take a closer look at caching in MVC :

Create a project in your Visual Studio(2017 in my example), by opening Visual Studio and clicking "File"-> "New"-> "Project". Select MVC template to generate basic HomeController and other details.

In your HomeController place the below code for Index ActionMethod

    [OutputCache(Duration=120, VaryByParam="none")]
    public ActionResult Index()
    {
     ViewBag.Message = DateTime.Now.ToString();
     return View();
    }

In your Index view delete all the auto-generated HTML and place the below code

@{
    ViewBag.Title = "Home Page";
}

@ViewBag.Message

Now, place a break-point inside your Index ActionMethod to check, how many times it was called and when and Debug your code, executing it for the first time will give results like below

output-cache-in-asp-net-mvc-min.png

Considering above example you can see in the image that action method was hit when called for the first time, and time is 1:16 PM in the View, while below is current actual time also, now when we try to Reload the same page within 120 seconds(which is the duration of OutputCache defined by us in above example), here is the output for that

outputcache-in-asp-net-mvc-example-min.png

Now, You can see in the above image, ActionMethod wasn't called when reloaded the page within 120 seconds of first call, and time in the view is still same, i.e 1:16PM while actually, time is 1:17 PM.

So, the above page/view was cached for 120 seconds, which results showed the view more quickly for the second time and also saved an unnecessary call to the server.

Where Content is Cached

By default, when you use the [OutputCache] attribute, content is cached in three locations: the web server, any proxy servers, and the web browser. You can control exactly where content is cached by modifying the Location property of the [OutputCache] attribute.

You can set the Location property to any one of the following values: Any, Client, Downstream, Server, None, ServerAndClient

By default, the Location property has the value Any. However, there are situations in which you might want to cache only on the browser or only on the server. For example, if you are caching information that is personalized for each user then you should not cache the information on the server. If you are displaying different information to different users then you should cache the information only on the client.

Cache Profile

You can create a cache profile in the web.config file. It is an alternative to configuring output cache properties by modifying properties of the [OutputCache] attribute. It offers a couple of important advantages which are as follows.

  • Controls how controller actions cache content in one central location.

  • Creates one cache profile and apply the profile to several controllers or controller actions.

  • Modifies the web configuration file without recompiling your application.

  • Disables caching for an application that has already been deployed to production.

Let’s take a look at a simple example of cache profile by creating the cache profile in web.config file. The <caching> section must appear within the <system.web> section.

<caching>
<outputCacheSettings>
    <outputCacheProfiles>
        <add name="Cache1Hour" duration="3600" varyByParam="none"/>
    </outputCacheProfiles>
</outputCacheSettings>
</caching

then you can use the above cache profile in your C# controller as below

[OutputCache(CacheProfile = "Cache1Hour")]
public ActionResult EmpList(){
   var employees = from e in db.Employees
   orderby e.ID
   select e;
   return View(employees);
}

When not to use OutputCache

Now there can be situations, when you do not need caching at all, for example, you are showing the profile pic of every user who login into your web application, then If a USer-A logs in he can see his profile pic, which is now cached on server and now User-B login, he will see the profile pic of User-A.

Another example can be, if you want to show the name of user's on Login, If Jack login, you will show him "Hi! Jack", that's correct for jack but within the cached time, if James login , he will same message "Hi! Jack" instead of "Hi! James".

To fix the above issues you can save data on Client side and code must be like below

[OutputCache(Duration = 10, VaryByParam = "none", Location=OutputCacheLocation.Client, NoStore=true)]
        public ActionResult Index()
        {
            User u = new User();
            return Content(u.GetName());
        }

In the above code we have used two new values, Location = Client and NoStore=true, OutputCacheLocation.Client means, cache is stored on client side, while NoStore=true is used to intimate the proxy server that should not save any copies of these data on the server.

Varying the Output Cache

In some cases, you might want different cached versions, such as, when you create a detail page, then when you click on the detailed link you will get details for the selected employee. In such cases, you can take advantage of the VaryByParam property of the [OutputCache] attribute. This property enables you to create different cached versions of the very same content when a form parameter or query string parameter varies. So the following will be an implementation of employee details action.

[OutputCache(Duration = int.MaxValue, VaryByParam = "id")]
public ActionResult Details(int id){
   var employee = db.Employees.SingleOrDefault(e => e.ID == id);
   return View(employee);
}

Short description of OutputCache Filter Parameter

Here are the OutputCache Filters with the short description & data-type:

  1. CacheProfile (string) :  Specify the name of the output cache policy which is defined with in <outputCacheSettings> tag of Web.config
  2. Duration (int):  time in secs to cache the content.
  3. Location (OutputCacheLocation): Specify the location of the output to be cached. By default location is Any.
  4. NoStore (bool): Enable/Disable where to use HTTP Cache-Control. This is used only to protect very sensitive data.
  5. Order (int): Gets or sets the order in which the action filters are executed.
  6. SqlDependency (string): the database and table name pairs on which the cache content depends on. The cached data will expire automatically when the data changes in the database.
  7. VaryByContentEncoding (string): the semicolon-separated list of the character set (Content encoding like gzip and deflate) that the output cache uses to vary the cache content.
  8. VaryByCustom (string): Specify the list of custom strings that the output cache uses to vary the cache content.
  9. VaryByHeader(string): Specify the semicolon-separated list of HTTP header names that are used to vary the cache content.
  10. VaryByParam (string): Specify the semicolon-separated list of form POST or query string parameters that are used to vary the cache content. If not specified, the default value is none.

The properties contained in OutputCacheAttribute are almost the same as the properties of the @OutputCache directive. The only @ OutputCache property that is not supported by OutputCacheAttribute is VaryByControl.