Sunday 15 March 2015

Caching in ASP.NET MVC

Introduction
In this article we will see how we can implement caching in an ASP.NET MVC application.

Background
As ASP.NET web developers, we are mostly involved in developing web pages that are dynamic, i.e. contents coming from databases, Server directories, XML files or getting pulled from some other websites. Caching means to store something in memory that is being used frequently to provide better performance.

Why should we even care about caching. Let us imagine a scenario when the contents of a web page are being pulled from a database. The user asks for contents depending on some criteria. Now if the database is getting changed very frequently that even between two requests of same user, we anticipate database change, then we can in no way cache the data that the user is requesting. But if the database is not getting changed that frequently, we can have some caching in place so that if the user is requesting the same data very frequently, we don't hit the database every time (since we know contents are not changed).
The two keys terms here are frequency and criteria. Frequency is the number of times we are anticipating the user requests for a particular page and criteria is what governs the uniqueness of result that is being displayed on the page.
Frequency is important because we need to figure out the interval in which database is changing and compare it with the frequency of user requests so that we can have caching in place and also make sure that user is not viewing outdated data.
Criteria is important because we need to make sure that we have caching implemented for the page on every unique criteria. It should not be the case that user is requesting contents based on criteria01 and we are showing him the cached results of criteria00 (cached earlier for him).
So with all this theory in mind, let's go ahead and see how we can implement caching in ASP.NET MVC.

Types of Caching
There are two types of caching available in ASP.NET:
  • Page Output Caching
  • Application Caching
Page Output Caching
Page output caching refer to the ability of the web server to cache a certain webpage after user request in its memory so that further requests for the same page will check for the cached page's validity and will not result in resource usage (DB access or file access) and the page will be returned to user from cache.
Let us develop a small application that will demonstrate how we can implement page output caching in ASP.NET MVC. Lets implement a simple view that will show the current time to the user. The Controller code is simply returning the view.

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    }  

In my view, I am showing the current time to the user.

Time is @DateTime.Now.ToString()

If we run this application now, it will show me the current date and time. If we refresh it, the time also gets updated(since there is no caching implemented right now).


Now lets say that this page should be cached for 30 seconds i.e. the time string should not change for 30 seconds. We can achieve this by adorning the action method with the OutputCache attribute. We will pass 2 values in the attribute, First is the Duration of cache and second property VaryByParamVaryByParam="none" specifies that caching doesn't depend on anything.

    public class HomeController : Controller
    {
        [OutputCache(Duration = 30, VaryByParam = "none")]
        public ActionResult Index()
        {
            return View();
        }
    } 

Now if we run the page and refresh it, the time will not change for 30 seconds.

In the above example, we have specified VaryByParam="none". Doing so can lead to a situation where user might see stale data. So if we want to invalidate the cache based on some user selection in screen, then we can specify the VaryByParam's value. So If I want to cache different values for page requests having different query string, I can specify the varyByParam value as the name of that query string.(or any HTML element I want to use).

    public class HomeController : Controller
    {
        [OutputCache(Duration = 30, VaryByParam = "none")]
        public ActionResult Index()
        {
            return View();
        }

        [OutputCache(Duration = 30, VaryByParam = "id")]
        public ActionResult About()
        {
            return View();
        }
     }

So now if I run the application and navigate to About, I will see a cached version for each value of "id" query string.


So what we saw is that we can specify the Duration the page should be cached which is related to the talk about frequency we did earlier. The Duration should be chosen so that during that time we are not expecting any change in data and for the criteria, we saw how we can use VaryByParam to make sure that the output for every different criteria is generated and the cached copy is not just presented to the user.
If we need different output pages based on any/all of the HTML element change, we can specify the list of VaryByParam ="*". Let us look as some other parameters that we can use to customize caching behavior.
  • VaryByParam: List of strings that are sent to server via HTTP POST/GET that are checked to validate cache
  • VaryByCustom: Used for custom output cache requirements
  • VaryByHeader: HTTPs header that determines the cache validity
  • SqlDependency: Defines the Database-tablename pair on which the validity of cache depends

Cache Location

There is one more important property of the OutputCache attribute class which is Location. This property will determine where will the cached data be stored on the server. Possible values for this property can be:
  • Any (Default): Content is cached in three locations: the web server, any proxy servers, and the web browser.
  • Client: Content is cached on the web browser.
  • Server: Content is cached on the web server.
  • ServerAndClient: Content is cached on the web server and and the web browser.
  • None: Content is not cached anywhere.

