In the fast-paced world of web development, performance is essential. Nowadays, Users expect quick responses and seamless experiences from the applications. One of the most effective ways to improve the performance of applications is through caching. This blog will explore what caching is, why it’s important, and how to implement it in ASP.NET Core. We’ll also provide practical examples to help you get started.
Introduction to Caching
Caching is a technique used to store data temporarily so that future requests for that data can be served faster. Instead of fetching data from a database every time, you can retrieve it from the cache. This can significantly reduce the time to load your application.
Why Caching Matters
- Improved Performance: Caching reduces the load on your database and speeds up data retrieval so that the page loads faster.
- Reduced Server Load: By serving cached data, you decrease the number of requests to your server, which can improve scalability.
- Cost Efficiency: Less load on your database and server means reduced operational costs.
Types of Caching in ASP.NET Core
ASP.NET Core provides several caching mechanisms:
- In-Memory Caching: Stores data in the memory of the web server.
- Distributed Caching: Stores data across multiple servers or a dedicated cache server, making it suitable for cloud environments and large-scale applications.
- Response Caching: Caches the entire response of a request so that it reduces the need to generate the response again.
Let’s understand caching with a real example. We have taken an e-commerce example in .Net core services. If you haven’t checked this blog then please check it. So let’s add caching in the ecommerce example.
Real-Time Usage of Caching in an E-Commerce Web Application
Scenario
In an e-commerce web application, users can search for products, view product details and add/remove products to their shopping cart. So this web application has the following features:
- Product Listing Page: This page displays all list of products.
- Product Details Page: This page displays product details.
- Shopping Cart: It Allows users to add, view, and delete their selected products.
Problem
As everyone knows nowadays users are doing more online shopping. So when more users use the website, retrieving product data from the database for every request can lead to slow response. This can negatively impact the user experience, especially during high-traffic periods like Black Friday sales.
Solution
To solve the above problem, we can implement caching to reduce database load and improve response times. We’ll use a combination of in-memory caching for frequently accessed data and distributed caching for session-related data.
Implementation
Step 1: Setting Up the Project
Create a new ASP.NET Core project with ECommerceApp name and install the below packages:
Microsoft.Extensions.Caching.Memory
Microsoft.Extensions.Caching.StackExchangeRedis
Step 2: Configuring Caching Services
In Startup.cs, configure in-memory and Redis caching:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
// In-memory caching
services.AddMemoryCache();
// Redis distributed caching
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379";
options.InstanceName = "ECommerceApp";
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Step 3: Implementing In-Memory Caching for Product Listings
We’ll cache the product listings to reduce database queries.
public class ProductsController : Controller
{
private readonly IMemoryCache _memoryCache;
private readonly ApplicationDbContext _context;
public ProductsController(IMemoryCache memoryCache, ApplicationDbContext context)
{
_memoryCache = memoryCache;
_context = context;
}
public IActionResult Index()
{
string cacheKey = "productList";
if (!_memoryCache.TryGetValue(cacheKey, out List<Product> products))
{
products = _context.Products.ToList(); // Fetch from database
var cacheOptions = new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
};
_memoryCache.Set(cacheKey, products, cacheOptions);
}
return View(products);
}
}
Step 4: Implementing Distributed Caching for Shopping Cart
We’ll use Redis to cache shopping cart data, as it needs to persist across different servers.
public class CartController : Controller
{
private readonly IDistributedCache _distributedCache;
public CartController(IDistributedCache distributedCache)
{
_distributedCache = distributedCache;
}
public async Task<IActionResult> AddToCart(int productId)
{
string cartKey = $"cart_{User.Identity.Name}";
List<int> cart;
var cartData = await _distributedCache.GetStringAsync(cartKey);
if (cartData != null)
{
cart = JsonConvert.DeserializeObject<List<int>>(cartData);
}
else
{
cart = new List<int>();
}
cart.Add(productId);
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
};
await _distributedCache.SetStringAsync(cartKey, JsonConvert.SerializeObject(cart), options);
return RedirectToAction("Index", "Products");
}
public async Task<IActionResult> ViewCart()
{
string cartKey = $"cart_{User.Identity.Name}";
var cartData = await _distributedCache.GetStringAsync(cartKey);
if (cartData != null)
{
var cart = JsonConvert.DeserializeObject<List<int>>(cartData);
var products = _context.Products.Where(p => cart.Contains(p.Id)).ToList();
return View(products);
}
return View(new List<Product>());
}
}
Step 5: Implementing Response Caching for Product Details
We’ll cache the entire response of the product details page for faster access.
public class ProductsController : Controller
{
private readonly ApplicationDbContext _context;
public ProductsController(ApplicationDbContext context)
{
_context = context;
}
[ResponseCache(Duration = 60)] // Duration is in second
public IActionResult Details(int id)
{
var product = _context.Products.Find(id);
if (product == null)
{
return NotFound();
}
return View(product);
}
}
Conclusion
Caching is a powerful tool that can greatly enhance the performance of your ASP.NET Core applications. By reducing the load on your database and server, caching ensures faster response times and a better user experience. Whether you choose in-memory caching for smaller applications, distributed caching for larger or cloud-based applications, or response caching for static content, ASP.NET Core provides robust caching mechanisms to meet your needs.
Implementing caching might seem complex at first, but with the examples provided, you should be well on your way to boosting your application’s performance. Remember, the key to effective caching is understanding your application’s data access patterns and choosing the right caching strategy accordingly.