Caching is a critical technique to improve the performance and scalability of your web applications by reducing the load on your server and speeding up response times for your users. ASP.NET Core 8 provides various ways to implement caching. This guide covers how to implement caching in an ASP.NET Core 8 Web API, along with best practices and detailed explanations.
Caching is the process of storing data in a temporary storage location to reduce the time and resources needed to access it. It helps to improve application performance by reducing the number of requests to the server and speeding up response times.
ASP.NET Core supports several types of caching:
In-memory caching stores data in the memory of the web server. It's fast and simple to implement but is not suitable for distributed environments.
3.1 Configure Services Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container
builder.Services.AddControllers();
builder.Services.AddMemoryCache();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IMemoryCache _cache;
private readonly ILogger<ProductsController> _logger;
public ProductsController(IMemoryCache cache, ILogger<ProductsController> logger)
{
_cache = cache;
_logger = logger;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetProduct(int id)
{
var cacheKey = $"Product_{id}";
if (!_cache.TryGetValue(cacheKey, out Product product))
{
product = await GetProductFromDatabaseAsync(id); // Assume this is a method to fetch the product from the database
var cacheEntryOptions = new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5),
SlidingExpiration = TimeSpan.FromMinutes(2)
};
_cache.Set(cacheKey, product, cacheEntryOptions);
}
return Ok(product);
}
private Task<Product> GetProductFromDatabaseAsync(int id)
{
// Simulate a database call
return Task.FromResult(new Product { Id = id, Name = "Product " + id });
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
Distributed caching stores data in an external cache such as Redis or SQL Server. It's suitable for web farm environments where multiple instances of the application need to share the same cached data.
4.1 Configure Redis Distributed Cache Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container
builder.Services.AddControllers();
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("Redis");
options.InstanceName = "SampleInstance";
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IDistributedCache _cache;
private readonly ILogger<ProductsController> _logger;
public ProductsController(IDistributedCache cache, ILogger<ProductsController> logger)
{
_cache = cache;
_logger = logger;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetProduct(int id)
{
var cacheKey = $"Product_{id}";
var cachedProduct = await _cache.GetStringAsync(cacheKey);
if (string.IsNullOrEmpty(cachedProduct))
{
var product = await GetProductFromDatabaseAsync(id); // Assume this is a method to fetch the product from the database
var productJson = JsonSerializer.Serialize(product);
var cacheEntryOptions = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5),
SlidingExpiration = TimeSpan.FromMinutes(2)
};
await _cache.SetStringAsync(cacheKey, productJson, cacheEntryOptions);
return Ok(product);
}
var cachedProductObj = JsonSerializer.Deserialize<Product>(cachedProduct);
return Ok(cachedProductObj);
}
private Task<Product> GetProductFromDatabaseAsync(int id)
{
// Simulate a database call
return Task.FromResult(new Product { Id = id, Name = "Product " + id });
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
Response caching reduces the need to generate the same HTTP response multiple times. It stores the responses and serves them directly from the cache for subsequent requests.
5.1 Configure Response Caching Middleware Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container
builder.Services.AddControllers();
builder.Services.AddResponseCaching();
var app = builder.Build();
app.UseResponseCaching();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet("{id}")]
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Client)]
public IActionResult GetProduct(int id)
{
var product = new Product { Id = id, Name = "Product " + id };
return Ok(product);
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
Redis is a popular in-memory data store that can be used as a distributed cache. It is suitable for applications deployed in a web farm or cloud environment where multiple instances of the application need to share cached data.
6.1 Configure Redis Cache Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container
builder.Services.AddControllers();
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("Redis");
options.InstanceName = "SampleInstance";
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IDistributedCache _cache;
private readonly ILogger<ProductsController> _logger;
public ProductsController(IDistributedCache cache, ILogger<ProductsController> logger)
{
_cache = cache;
_logger = logger;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetProduct(int id)
{
var cacheKey = $"Product_{id}";
var cachedProduct = await _cache.GetStringAsync(cacheKey);
if (string.IsNullOrEmpty(cachedProduct))
{
var product = await GetProductFromDatabaseAsync(id); // Assume this is a method to fetch the product from the database
var productJson = JsonSerializer.Serialize(product);
var cacheEntryOptions = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5),
SlidingExpiration = TimeSpan.FromMinutes(2)
};
await _cache.SetStringAsync(cacheKey, productJson, cacheEntryOptions);
return Ok(product);
}
var cachedProductObj = JsonSerializer.Deserialize<Product>(cachedProduct);
return Ok(cachedProductObj);
}
private Task<Product> GetProductFromDatabaseAsync(int id)
{
// Simulate a database call
return Task.FromResult(new Product { Id = id, Name = "Product " + id });
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
Caching is an effective way to improve the performance and scalability of your ASP.NET Core 8 Web API. By using in-memory caching for simple scenarios, distributed caching for scalable environments, and response caching for repeated HTTP responses, you can significantly reduce server load and improve response times. Follow best practices to ensure that your caching strategy is effective and maintains data integrity.