Implementing Azure Redis Cache To MVC Application

In this article, we are going to learn about caching and how we can implement Azure Redis cache in MVC web application to make the application faster.
 
Table of contents
  • Introduction to Caching
  • Understanding why 
  •  Introduction to Redis Cache
  • Creating a Redis Cache In Microsoft Azure
  • Creating a Client MVC application to use Caching.
  • Health Monitering in Caching
Introduction

Caching is a technique of storing the frequently used data or information in a small memory space, so that when the same data is needed next time, it can directly be retrieved from that memory instead of regenerating the data once again. Caching is extremely important for performance boosting in ASP.NET or MVC application.

Caching places the frequently used data in a small and quick storage, such as the random access memory of the computer.

The flow for how the caching will work is shown in the below diagram.
 
 
The working principles include the following steps,
  • When a user requests a page from the server, first, it will check the cache memory and see if the page is present in cache or not. 
  • If the page is found in the Cache, the third step is to check its expiration time. If it's already expired, then again it will go for regenerating the page.
  • If it's not expired, then the cached content is provided to the user.
  • On the other hand, if the page or content is not found in this case, it will go with the manual process and generate the the page and store that in Cache Memory and then forwarded that to its client.
This is how the entire caching process works.

Here we will learn the Azure Redis Cache provided by the Redis Cache. Azure Redis Cache is based on the popular open-source Redis cache. It gives you access to a secure, dedicated Redis cache, managed by Microsoft, and accessible from any application within Azure.


To work with Azure Redis Cache we have to create a Redis cache in the Azure Portal. Please follow the following steps to create a Redis cache in the portal.
 
Why Caching is Fast??
 
A cache is a small storage area that is closer to the application needing it than the original source.
Accessing this cache is typically faster than accessing a typically stored in memory or on disk.
A memory cache is normally faster to read from than a disk cache, but a memory cache typically does not survive system restarts.
 
 This is very much similar to a library(considered as a DB) and searching a book from this vast memory will be very difficult.so once any item is searched putting that in study table will be searched easily next time.

To use Azure Redis Cache Log in to your Azure portal with your UserId and Password. Once you are logged in it will forward you to the Dashbord.

From the Search menu, search for Database in the Portal as shown below.

 

Once you select the Database option, under that you can search for Redis Cache as shown in the below picture.

 
Select the Redis Cache and create and create a new Redis Cache in the Portal.
While creating Redis cache on the basic of Pricing tier, you will find 3 options:
  • Basic – Single node. Multiple sizes up to 53 GB. 
  • Standard – Two-node Primary/Replica. Multiple sizes up to 53 GB. 99.9% SLA.
  • Premium – Two-node Primary/Replica with up to 10 shards. Multiple sizes from 6 GB to 530 GB. All Standard tier features and more including support for Redis cluster,  Redis persistence, and Azure Virtual Network. 99.9% SLA.
Here I have shown the Premium One with Redis Cluster in the below image.

 
Once you create your Cache just pin it to the Dashbord, so that it will be easy to work on it. So in this way you are able to create a Redis Cache in the Azure Portal.

Now let's create a Client MVC application will  use this cache to store and retrieve the data to boost the performance.
 
So Open Visual Studio and create a new MVC project as shown below.

 
 
Once you create the project, go to NuGet Package and search for Stack Exchange Redis and include that in the project as shown below.


Once that is completed, you will find the references in Reference folder.


Here is my solution Explorer with all the settings.

 
Now go to the Azure Portal and check the access key for the Redis Cache


Once you get the connection string and Key, copy it and take it to the Configfile of your application.
  1. <appSettings>  
  2.   <add key="webpages:Version" value="3.0.0.0" />  
  3.   <add key="webpages:Enabled" value="false" />  
  4.   <add key="ClientValidationEnabled" value="true" />  
  5.   <add key="UnobtrusiveJavaScriptEnabled" value="true" />  
  6.   <add key="RedisCachekey" value="Debendra.redis.cache.windows.net:6980,password=###########KtWeHK9IRK3kmb7uIsdeben&&&&=,ssl=True,abortConnect=False" />  
  7. </appSettings>  
