Nowadays, visiting a website on a desktop or on mobile is our daily routine. Whenever we visit a website or a web application, then we expect that it will render very soon, within 5 to 10 seconds. But unfortunately, there are only a very few websites that take the minimum time to open and the reasons behind this are as following.
- Huge content
- Large and multiple images
- Complex business logic
- Too much server requests
- Poor connection
- Data Access Layer etc.
So, there are several reasons behind the slowness of a website. Now, what we can do to resolve these issues that hamper the performance of the website is, we can use Caching. Yes, using caching, we can cache the data and if the user makes another request for the same type of data, then we don’t need to go and get the same data again from the Server and we don’t need to execute the same logic again and again.
Caching is a technique which helps us to store our data somewhere we already have, and if we require the same data again, then we can get it from the stored data. Data can be saved at client side as well as server side. It totally depends on your requirements, not your choice.
Advantage of caching
If we define the advantage of caching in one word, that will be “Performance”; and it can be achieved to minimize the following things.
- Minimize Server round trips [Hosting Server or Database Server or Any Other Server]
- Minimize Network Traffic [Http Call to Server]
- Avoid repeating same data binding logic
Tips and Tricks when using ASP.NET MVC caching
- Don’t use caching with the data which changes frequently.
- Don’t use caching with Authentication logic.
- Don’t use caching with the data which is unique for the individual user.
- Don’t use caching with data which use very rare like privacy policy page.
- Don’t use caching for an Error page.
- Use caching with data which is used very frequently and same data can be used by all user.
- Always use caching with images or media files.
Generally, we can cache our data using 3 ways in ASP.NET MVC.
- Caching Static Content
- Caching whole or partial page response using OutputCache Attribute
- Caching shared data
CACHING STATIC CONTENTS
While designing any website, we have to use static content. Static Content generally means a piece of content that does not change dynamically, like your images, CSS and JavaScript files etc. These are really heavy files and loading these from the server is a time-consuming task. Do you know how much time is taken to load this static content? It is probably more than 60% of the total time we are consuming. But that is normal. If we use more static content, then it will definitely take more time to load.
Now, the question arises, "Should it take time to download this content every time when we use the same page on the same browser again and again?"
Well, the answer is NO. The downloading process should be the part of the first time, not everytime. So, what we can do is to use Static Content Caching in ASP.NET MVC here to cache our downloaded static contents in memory and when we access the same page again, then rather than going to download the whole static contents again from the server, we just get these from the memory caches.
Let's understand it from a demonstration of how we can achieve static contents caching in ASP.NET MVC.
Here, I have created one ASP.NET MVC 4 application. If you don't know how to create Asp.Net MVC application, just follow my previous articles. After creating an application, go to Index View for the HomeController which is auto-generated using the following codes. Here, you can see that I have just added three images. For this demonstration, I have downloaded these images from Google; you can test it with any images. So, when we run the application, these images will be downloaded from the server every time.
- @{
- ViewBag.Title = "Home Page";
- }
- <style>
- table td {
- padding: 10px;
- border: 2px solid #808080;
- text-align: center;
- }
- </style>
- <div class="jumbotron">
- <h3>Static Content Caching in Asp.Net MVC</h3>
- <table>
- <tr>
- <td><img src="~/Content/img/image1.png" width="300" height="300" />Image 1</td>
- <td><img src="~/Content/img/image2.jpg" width="300" height="300" />Image 2</td>
- <td><img src="~/Content/img/image3.png" width="300" height="300" />Image 3</td>
- </tr>
- </table>
- </div>
Here is the Index Action method which is responsible for rendering our Index View.
-
- public ActionResult Index()
- {
- return View();
- }
Now, it's time to run the application and see what happens. When we run the application and go to developer tools > Networks section, we find that each static content like images, CSS or JS file is being downloaded. But if we refresh the same page, again the same process repeats and same files are downloaded again.
To cache static contents, we have to define a few configurations in our application's Web.Config file as below. Here, you can see, we have defined the file extension with mime type which needs to be cache. To define an age of caching time, we use "cacheControlMaxAge" attribute from "clientCache" and define the time here. For this demonstration, we have used 1 minute.
- <system.webServer>
- <staticContent>
- <clear/>
- <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="00:01:00" />
- <mimeMap fileExtension=".jpg" mimeType="image/jpg"/>
- <mimeMap fileExtension=".png" mimeType="image/jpg"/>
- <mimeMap fileExtension=".css" mimeType="text/css"/>
- <mimeMap fileExtension=".js" mimeType="text/javascript"/>
- </staticContent>
- <validation validateIntegratedModeConfiguration="false" />
- <modules>
- <remove name="ApplicationInsightsWebTracking" />
- <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
- </modules>
- </system.webServer>
Again, it is time to run the application after configuration of caching for static contents. When we run the application for the first time, we see the same screen as above where we will find that each component is being downloaded in a specific time. But if we run the application again within 1 minute, we will see the output as follows.
The following images show that each static component is being retrieved from memory cache rather than downloaded from the server. So, here, we have achieved static caching technique. Now, using this, we can cache static contents and we don't need to download these every time.
OUTPUT CACHING
In ASP.NET MVC, we can cache page response using "OutputCache" attribute. This type of caching is basically used to cache your content generated by an action method. "OutputCache" attribute can be used with activity level or controller level. In Output Caching, we can define the age of caching using duration in seconds. Here, we can also define the location for caching; it can be client side or server side. If we would like to cache the content using some parameter, then it can be defined using "VaryByParam".
So, let us understand it with an example. Now, we will create a new action method as "Index1" as follows. Here, we are creating a list for the blog post which contains 1000 records.
-
- [OutputCache(Duration = 60, VaryByParam = "none", Location = System.Web.UI.OutputCacheLocation.Server)]
- public ActionResult Index1()
- {
- var postModel = new List < BlogPost > ();
-
-
- for (int i = 0; i < 1000; i++) {
- postModel.Add(new BlogPost() {
- PostId = i, Title = "Blog Post Title " + i, Category = "Category " + i, Content = "Content for Blog Post " + i
- });
- }
-
- foreach(var item in postModel)
- {
- if (item.PostId % 2 == 0) {
- item.UserName = "Mukesh Kumar";
- } else {
- item.UserName = "Admin";
- }
- }
-
-
- return View(postModel);
- }
Following is the entity class "BlogPost" for Blog.
- namespace CachingInMVC.Models
- {
- public class BlogPost
- {
- public int PostId { get; set; }
- public string Title { get; set; }
- public string Category { get; set; }
- public string Content { get; set; }
- public string UserName { get; set; }
- }
- }
Now, we need to create a view "Index1" inside the Home folder of the View. This View basically renders all the blog posts in tabular view. We have defined date time to see when our data last updated.
- @model IEnumerable<CachingInMVC.Models.BlogPost>
- @{
- ViewBag.Title = "Home Page";
- }
- <style>
- table td {
- padding: 10px;
- border: 2px solid #808080;
- text-align: center;
- }
- </style>
- <div class="jumbotron">
- <h2>Output Caching in Asp.Net MVC</h2>
- <h3>Last Update Data: <strong style="color:red;">@DateTime.Now.ToString()</strong></h3>
- <br />
- <table style="border:3px solid #808080;">
- <tr>
- <th>ID</th>
- <th>Title</th>
- <th>Category</th>
- <th>Content</th>
- <th>User</th>
- </tr>
- @foreach (var post in Model)
- {
- <tr style="border:1px solid #808080">
- <td>@post.PostId</td>
- <td>@post.Title</td>
- <td>@post.Category</td>
- <td>@post.Content</td>
- <td>@post.UserName</td>
- </tr>
- }
- </table>
- </div>
When we run the application, we will find the output as below where we can see the time forthe last updated data along with the blog post data in tabular format. As above with action method, we are using Output Caching with a duration of 60 seconds. So, if we reload this page again within 60 seconds, then it will not process the whole code for "Index1" and render the data from the cache.
Here, we have reloaded the page again. The page rendered very quickly and we can see, the data is same as the previous result and the time for the last updated data is the same because everything is being retrieved from the server rather than executing the whole code again for "Index1".
COMMON DATA CACHING
Now, if we are required to share common data with multiple action methods and would like to add this type of data in the cache, then we can use "HttpContext.Cache" for setting or getting the data. As we can see with the below code, we are just using the same code which we have already used with the Output Cache example above but here we have removed model data, creating logic inside a method.
At first, we will try to check if the data is available in Cache using the defined key, if data is there then we will render the data on view from the cache and if not then we will get the data from "getThousandsPost" method and bind the model. But make sure, before rendering the data, that we add this data inside the cache so that the next time we don't need to go and execute the same logic again and again.
Getting the data from the cache.
- var postModel = HttpContext.Cache.Get("ThousandsPost") as List < BlogPost > ;
Setting the data in the cache.
- HttpContext.Cache.Insert("ThousandsPost", postModel, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration);
-
-
- public ActionResult Index2()
- {
- var postModel = HttpContext.Cache.Get("ThousandsPost") as List < BlogPost > ;
-
- if (postModel == null) {
- postModel = this.getThousandsPost();
- HttpContext.Cache.Insert("ThousandsPost", postModel, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration);
- }
-
- return View(postModel);
- }
-
- private List < BlogPost > getThousandsPost()
- {
- List < BlogPost > post = new List < BlogPost > ();
-
-
- for (int i = 0; i < 1000; i++)
- {
- post.Add(new BlogPost() {
- PostId = i, Title = "Blog Post Title " + i, Category = "Category " + i, Content = "Content for Blog Post " + i
- });
- }
-
- foreach(var item in post)
- {
- if (item.PostId % 2 == 0) {
- item.UserName = "Mukesh Kumar";
- } else {
- item.UserName = "Admin";
- }
- }
- return post;
- }
Here using the new view "Index2" as follows.
- @model IEnumerable<CachingInMVC.Models.BlogPost>
- @{
- ViewBag.Title = "Home Page";
- }
- <style>
- table td {
- padding: 10px;
- border: 2px solid #808080;
- text-align: center;
- }
- </style>
- <div class="jumbotron">
-
- <h2>Data Caching in Asp.Net MVC</h2>
- <h3>Last Update Data: <strong style="color:red;">@DateTime.Now.ToString()</strong></h3>
- <br />
- <table style="border:3px solid #808080;">
- <tr>
- <th>ID</th>
- <th>Title</th>
- <th>Category</th>
- <th>Content</th>
- <th>User</th>
- </tr>
- @foreach (var post in Model)
- {
- <tr style="border:1px solid #808080">
- <td>@post.PostId</td>
- <td>@post.Title</td>
- <td>@post.Category</td>
- <td>@post.Content</td>
- <td>@post.UserName</td>
- </tr>
- }
- </table>
- </div>
When we run the application, we will notice that our date time is being changed every time. It is because date time is not a part of the cache. We have defined it in the View. To check if the data is loading from cache or not, just put a breakpoint in the "getThousandsPost()" method. You will find that the first time we hit this method and once the data is cached, we will get data from cache next time.
Conclusion
So, today, we learned how to cache our data in ASP.NET MVC. The data can be of any type, it could be static content or page response or common data which needs to be shared.
I hope, this post will help you. Please put your feedback into the comments section which will help me to improve myself for the next post. If you have any doubts, please ask; and if you like this post, please share it with your friends.