Implementing Caching in ASP.NET Core

By FoxLearn 12/14/2024 4:26:01 AM   49
Caching improves application performance by storing frequently accessed data in memory, reducing the need to repeatedly fetch it from the database.

ASP.NET Core supports various caching techniques, including in-memory caching, distributed caching, and response caching, to enhance request handling and optimize resource usage.

Cache is a fast but limited short-term memory used to store frequently accessed data, reducing the need to retrieve it from the database repeatedly. In-memory and distributed caches store data as key-value pairs, improving application performance and efficiency.

How to Implement Caching in ASP.NET Core?

Caching can add complexity to an application, so it’s essential to carefully evaluate its necessity. Applications should not rely solely on cache data; they must be designed to fetch data from the database in case of cache failures. A cache hit occurs when data is retrieved from the cache, while a cache miss happens when the data is unavailable in the cache.

Caches can be maintained locally on each server or centralized for access across multiple servers. In-memory caching works well for single-server setups, but in a Web Farm scenario, a distributed cache is preferred to ensure consistency and scalability.

In-memory caching is the simplest caching method, implemented as a service through dependency injection. It uses the IMemoryCache interface and requires the Microsoft.Extensions.Caching.Memory NuGet package. To implement caching in ASP.NET Core, the in-memory cache service must be registered in the ConfigureServices method of the Startup class.

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // Configure services for the application
    public void ConfigureServices(IServiceCollection services)
    {
        // Add MVC controller and view support
        services.AddControllersWithViews();

        // Register In-memory caching service
        services.AddMemoryCache();
    }

    // Configure the HTTP request pipeline
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            // Display detailed error pages in development mode
            app.UseDeveloperExceptionPage();
        }
        else
        {
            // Redirect to error page in production
            app.UseExceptionHandler("/Home/Error");
        }

        // Serve static files (e.g., images, CSS, JavaScript)
        app.UseStaticFiles();

        // Set up routing
        app.UseRouting();

        // Enable authorization
        app.UseAuthorization();

        // Define the default route
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

We need to inject IMemoryCache interface in the constructor of the controller.

public class PostController : ControllerBase
{
    private readonly ILogger<PostController> _logger;
    private readonly IPostRepository _postRepository;
    private readonly IMemoryCache _memoryCache;

    // Constructor injection for dependencies (logger, repository, and memory cache)
    public PostController(ILogger<PostController> logger, IPostRepository postRepository, IMemoryCache memoryCache)
    {
        _postRepository = postRepository;
        _logger = logger;
        _memoryCache = memoryCache;
    }

    public async Task<List<Post>> GetPostList(int categoryId)
    {
        try
        {
            var key = categoryId.ToString();
            // Check if the post list for the category is already cached
            if (!_memoryCache.TryGetValue(key, out List<Post> postList))
            {
                // If not cached, fetch posts from the repository
                postList = await _postRepository.GetPostListByCategoryId(categoryId);
                // Cache the result for 60 minutes
                var cacheEntryOptions = new MemoryCacheEntryOptions
                {
                    AbsoluteExpiration = DateTime.Now.AddMinutes(60)
                };

                _memoryCache.Set(key, postList, cacheEntryOptions);
            }
            return postList;
        }
        catch (Exception ex)
        {
            // Log errors and rethrow
            _logger.LogError(ex, ex.Message);
            throw ex;
        }
    }
}

In the above code, we first check if the post list is available in the local in-memory cache. If it is, we return the cached data. If not, we query the database to retrieve the list of posts matching the provided categoryId and then store the result in the cache for future use.

Caching improves performance by reducing response time, as cache memory is faster than main memory. It also reduces the utilization of resources such as CPU, network, and databases. In ASP.NET Core, caching enhances the overall user experience by providing faster access to frequently requested data.