Note
Here I have tempered my password. In the below section I have pasted the connection string; the database for this application is hosted in webAPP in the Azure.
  1. <connectionStrings>  
  2.    <add name="Connect" connectionString="Server=tcp:debendra.database.windows.net,1433;Initial Catalog=EmployeeDetails;User ID=Debendra;Password=Password#####;" providerName="System.Data.SqlClient"/>  
  3.  </connectionStrings>  
Now create an Employee Model to define properties for CRUD operations.
  1. namespace RedisCache.Models  
  2. {  
  3.     public class Employee  
  4.     {  
  5.         public int Id { getset; }  
  6.         public string Name { getset; }  
  7.         public string Address { getset; }  
  8.         public string Company { getset; }  
  9.         public string MobileNo { getset; }  
  10.     }  
  11. }  
As I will work in the CodeFirst Approach, here I have defined my DBContex class as follows.
  1. public class DebendraContext:DbContext  
  2.     {  
  3.         public DebendraContext():base("Connect")  
  4.         {  
  5.   
  6.         }  
  7.         public DbSet<Employee> Employee { getset; }  
  8.   
  9.     }  
Now Create an Index controller and read the connection string and Redis Cache connection value in that.


Now Create an Action Method to add some Employee Data in the same Index Controller.
  1. [HttpPost]  
  2.        public ActionResult AddEmployee(Employee model)  
  3.        {  
  4.            mydbcontext = new DebendraContext();  
  5.            mydbcontext.Employee.Add(model);  
  6.            mydbcontext.SaveChanges();  
  7.   
  8.            return View();  
  9.        }  
  10.        [HttpGet]  
  11.        public ActionResult AddEmployee()  
  12.        {  
  13.             
  14.            return View();  
  15.        }  
Create the  Add Employee View. Here is the attached view code.

  1. @model RedisCache.Models.Employee  
  2.   
  3. @{  
  4.     Layout = null;  
  5. }  
  6.   
  7. <!DOCTYPE html>  
  8.   
  9. <html>  
  10. <head>  
  11.     <meta name="viewport" content="width=device-width" />  
  12.     <title>AddEmployee</title>  
  13. </head>  
  14. <body>  
  15.     @Scripts.Render("~/bundles/jquery")  
  16.     @Scripts.Render("~/bundles/jqueryval")  
  17.       
  18.       
  19.     @using (Html.BeginForm())   
  20.     {  
  21.         @Html.AntiForgeryToken()  
  22.           
  23.         <div class="form-horizontal">  
  24.             <h4>Employee</h4>  
  25.             <hr />  
  26.             @Html.ValidationSummary(true, "", new { @class = "text-danger" })  
  27.             <div class="form-group">  
  28.                 @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })  
  29.                 <div class="col-md-10">  
  30.                     @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })  
  31.                     @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })  
  32.                 </div>  
  33.             </div>  
  34.       
  35.             <div class="form-group">  
  36.                 @Html.LabelFor(model => model.Address, htmlAttributes: new { @class = "control-label col-md-2" })  
  37.                 <div class="col-md-10">  
  38.                     @Html.EditorFor(model => model.Address, new { htmlAttributes = new { @class = "form-control" } })  
  39.                     @Html.ValidationMessageFor(model => model.Address, "", new { @class = "text-danger" })  
  40.                 </div>  
  41.             </div>  
  42.       
  43.             <div class="form-group">  
  44.                 @Html.LabelFor(model => model.Company, htmlAttributes: new { @class = "control-label col-md-2" })  
  45.                 <div class="col-md-10">  
  46.                     @Html.EditorFor(model => model.Company, new { htmlAttributes = new { @class = "form-control" } })  
  47.                     @Html.ValidationMessageFor(model => model.Company, "", new { @class = "text-danger" })  
  48.                 </div>  
  49.             </div>  
  50.       
  51.             <div class="form-group">  
  52.                 @Html.LabelFor(model => model.MobileNo, htmlAttributes: new { @class = "control-label col-md-2" })  
  53.                 <div class="col-md-10">  
  54.                     @Html.EditorFor(model => model.MobileNo, new { htmlAttributes = new { @class = "form-control" } })  
  55.                     @Html.ValidationMessageFor(model => model.MobileNo, "", new { @class = "text-danger" })  
  56.                 </div>  
  57.             </div>  
  58.       
  59.             <div class="form-group">  
  60.                 <div class="col-md-offset-2 col-md-10">  
  61.                     <input type="submit" value="Create" class="btn btn-default" />  
  62.                 </div>  
  63.             </div>  
  64.         </div>  
  65.     }  
  66.       
  67.     <div>  
  68.         @Html.ActionLink("Back to List", "Index")  
  69.     </div>  
  70. </body>  
  71. </html>  