Smarter ways to specify Cache attribute

If all our action methods have same caching needs then instead of adorning all the individual action methods with this attribute, we can simply go and adorn the controller with this attribute and the caching will be effective on all the aciton methods.

       [OutputCache(Duration = 30, VaryByParam = "none")]
    public class HomeController : Controller
    {   
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult About()
        {
            return View();
        }
     }

In case we have multiple action methods across controllers needing the same caching behavior, we can put this caching values in the web.config and create acacheprofile for it.

<caching>
  <outputCacheSettings>
    <outputCacheProfiles>
      <add name="MyCacheProfile"
           duration="30"
           varyByParam="id"
           location="Any" />
    </outputCacheProfiles>
  </outputCacheSettings>
</caching>

And to use these values in the action methods we just need to specify the CacheProfile name in the action method.

        [OutputCache(CacheProfile = "MyCacheProfile")]
        public ActionResult Index()
        {
            return View();
        }

Partial Page Caching

In asp.net Web forms, we need to create custom user controls in order to achieve partial page caching. Same can be achieved in the MVC world by creating a simple partial view. Caching in that partial view will be governed by the OutputCache attribute associated with the action method responsible to render the data in this partial view.

To Illustrate this let us create one more action method Index2 in the controller. This action will not cache the data. We will render a partial View in this Index2 View. The partial view will cache the time for 10 seconds. Lets look at the action methods for these.

        public ActionResult Index2()
        {
            return View();
        }

        [OutputCache(Duration = 10, VaryByParam = "none")]
        public PartialViewResult PartialTest()
        {
            return PartialView("SamplePartial");
        }

The Index2 View looks like:


@{
    ViewBag.Title = "Caching Demo";
}

Time is @DateTime.Now.ToString()

<br /><br />
Partial page here: @Html.Action("PartialTest")

And finally the partial view code:

Time @DateTime.Now.ToString()

Now if we run the application and navigate to Index2, we can see that the time from the main page is not getting cached but the the time coming from the partial view is getting cached for 10 seconds.

Application Caching

Application data caching is a mechanism for storing the Data objects on cache. It has nothing to do with the page caching. ASP.NET allows us to store the object in a Key-Value based cache. We can use this to store the data that need to cached. Let us work on the same example and try to store the DateTime string in the Application Cache now.

Let us create one action method which will display the date on the view from the application cache.

    public ActionResult Index3()
        {
            if (System.Web.HttpContext.Current.Cache["time"] == null)
            {
                System.Web.HttpContext.Current.Cache["time"] = DateTime.Now;
            }

     ViewBag.Time= ((DateTime)System.Web.HttpContext.Current.Cache["time"]).ToString();
            return View();
        }

The view corresponding to this action method is:


@{
    ViewBag.Title = "Caching Demo";
}

Time is @ViewBag.Time

Now if we run the application and navigate to Index3, we will see the time. But no matter how many times, we refresh this page, the time value will not change. Because the value is coming from the Application cache. Also, we are not invalidating the cache at all.



There are various parameters associated with application data caching that can be used to invalidate the value and control its behavior.
  • Dependencies: Any file or item in cache that invalidates this cache item
  • absoluteExpiration: Absolute time when this object should be removed from cache
  • slidingExpiration: Relative time when this object should be removed from the cache
  • priority: Defines the priority of the item. This is useful when server runs out of memory as in that case it start removing items from cache with lowest priority first
  • onRemoveCallBack: This is the event handler that will be called when the object is removed from cache. It gives us a place to take further actions.

one more helpfull link is Click here

0 comments:

Post a Comment

Topics

ADFS (1) ADO .Net (1) Ajax (1) Angular (43) Angular Js (15) ASP .Net (14) Authentication (4) Azure (3) Breeze.js (1) C# (47) CD (1) CI (2) CloudComputing (2) Coding (7) CQRS (1) CSS (2) Design_Pattern (6) DevOps (4) DI (3) Dotnet (8) DotnetCore (16) Entity Framework (2) ExpressJS (4) Html (4) IIS (1) Javascript (17) Jquery (8) Lamda (3) Linq (11) microservice (3) Mongodb (1) MVC (46) NodeJS (8) React (11) SDLC (1) Sql Server (32) SSIS (3) SSO (1) TypeScript (1) UI (1) UnitTest (1) WCF (14) Web Api (15) Web Service (1) XMl (1)

Dotnet Guru Archives