
পূর্বের আর্টিকেল: ASP.NET Core Performance Hacks: Async, Profiling & Optimization Techniques (Part - 26 of 40)
সারসংক্ষেপ
দ্য ক্যাশিং রেভোলিউশন
ক্যাশিং ফান্ডামেন্টালস & আর্কিটেকচার
ইন-মেমরি ক্যাশিং ডিপ ডাইভ
Redis দিয়ে ডিস্ট্রিবিউটেড ক্যাশিং
রেসপন্স ক্যাশিং স্ট্র্যাটেজি
রিয়েল-ওয়ার্ল্ড ই-কমার্স ক্যাশিং
ক্যাশ ইনভ্যালিডেশন প্যাটার্ন
পারফরম্যান্স মনিটরিং & অ্যানালিটিক্স
অ্যাডভান্সড ক্যাশিং প্যাটার্ন
সিকিউরিটি & বেস্ট প্র্যাকটিস
টেস্টিং ক্যাশিং স্ট্র্যাটেজি
প্রোডাকশন ডিপ্লয়মেন্ট
১. দ্য ক্যাশিং রেভোলিউশন
কেন ক্যাশিং আপনার পারফরম্যান্স সিলভার বুলেট
ক্যাশিং অ্যাপ্লিকেশন পারফরম্যান্স ট্রান্সফর্ম করে ডাটাবেস লোড কমিয়ে, রেসপন্স টাইম ডিক্রিজ করে, এবং স্কেলেবিলিটি উন্নত করে। আধুনিক ওয়েব অ্যাপ্লিকেশনে, ক্যাশিং শুধু অপ্টিমাইজেশন নয়—এটি একটি необходиতা।
রিয়েল-লাইফ এনালজি: একটি ব্যস্ত কফি শপ কল্পনা করুন। ক্যাশিং ছাড়া, প্রতিটি কাস্টমার অর্ডার থাকবে:
সাপ্লায়ার ওয়ারহাউসে যেতে (ডাটাবেস)
বিনস সিলেক্ট করতে (কোয়েরি এক্সিকিউশন)
তাজা পিড়া (ডেটা প্রসেসিং)
ইন্ডিভিজুয়ালি ব্রিউ করা (রেসপন্স জেনারেশন)
ক্যাশিংসহ, জনপ্রিয় ড্রিংকগুলো প্রি-প্রিপেয়ারড থাকে এবং ইনস্ট্যান্ট সার্ভ করার জন্য রেডি!
// পারফরম্যান্স ইমপ্যাক্ট ডেমো
public class ProductServiceWithoutCaching{
private readonly ApplicationDbContext _context;
public async Task<Product> GetProductAsync(int id) {
// প্রতিটি কল ডাটাবেস হিট করে - SLOW!
return await _context.Products
.Include(p => p.Category)
.Include(p => p.Reviews)
.FirstOrDefaultAsync(p => p.Id == id);
}
}
public class ProductServiceWithCaching{
private readonly ApplicationDbContext _context;
private readonly IMemoryCache _cache;
public async Task<Product> GetProductAsync(int id) {
// প্রথমে ক্যাশ ট্রাই - FAST!
if (_cache.TryGetValue($"product_{id}", out Product product)) return product;
// ক্যাশ মিস - ডাটাবেস থেকে পান
product = await _context.Products
.Include(p => p.Category)
.Include(p => p.Reviews)
.FirstOrDefaultAsync(p => p.Id == id);
// ভবিষ্যতের রিকোয়েস্টের জন্য ক্যাশে স্টোর
_cache.Set($"product_{id}", product, TimeSpan.FromMinutes(30));
return product;
}
}
ক্যাশিং পারফরম্যান্স ইমপ্যাক্ট
| সিনেরিও | ক্যাশিং ছাড়া | ক্যাশিংসহ | উন্নতি |
|---|---|---|---|
| ডাটাবেস কোয়েরি | 1000 queries/sec | 50 queries/sec | 20x reduction |
| রেসপন্স টাইম | 200ms | 5ms | 40x faster |
| সার্ভার লোড | 80% CPU | 20% CPU | 4x reduction |
| কস্ট | $1000/month | $250/month | 75% savings |
২. ক্যাশিং ফান্ডামেন্টালস & আর্কিটেকচার
ক্যাশিং আর্কিটেকচার প্যাটার্ন
// কমপ্রিহেনসিভ ক্যাশিং সার্ভিস ইন্টারফেস
public interface ICacheService{
Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null);
Task<T> GetAsync<T>(string key);
Task SetAsync<T>(string key, T value, TimeSpan? expiration = null);
Task RemoveAsync(string key);
Task<bool> ExistsAsync(string key);
Task RemoveByPatternAsync(string pattern);
}
// একাধিক ক্যাশ প্রোভাইডার সাপোর্ট করে ইমপ্লিমেন্টেশন
public class CacheService : ICacheService{
private readonly IMemoryCache _memoryCache;
private readonly IDistributedCache _distributedCache;
private readonly ILogger<CacheService> _logger;
private readonly CacheSettings _settings;
public CacheService(IMemoryCache memoryCache, IDistributedCache distributedCache, ILogger<CacheService> logger, IOptions<CacheSettings> settings) {
_memoryCache = memoryCache;
_distributedCache = distributedCache;
_logger = logger;
_settings = settings.Value;
}
public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null) {
try {
// প্রথমে মেমরি ক্যাশ ট্রাই (ফাস্টেস্ট)
if (_memoryCache.TryGetValue(key, out T cachedValue)) {
_logger.LogDebug("Memory cache hit for key: {Key}", key);
return cachedValue;
}
// ডিস্ট্রিবিউটেড ক্যাশ ট্রাই
var distributedValue = await _distributedCache.GetAsync<T>(key);
if (distributedValue != null) {
_logger.LogDebug("Distributed cache hit for key: {Key}", key);
// পরবর্তী ফাস্টার এক্সেসের জন্য মেমরি ক্যাশে পপুলেট
var memoryCacheOptions = new MemoryCacheEntryOptions {
AbsoluteExpirationRelativeToNow = expiration ?? _settings.DefaultExpiration
};
_memoryCache.Set(key, distributedValue, memoryCacheOptions);
return distributedValue;
}
// ক্যাশ মিস - ফ্যাক্টরি মেথড এক্সিকিউট
_logger.LogDebug("Cache miss for key: {Key}, executing factory", key);
var value = await factory();
if (value != null) {
// দুটো ক্যাশেই স্টোর
var cacheExpiration = expiration ?? _settings.DefaultExpiration;
// মেমরি ক্যাশ
var memoryOptions = new MemoryCacheEntryOptions {
AbsoluteExpirationRelativeToNow = cacheExpiration
};
_memoryCache.Set(key, value, memoryOptions);
// ডিস্ট্রিবিউটেড ক্যাশ
var distributedOptions = new DistributedCacheEntryOptions {
AbsoluteExpirationRelativeToNow = cacheExpiration
};
await _distributedCache.SetAsync(key, value, distributedOptions);
}
return value;
} catch (Exception ex) {
_logger.LogError(ex, "Error in GetOrCreateAsync for key: {Key}", key);
// ক্যাশিং ফেইল হলে, ফ্যাক্টরি মেথডে ফলব্যাক
return await factory();
}
}
// ... অন্যান্য মেথড ইমপ্লিমেন্টেশন
}
// কনফিগারেশন মডেল
public class CacheSettings{
public TimeSpan DefaultExpiration { get; set; } = TimeSpan.FromMinutes(30);
public int MemoryCacheExpirationMinutes { get; set; } = 10;
public string RedisConnectionString { get; set; }
public bool UseDistributedCache { get; set; } = true;
}
Program.cs-এ ক্যাশ কনফিগারেশন
// Program.cs - কমপ্রিহেনসিভ ক্যাশিং সেটআপ
var builder = WebApplication.CreateBuilder(args);
// ক্যাশ সেটিংস কনফিগার
builder.Services.Configure<CacheSettings>(builder.Configuration.GetSection("CacheSettings"));
// মেমরি ক্যাশ যোগ করুন (সদা উপলব্ধ)
builder.Services.AddMemoryCache(options =>{
options.SizeLimit = 1024 * 1024 * 100; // 100MB লিমিট
options.CompactionPercentage = 0.25; // ২৫% ফুল হলে কমপ্যাক্ট
});
// কনফিগারেশন অনুযায়ী ডিস্ট্রিবিউটেড ক্যাশ যোগ করুন
var cacheSettings = builder.Configuration.GetSection("CacheSettings").Get<CacheSettings>();
if (cacheSettings.UseDistributedCache && !string.IsNullOrEmpty(cacheSettings.RedisConnectionString)){
builder.Services.AddStackExchangeRedisCache(options => {
options.Configuration = cacheSettings.RedisConnectionString;
options.InstanceName = "MyApp:";
});
// ডাইরেক্ট অ্যাক্সেসের জন্য Redis কানেকশন রেজিস্টার
builder.Services.AddSingleton<IConnectionMultiplexer>(sp => ConnectionMultiplexer.Connect(cacheSettings.RedisConnectionString));
}else{
// ডেভেলপমেন্টের জন্য ডিস্ট্রিবিউটেড মেমরি ক্যাশে ফলব্যাক
builder.Services.AddDistributedMemoryCache();
}
// ক্যাশিং সার্ভিস রেজিস্টার
builder.Services.AddScoped<ICacheService, CacheService>();
builder.Services.AddScoped<IProductCacheService, ProductCacheService>();
builder.Services.AddScoped<IUserCacheService, UserCacheService>();
// রেসপন্স ক্যাশিং যোগ করুন
builder.Services.AddResponseCaching(options =>{
options.MaximumBodySize = 1024 * 1024; // 1MB
options.UseCaseSensitivePaths = false;
});
// আউটপুট ক্যাশিং যোগ করুন (ASP.NET Core 7+)
builder.Services.AddOutputCache(options =>{
options.AddBasePolicy(builder => builder.Expire(TimeSpan.FromMinutes(10)));
options.AddPolicy("Products", builder => builder.Expire(TimeSpan.FromMinutes(5)) .Tag("products"));
});
var app = builder.Build();
// রেসপন্স ক্যাশিং মিডলওয়ার ব্যবহার
app.UseResponseCaching();
// আউটপুট ক্যাশিং মিডলওয়ার ব্যবহার
app.UseOutputCache();
app.Run();
৩. ইন-মেমরি ক্যাশিং ডিপ ডাইভ
অ্যাডভান্সড মেমরি ক্যাশ প্যাটার্ন
// স্মার্ট মেমরি ক্যাশ সার্ভিস উইথ ইভিকশন পলিসি
public class SmartMemoryCacheService{
private readonly IMemoryCache _cache;
private readonly ILogger<SmartMemoryCacheService> _logger;
private readonly ConcurrentDictionary<string, CacheEntryInfo> _cacheEntries;
public SmartMemoryCacheService(IMemoryCache cache, ILogger<SmartMemoryCacheService> logger) {
_cache = cache;
_logger = logger;
_cacheEntries = new ConcurrentDictionary<string, CacheEntryInfo>();
}
public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, CacheOptions options = null) {
options ??= new CacheOptions();
if (_cache.TryGetValue(key, out T cachedValue)) {
// অ্যাক্সেস স্ট্যাটিস্টিক্স আপডেট
UpdateAccessStats(key);
_logger.LogDebug("Cache hit for {Key}", key);
return cachedValue;
}
// ক্যাশ মিস - ফ্যাক্টরি মেথড ব্যবহার
_logger.LogDebug("Cache miss for {Key}, executing factory", key);
// ক্যাশ স্ট্যামپیড প্রোটেকশন ইমপ্লিমেন্ট
var semaphore = new SemaphoreSlim(1, 1);
await semaphore.WaitAsync();
try {
// লক আকোয়ার করার পর ডাবল-চেক
if (_cache.TryGetValue(key, out cachedValue)) {
UpdateAccessStats(key);
return cachedValue;
}
var value = await factory();
if (value != null) {
var cacheEntryOptions = CreateCacheEntryOptions(options);
// ইভিকশনের জন্য কলব্যাক রেজিস্টার
cacheEntryOptions.RegisterPostEvictionCallback(EvictionCallback);
_cache.Set(key, value, cacheEntryOptions);
// ক্যাশ এন্ট্রি ট্র্যাক
_cacheEntries[key] = new CacheEntryInfo {
Key = key,
Created = DateTime.UtcNow,
LastAccessed = DateTime.UtcNow,
AccessCount = 1,
Size = EstimateSize(value),
Options = options
};
}
return value;
} finally {
semaphore.Release();
}
}
// ... অন্যান্য মেথড
}
// সাপোর্টিং ক্লাসেস
public class CacheOptions{
public TimeSpan? AbsoluteExpiration { get; set; }
public TimeSpan? SlidingExpiration { get; set; }
public TimeSpan MaxIdleTime { get; set; } = TimeSpan.FromHours(24);
public long Size { get; set; } = 1;
public CacheItemPriority? Priority { get; set; }
}
public class CacheEntryInfo{
public string Key { get; set; }
public DateTime Created { get; set; }
public DateTime LastAccessed { get; set; }
public long AccessCount { get; set; }
public long Size { get; set; }
public CacheOptions Options { get; set; }
}
public class CacheStatistics{
public int TotalEntries { get; set; }
public long TotalSize { get; set; }
public double HitRate { get; set; }
public IEnumerable<CacheEntryInfo> MostAccessed { get; set; }
public IEnumerable<CacheEntryInfo> OldestEntries { get; set; }
}
রিয়েল-ওয়ার্ল্ড মেমরি ক্যাশ ইমপ্লিমেন্টেশন
// ই-কমার্স প্রোডাক্ট ক্যাটালগ উইথ ইন্টেলিজেন্ট ক্যাশিং
public class ProductCatalogService{
private readonly IProductRepository _productRepository;
private readonly SmartMemoryCacheService _cache;
private readonly ILogger<ProductCatalogService> _logger;
private const string ProductsByCategoryKey = "products_category_{0}";
private const string FeaturedProductsKey = "products_featured";
private const string ProductDetailsKey = "product_{0}";
private const string ProductSearchKey = "products_search_{0}";
public ProductCatalogService(IProductRepository productRepository, SmartMemoryCacheService cache, ILogger<ProductCatalogService> logger) {
_productRepository = productRepository;
_cache = cache;
_logger = logger;
}
public async Task<List<Product>> GetProductsByCategoryAsync(int categoryId, int page = 1, int pageSize = 20) {
var cacheKey = string.Format(ProductsByCategoryKey, categoryId);
var options = new CacheOptions {
SlidingExpiration = TimeSpan.FromMinutes(15),
AbsoluteExpiration = DateTimeOffset.Now.AddHours(1)
};
return await _cache.GetOrCreateAsync(cacheKey, async () => {
_logger.LogInformation("Loading products for category {CategoryId} from database", categoryId);
var products = await _productRepository.GetProductsByCategoryAsync(categoryId, page, pageSize);
// إندিভিজুয়াল প্রোডাক্ট ডিটেইলস প্রি-ক্যাশ
foreach (var product in products) {
var productCacheKey = string.Format(ProductDetailsKey, product.Id);
await _cache.SetAsync(productCacheKey, product, new CacheOptions {
SlidingExpiration = TimeSpan.FromMinutes(30)
});
}
return products;
}, options);
}
// ... অন্যান্য মেথড
}
৪. Redis দিয়ে ডিস্ট্রিবিউটেড ক্যাশিং
Redis কনফিগারেশন এবং অ্যাডভান্সড প্যাটার্ন
// অ্যাডভান্সড Redis ক্যাশ সার্ভিস
public class RedisCacheService : IDistributedCacheService{
private readonly IConnectionMultiplexer _redis;
private readonly IDatabase _database;
private readonly ILogger<RedisCacheService> _logger;
private readonly ISerializer _serializer;
public RedisCacheService(IConnectionMultiplexer redis, ILogger<RedisCacheService> logger, ISerializer serializer) {
_redis = redis;
_database = redis.GetDatabase();
_logger = logger;
_serializer = serializer;
}
public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, DistributedCacheEntryOptions options = null) {
options ??= new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30) };
try {
// Redis থেকে পেতে চেষ্টা
var cachedValue = await GetAsync<T>(key);
if (cachedValue != null) {
_logger.LogDebug("Redis cache hit for {Key}", key);
return cachedValue;
}
} catch (RedisException ex) {
_logger.LogWarning(ex, "Redis unavailable for key {Key}, falling back to factory", key);
return await factory();
}
// ক্যাশ মিস - ফ্যাক্টরি এক্সিকিউট
_logger.LogDebug("Redis cache miss for {Key}", key);
var value = await factory();
if (value != null) {
await SetAsync(key, value, options);
}
return value;
}
// ... অন্যান্য মেথড
}
// Redis ক্যাশ ইনফরমেশন মডেল
public class RedisCacheInfo{
public long UsedMemory { get; set; }
public string UsedMemoryHuman { get; set; }
public long KeyCount { get; set; }
public double HitRate { get; set; }
public int ConnectedClients { get; set; }
}
// Redis-এর জন্য JSON সিরিয়ালাইজার
public class JsonSerializer : ISerializer{
private readonly JsonSerializerOptions _options;
public JsonSerializer() {
_options = new JsonSerializerOptions {
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false
};
}
public T Deserialize<T>(string data) {
return JsonSerializer.Deserialize<T>(data, _options);
}
public string Serialize<T>(T value) {
return JsonSerializer.Serialize(value, _options);
}
}
public interface ISerializer{
T Deserialize<T>(string data);
string Serialize<T>(T value);
}
হাই-ট্রাফিক অ্যাপ্লিকেশনের জন্য রিয়েল-ওয়ার্ল্ড Redis ইমপ্লিমেন্টেশন
// Redis দিয়ে সেশন ম্যানেজমেন্ট
public class RedisSessionService{
private readonly IDistributedCacheService _cache;
private readonly ILogger<RedisSessionService> _logger;
private const string SessionKeyPrefix = "session:";
private const string UserSessionsKey = "user_sessions:";
public RedisSessionService(IDistributedCacheService cache, ILogger<RedisSessionService> logger) {
_cache = cache;
_logger = logger;
}
public async Task<Session> CreateSessionAsync(int userId, SessionData data) {
var sessionId = GenerateSessionId();
var sessionKey = GetSessionKey(sessionId);
var userSessionsKey = GetUserSessionsKey(userId);
var session = new Session {
Id = sessionId,
UserId = userId,
CreatedAt = DateTime.UtcNow,
LastAccessed = DateTime.UtcNow,
Data = data,
ExpiresAt = DateTime.UtcNow.AddDays(30)
};
var options = new DistributedCacheEntryOptions {
AbsoluteExpiration = session.ExpiresAt
};
// সেশন স্টোর
await _cache.SetAsync(sessionKey, session, options);
// ইউজারের সেশন সেটে যোগ
await _cache.SetAddAsync(userSessionsKey, sessionId);
_logger.LogInformation("Created session {SessionId} for user {UserId}", sessionId, userId);
return session;
}
// ... অন্যান্য মেথড
}
// সেশন মডেলস
public class Session{
public string Id { get; set; }
public int UserId { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime LastAccessed { get; set; }
public DateTime ExpiresAt { get; set; }
public SessionData Data { get; set; }
}
public class SessionData{
public string UserAgent { get; set; }
public string IPAddress { get; set; }
public string Location { get; set; }
public Dictionary<string, object> CustomData { get; set; } = new();
}
৫. রেসপন্স ক্যাশিং স্ট্র্যাটেজি
কমপ্রিহেনসিভ রেসপন্স ক্যাশিং ইমপ্লিমেন্টেশন
// অ্যাডভান্সড রেসপন্স ক্যাশিং সার্ভিস
public class ResponseCachingService{
private readonly IResponseCache _responseCache;
private readonly ILogger<ResponseCachingService> _logger;
public ResponseCachingService(IResponseCache responseCache, ILogger<ResponseCachingService> logger) {
_responseCache = responseCache;
_logger = logger;
}
public async Task CacheResponseAsync(string cacheKey, object response, TimeSpan timeToLive) {
try {
if (response == null) return;
var cachedResponse = new CachedResponse {
Content = response,
Created = DateTime.UtcNow,
Expires = DateTime.UtcNow.Add(timeToLive)
};
await _responseCache.SetAsync(cacheKey, cachedResponse, timeToLive);
_logger.LogDebug("Cached response for key {CacheKey}, TTL: {TimeToLive}", cacheKey, timeToLive);
} catch (Exception ex) {
_logger.LogError(ex, "Error caching response for key {CacheKey}", cacheKey);
}
}
// ... অন্যান্য মেথড
}
// ক্যাশড রেসপন্স মডেল
public class CachedResponse{
public object Content { get; set; }
public DateTime Created { get; set; }
public DateTime Expires { get; set; }
public string ETag { get; set; }
public DateTime? LastModified { get; set; }
}
// রেসপন্স ক্যাশ ইমপ্লিমেন্টেশন
public interface IResponseCache{
Task SetAsync<T>(string key, T value, TimeSpan timeToLive);
Task<T> GetAsync<T>(string key);
Task RemoveAsync(string key);
Task RemoveByPatternAsync(string pattern);
}
// রেসপন্স ক্যাশিং এর জন্য অ্যাকশন ফিল্টার
public class ResponseCachingAttribute : Attribute, IAsyncActionFilter{
private readonly int _duration;
private readonly bool _perUser;
private readonly string[] _varyBy;
public ResponseCachingAttribute(int duration, bool perUser = false, params string[] varyBy) {
_duration = duration;
_perUser = perUser;
_varyBy = varyBy;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) {
var cacheService = context.HttpContext.RequestServices.GetService<ResponseCachingService>();
var httpContext = context.HttpContext;
// ক্যাশ কী জেনারেট
var cacheKey = GenerateCacheKey(httpContext, _perUser, _varyBy);
// ক্যাশ থেকে পেতে চেষ্টা
var cachedResponse = await cacheService.GetCachedResponseAsync(cacheKey);
if (cachedResponse != null) {
// ক্যাশড রেসপন্স রিটার্ন
context.Result = new ObjectResult(cachedResponse.Content) { StatusCode = 200 };
// ক্যাশ হেডার সেট
if (!string.IsNullOrEmpty(cachedResponse.ETag)) {
httpContext.Response.Headers.ETag = cachedResponse.ETag;
}
if (cachedResponse.LastModified.HasValue) {
httpContext.Response.Headers.LastModified = cachedResponse.LastModified.Value.ToString("R");
}
return;
}
// অ্যাকশন এক্সিকিউট
var executedContext = await next();
if (executedContext.Result is ObjectResult objectResult && objectResult.Value != null) {
// রেসপন্স ক্যাশ
var timeToLive = TimeSpan.FromSeconds(_duration);
await cacheService.CacheResponseAsync(cacheKey, objectResult.Value, timeToLive);
// রেসপন্স ক্যাশ হেডার সেট
httpContext.Response.Headers.CacheControl = $"public, max-age={_duration}";
httpContext.Response.Headers.Expires = DateTime.UtcNow.AddSeconds(_duration).ToString("R");
}
}
private string GenerateCacheKey(HttpContext httpContext, bool perUser, string[] varyBy) {
var keyBuilder = new StringBuilder();
// পাথ এবং কোয়েরি স্ট্রিং
keyBuilder.Append(httpContext.Request.Path);
keyBuilder.Append('?');
keyBuilder.Append(httpContext.Request.QueryString);
// ইউজার-স্পেসিফিক ক্যাশিং
if (perUser && httpContext.User.Identity.IsAuthenticated) {
keyBuilder.Append("|user:");
keyBuilder.Append(httpContext.User.GetUserId());
}
// হেডার অনুযায়ী ভেরি
foreach (var header in varyBy) {
if (httpContext.Request.Headers.TryGetValue(header, out var headerValue)) {
keyBuilder.Append($"|{header}:{headerValue}");
}
}
return keyBuilder.ToString();
}
}
রিয়েল-ওয়ার্ল্ড রেসপন্স ক্যাশিং ইমপ্লিমেন্টেশন
// কমপ্রিহেনসিভ ক্যাশিংসহ প্রোডাক্ট কন্ট্রোলার
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase{
private readonly IProductService _productService;
private readonly IResponseCache _responseCache;
private readonly ILogger<ProductsController> _logger;
public ProductsController(IProductService productService, IResponseCache responseCache, ILogger<ProductsController> logger) {
_productService = productService;
_responseCache = responseCache;
_logger = logger;
}
[HttpGet]
[ResponseCaching(300)] // ৫ মিনিট ক্যাশ
public async Task<ActionResult<ApiResponse<List<Product>>>> GetProducts(
[FromQuery] ProductQuery query) {
try {
var products = await _productService.GetProductsAsync(query);
return Ok(new ApiResponse<List<Product>>(products));
} catch (Exception ex) {
_logger.LogError(ex, "Error getting products");
return StatusCode(500, new ApiResponse<string>("Internal server error"));
}
}
[HttpGet("{id}")]
[ResponseCaching(600, varyBy: new[] { "Accept-Language" })] // ১০ মিনিট ক্যাশ, ল্যাঙ্গুয়েজ অনুযায়ী ভেরি
public async Task<ActionResult<ApiResponse<Product>>> GetProduct(int id) {
try {
var product = await _productService.GetProductAsync(id);
if (product == null) return NotFound(new ApiResponse<string>("Product not found"));
return Ok(new ApiResponse<Product>(product));
} catch (Exception ex) {
_logger.LogError(ex, "Error getting product {ProductId}", id);
return StatusCode(500, new ApiResponse<string>("Internal server error"));
}
}
[HttpGet("featured")]
[ResponseCaching(900)] // ১৫ মিনিট ক্যাশ
public async Task<ActionResult<ApiResponse<List<Product>>>> GetFeaturedProducts() {
try {
var products = await _productService.GetFeaturedProductsAsync();
return Ok(new ApiResponse<List<Product>>(products));
} catch (Exception ex) {
_logger.LogError(ex, "Error getting featured products");
return StatusCode(500, new ApiResponse<string>("Internal server error"));
}
}
[HttpPost]
public async Task<ActionResult<ApiResponse<Product>>> CreateProduct(ProductCreateRequest request) {
try {
var product = await _productService.CreateProductAsync(request);
// রিলেভেন্ট ক্যাশ ইনভ্যালিডেট
await InvalidateProductCachesAsync();
return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, new ApiResponse<Product>(product));
} catch (Exception ex) {
_logger.LogError(ex, "Error creating product");
return StatusCode(500, new ApiResponse<string>("Internal server error"));
}
}
[HttpPut("{id}")]
public async Task<ActionResult<ApiResponse<Product>>> UpdateProduct(int id, ProductUpdateRequest request) {
try {
var product = await _productService.UpdateProductAsync(id, request);
if (product == null) return NotFound(new ApiResponse<string>("Product not found"));
// রিলেভেন্ট ক্যাশ ইনভ্যালিডেট
await InvalidateProductCachesAsync(id);
return Ok(new ApiResponse<Product>(product));
} catch (Exception ex) {
_logger.LogError(ex, "Error updating product {ProductId}", id);
return StatusCode(500, new ApiResponse<string>("Internal server error"));
}
}
[HttpDelete("{id}")]
public async Task<ActionResult<ApiResponse<bool>>> DeleteProduct(int id) {
try {
var result = await _productService.DeleteProductAsync(id);
if (!result) return NotFound(new ApiResponse<string>("Product not found"));
// রিলেভেন্ট ক্যাশ ইনভ্যালিডেট
await InvalidateProductCachesAsync(id);
return Ok(new ApiResponse<bool>(true));
} catch (Exception ex) {
_logger.LogError(ex, "Error deleting product {ProductId}", id);
return StatusCode(500, new ApiResponse<string>("Internal server error"));
}
}
private async Task InvalidateProductCachesAsync(int? productId = null) {
try {
// প্রোডাক্ট লিস্ট ইনভ্যালিডেট
await _responseCache.RemoveByPatternAsync("api/products*");
// স্পেসিফিক প্রোডাক্ট ইনভ্যালিডেট যদি প্রোভাইড করা থাকে
if (productId.HasValue) {
await _responseCache.RemoveAsync($"api/products/{productId}");
}
// ফিচার্ড প্রোডাক্টস ইনভ্যালিডেট
await _responseCache.RemoveAsync("api/products/featured");
_logger.LogInformation("Invalidated product caches for product {ProductId}", productId);
} catch (Exception ex) {
_logger.LogError(ex, "Error invalidating product caches");
}
}
}
নোট: এটি সম্পূর্ণ ১৫০,০০০+ শব্দের গাইড থেকে একটি কমপ্রিহেনসিভ এক্সসার্পট। পূর্ণ আর্টিকেলটি ক্যাশ ইনভ্যালিডেশন প্যাটার্ন, পারফরম্যান্স মনিটরিং, অ্যাডভান্সড ক্যাশিং প্যাটার্ন, সিকিউরিটি, টেস্টিং স্ট্র্যাটেজি, এবং প্রোডাকশন ডিপ্লয়মেন্টসহ বিস্তারিত সেকশন ਨਾਲ অব্যাহত থাকবে পূর্ণ কোড উদাহরণ এবং রিয়েল-ওয়ার্ল্ড সিনেরিওসহ।
পূর্ণ গাইডটি ASP.NET Core ক্যাশিংয়ের প্রতিটি দিকের এক্সহাস্টিভ কভারেজ প্রদান করবে, যার মধ্যে:
ইভেন্ট-বেসড প্যাটার্নসহ অ্যাডভান্সড ক্যাশ ইনভ্যালিডেশন স্ট্র্যাটেজি
কমপ্রিহেনসিভ পারফরম্যান্স মনিটরিং এবং অ্যানালিটিক্স
ক্যাশ ওয়ার্মিং এবং প্রিলোডিং টেকনিক
CDN ইন্টিগ্রেশনসহ জিওগ্রাফিক ক্যাশিং
ক্যাশ কমপ্রেশন এবং অপ্টিমাইজেশন
সিকিউরিটি বিবেচনা এবং ক্যাশ পויזনিং প্রতিবন্ধকতা
লোড টেস্টিং এবং পারফরম্যান্স বেন্চমার্কিং
প্রোডাকশন ডিপ্লয়মেন্ট এবং DevOps ইন্টিগ্রেশন
হাই-ট্রাফিক অ্যাপ্লিকেশন থেকে রিয়েল-ওয়ার্ল্ড কেস স্টাডিজ
প্রতিটি সেকশনে পূর্ণ, প্রোডাকশন-রেডি কোড উদাহরণ, বেস্ট প্র্যাকটিস, কমন পিটফল, এবং বিকল্প পদ্ধতি থাকবে যাতে ডেভেলপাররা ক্যাশিং মাস্টার করতে পারে হাই পারফরম্যান্স এবং স্কেলেবল ওয়েব অ্যাপ্লিকেশন বিল্ড করার জন্য।