Now run the application to add some employee details to the Database, which will later be cached and shown.

Here I have saved some data in the DataBase in Azure.


Now here is the Main logic to retrieve the data from DataBase and put it in Cache.
  1. public ActionResult Index()  
  2.       {  
  3.             var connect = ConnectionMultiplexer.Connect(cacheConnectionstring);  
  4.             mydbcontext = new DebendraContext();  
  5.             IDatabase Rediscache = connect.GetDatabase();  
  6.             if (string.IsNullOrEmpty(Rediscache.StringGet("EmployeeDetails")))  
  7.             {  
  8.               var liemp = mydbcontext.Employee.ToList();  
  9.              var emplist= JsonConvert.SerializeObject(liemp);  
  10.   
  11.               Rediscache.StringSet("EmployeeDetails", emplist, TimeSpan.FromMinutes(2));  
  12.                 return View(liemp);  
  13.   
  14.             }  
  15.             else  
  16.             {  
  17.                   
  18.                 var detail = JsonConvert.DeserializeObject<List<Employee>>(Rediscache.StringGet("EmployeeDetails"));  
  19.                 return View(detail);  
  20.   
  21.             }  
  22.            
  23.         }  
CODE EXPLANATION
  1. As you know we have installed StackExchange.Redisfor using the Redis Cache in our client application.
  2. The central object in StackExchange.Redis is the ConnectionMultiplexer class in the StackExchange.
  3. The connection to the Azure Redis Cache is managed by the ConnectionMultiplexer class.
  4. This class should be shared and reused throughout your client application, and does not need to be created on a per operation basis.
  5. In these examples abortConnect is set to false, which means that the call succeeds even if a connection to the Azure Redis Cache is not established.  
    1. <appSettings>      
    2.   <add key="RedisCachekey" value="Debendra.redis.cache.windows.net:6980,password=###########KtWeHK9IRK3kmb7uIsdeben&&&&=,ssl=True,abortConnect=False" />      
    3. </appSettings>  
  6. One key feature of ConnectionMultiplexer class is that it automatically restores connectivity to the cache once the network issue or other causes are resolved.
  7. Accessing a redis database is as simple as:
    1. IDatabase db = redis.GetDatabase();   
  8. Once you have the IDatabase, it is simply a case of using the redis API. Note that all methods have both synchronous and asynchronous implementations.
  9. Here I  have used two methods to store and retrieve data using StringGet and StringSet.
  10. Add and retrieve objects from the cache.
    1. // If key1 exists, it is overwritten.    
    2. Rediscache .StringSet("key1""value1");    
    3.     
    4. string value = Rediscache .StringGet("key1");    
    Where Rediscache is the object of IDatabase.

  11. Here we are definging the expiration time  while setting the data. 
    1. Rediscache.StringSet("EmployeeDetails", emplist, TimeSpan.FromMinutes(2));   
Now just run the Index method and check how it works: 

For the first time the Rediscache.StringGet("EmployeeDetails") will be null. Go  inside the If statement, fetch the data, and set it the to the cache object. This object is valid for two minutes. If you make any request within that time period it will go to the else part and just fetch the data from the cache without regenerating again .

So let's request it again. 

 
NOTE
The second request is within two minutes, otherwise it will go  inside the If statement again. Here is the complete Flow.


So we can avoid a lot of  time using Caching.

You can also set rules to get email alerts when a particular threshold is reached for your cached object.


Similarly you can monitor your cache health here as follows.


Conclusion

In this way we can work on Azure Redis Cache  and keep our web application maximized.

Please let me know if  you have any doubts or if I made any mistakes so I can modify and learn from that.