Caching Strategies in Angular and .NET Core

Introduction

Caching is a critical strategy for improving the performance and scalability of web applications. In the context of Angular (a client-side framework) and .NET Core (a server-side framework), caching can be implemented in several ways, each suitable for different scenarios. Here are some common caching strategies for both:

Caching in Angular
 

HTTP Interceptor for Caching HTTP Requests

  • Use an HTTP interceptor to cache HTTP responses. This can help reduce the number of HTTP requests to the server by returning cached responses when appropriate.
  • Example. Create a caching service that stores responses and an HTTP interceptor that checks the cache before making a network request.
    import { Injectable } from '@angular/core';
    import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
    import { Observable, of } from 'rxjs';
    import { tap } from 'rxjs/operators';
    @Injectable()
    export class CacheInterceptor implements HttpInterceptor {
      private cache = new Map<string, any>();
      intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (req.method !== 'GET') {
          return next.handle(req);
        }
        const cachedResponse = this.cache.get(req.url);
        if (cachedResponse) {
          return of(cachedResponse);
        }
        return next.handle(req).pipe(
          tap(event => {
            this.cache.set(req.url, event);
          })
        );
      }
    }
    

Service Worker for Offline Caching

  • Use Angular's built-in service worker support to cache assets and API responses for offline access and faster load times.
  • Example. Enable the Angular service worker by running ng add @angular/pwa and configure caching in the ngsw-config.json file.

Local Storage or IndexedDB

  • Store data in the browser's local storage or IndexedDB for long-term caching. This can be useful for storing user preferences or large datasets that rarely change.
  • Example. Use Angular's localStorage or IndexedDB wrappers to store and retrieve data.
    localStorage.setItem('key', JSON.stringify(data));
    const cachedData = JSON.parse(localStorage.getItem('key'));
    

Caching in .NET Core
 

In-Memory Caching

  • Store cache data in the memory of the web server. This is useful for small amounts of data that change frequently.
  • Example. Use the IMemoryCache interface to cache data in memory.
    public class MyService
    {
        private readonly IMemoryCache _memoryCache;
        public MyService(IMemoryCache memoryCache)
        {
            _memoryCache = memoryCache;
        }
        public string GetData()
        {
            string cacheKey = "myCacheKey";
            if (!_memoryCache.TryGetValue(cacheKey, out string cachedData))
            {
                cachedData = "Data from database";
                _memoryCache.Set(cacheKey, cachedData, TimeSpan.FromMinutes(5));
            }
            return cachedData;
        }
    }
    

Distributed Caching

  • Store cache data in a distributed cache like Redis or SQL Server. This is useful for data that needs to be shared across multiple servers.
  • Example. Use the IDistributedCache interface to cache data in Redis.
    public class MyService
    {
        private readonly IDistributedCache _distributedCache;
        public MyService(IDistributedCache distributedCache)
        {
            _distributedCache = distributedCache;
        }
        public async Task<string> GetDataAsync()
        {
            string cacheKey = "myCacheKey";
            var cachedData = await _distributedCache.GetStringAsync(cacheKey);
            if (cachedData == null)
            {
                cachedData = "Data from database";
                await _distributedCache.SetStringAsync(cacheKey, cachedData, new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
                });
            }
            return cachedData;
        }
    }
    

Response Caching Middleware

  • Cache HTTP responses at the server level to improve performance for subsequent requests.
  • Example. Configure response caching middleware in the Startup class.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddResponseCaching();
    }
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseResponseCaching();
        app.Use(async (context, next) =>
        {
            context.Response.GetTypedHeaders().CacheControl =
                new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
                {
                    Public = true,
                    MaxAge = TimeSpan.FromSeconds(60)
                };
            await next();
        });
    }
    

Combining Angular and .NET Core Caching

To achieve optimal performance, you can combine caching strategies in Angular and .NET Core:

Client-Side Caching

  • Cache static assets and API responses in Angular using service workers or local storage.
  • Implement HTTP interceptors to cache responses and reduce server requests.

Server-Side Caching

  • Use in-memory or distributed caching in .NET Core to store frequently accessed data.
  • Implement response caching middleware to cache entire HTTP responses.

Conclusion

By leveraging both client-side and server-side caching, you can create a robust and efficient caching strategy that significantly enhances the performance and scalability of your Angular and .NET Core applications.