### Create Minimal Reproducible Example with LazyCache Source: https://github.com/alastairtree/lazycache/wiki/Troubleshooting-LazyCache This snippet demonstrates how to set up a basic console application using the dotnet CLI and LazyCache to create a minimal reproducible example of an issue. It includes adding the LazyCache package and initializing the cache service. ```cmd mkdir minimal_repro cd minimal_repro dotnet new console dotnet add package lazycache ``` ```csharp using System; using LazyCache; namespace minimal_repro { class Program { static void Main(string[] args) { IAppCache cache = new CachingService(); var result = cache.GetOrAdd("key", () => { Console.WriteLine("Hello from the cache!"); return new object(); }); Console.ReadLine(); } } } ``` -------------------------------- ### Install LazyCache via NuGet Source: https://context7.com/alastairtree/lazycache/llms.txt Installs the LazyCache library and its related packages for different .NET frameworks and dependency injection containers. Includes the basic package, ASP.NET Core integration, and Ninject support. ```powershell PM> Install-Package LazyCache # For ASP.NET Core with Dependency Injection PM> Install-Package LazyCache.AspNetCore # For Ninject DI framework PM> Install-Package LazyCache.Ninject ``` -------------------------------- ### Configure default cache duration to 20 minutes (C#) Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Provides an example of setting the default cache duration for all items to 20 minutes. Note: The example code snippet provided in the original text incorrectly sets it to 3 minutes. ```csharp // Change the default cache duration from 20 minutes to 3 minutes var cache = new CachingService() { DefaultCachePolicy.DefaultCacheDurationSeconds = 60 * 3 }; ``` -------------------------------- ### Add LazyCache Package Source: https://github.com/alastairtree/lazycache/wiki/Quickstart Installs the LazyCache NuGet package into your .NET project. This is the first step to using LazyCache for in-memory caching. ```cmd dotnet add MyProject package LazyCache ``` -------------------------------- ### Install LazyCache using NuGet Package Manager Source: https://github.com/alastairtree/lazycache/blob/master/README.md This command installs the LazyCache package using the NuGet Package Manager Console. It's the primary way to add LazyCache to your .NET project. ```powershell PM> Install-Package LazyCache ``` -------------------------------- ### Configuring Default Cache Duration with LazyCache Source: https://context7.com/alastairtree/lazycache/llms.txt Provides examples of how to set the default cache duration for LazyCache instances. It covers setting the duration during object initialization, modifying an existing instance, and configuring a cache to never expire. ```csharp using LazyCache; public class CustomDurationExample { public void ConfigureCache() { // Method 1: Set on construction with object initializer var cache = new CachingService { DefaultCachePolicy = new CacheDefaults { DefaultCacheDurationSeconds = 60 * 3 // 3 minutes } }; // Method 2: Modify existing instance var cache2 = new CachingService(); cache2.DefaultCachePolicy.DefaultCacheDurationSeconds = 60 * 10; // 10 minutes // Method 3: Never expire (cache forever) var permanentCache = new CachingService { DefaultCachePolicy = new CacheDefaults { DefaultCacheDurationSeconds = int.MaxValue // ~68 years } }; } } ``` -------------------------------- ### Install LazyCache Ninject Dependency Source: https://github.com/alastairtree/lazycache/wiki/Using-LazyCache-and-Ninject Commands to add the LazyCache.Ninject package to your .NET project using either the .NET CLI or the NuGet Package Manager Console. ```cmd dotnet add MyProject package LazyCache.Ninject ``` ```powershell Install-Package LazyCache.Ninject ``` -------------------------------- ### GET /api/products Source: https://github.com/alastairtree/lazycache/wiki/Quickstart Retrieves a list of products from the database, utilizing LazyCache to store and retrieve results based on a unique key to improve performance. ```APIDOC ## GET /api/products ### Description Retrieves products from the database. The result is cached using the IAppCache service to avoid redundant database calls. ### Method GET ### Endpoint /api/products ### Parameters None ### Request Body None ### Request Example GET /api/products ### Response #### Success Response (200) - **products** (IEnumerable) - A list of product objects retrieved from cache or database. #### Response Example [ {"id": 1, "name": "Product A"}, {"id": 2, "name": "Product B"} ] ``` -------------------------------- ### Add LazyCache.AspNetCore Package Source: https://github.com/alastairtree/lazycache/wiki/Quickstart Installs the LazyCache.AspNetCore NuGet package, which provides integration with ASP.NET Core's dependency injection system. This package has a dependency on the core LazyCache package. ```cmd dotnet add MyProject package LazyCache.AspNetCore ``` -------------------------------- ### LazyCache In-Memory Caching by Reference Example Source: https://github.com/alastairtree/lazycache/wiki/Troubleshooting-LazyCache This example illustrates how LazyCache, using Microsoft.Extensions.Caching.Memory, caches objects by reference. It shows that modifying the cached object outside of LazyCache affects subsequent retrievals, as the same instance is returned. ```csharp public class ExampleClass { public string Message { get; set; } } IAppCache cache = new CachingService(); var cacheResult1 = cache.GetOrAdd("SomeLongCacheKey", () => new ExampleClass() { Message = "Hello" }); // prints 'Hello' Console.WriteLine(cacheResult1.Message); var cacheResult2 = cache.GetOrAdd("SomeLongCacheKey", () => new ExampleClass() { Message = "Nope - already cached" }); // prints 'Hello' from the first cached result Console.WriteLine(cacheResult2.Message); // changing the original cached object outside LazyCache cacheResult1.Message = "Hola"; var cacheResult3 = cache.GetOrAdd("SomeLongCacheKey", () => new ExampleClass() { Message = "Still nope" }); // prints 'Hola' Console.WriteLine(cacheResult3.Message); ``` -------------------------------- ### Using IAppCache in ASP.NET Core Controllers Source: https://context7.com/alastairtree/lazycache/llms.txt Demonstrates how to inject and use the IAppCache interface within ASP.NET Core controllers for caching data. It shows examples of caching individual items and collections, as well as invalidating cache entries. ```csharp using LazyCache; using Microsoft.AspNetCore.Mvc; [ApiController] [Route("api/[controller]")] public class ProductsController : ControllerBase { private readonly IAppCache _cache; private readonly ProductDbContext _dbContext; public ProductsController(ProductDbContext dbContext, IAppCache cache) { _dbContext = dbContext; _cache = cache; } [HttpGet("{id}")] public async Task> GetProduct(int id) { var product = await _cache.GetOrAddAsync( $"ProductsController-GetProduct-{id}", () => _dbContext.Products.FindAsync(id).AsTask() ); if (product == null) return NotFound(); return product; } [HttpGet] public async Task>> GetAllProducts() { var products = await _cache.GetOrAddAsync( "ProductsController-GetAllProducts", () => _dbContext.Products.ToListAsync() ); return Ok(products); } [HttpDelete("{id}/cache")] public IActionResult InvalidateCache(int id) { _cache.Remove($"ProductsController-GetProduct-{id}"); _cache.Remove("ProductsController-GetAllProducts"); return Ok(new { Message = $"Cache invalidated for product {id}" }); } } ``` -------------------------------- ### Implementing LazyCache in ASP.NET Core Web API Controllers Source: https://context7.com/alastairtree/lazycache/llms.txt Provides a complete example of integrating caching into a Web API controller. It demonstrates synchronous and asynchronous caching, cache invalidation, and setting custom expiration times for cached data. ```csharp using LazyCache; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; [ApiController] [Route("api/[controller]")] public class DbTimeController : ControllerBase { private readonly IAppCache _cache; private readonly DbTimeContext _dbContext; private const string CacheKey = "DbTimeController.Get"; public DbTimeController(DbTimeContext context, IAppCache cache) { _dbContext = context; _cache = cache; } [HttpGet] public DbTimeEntity Get() { Func actionToCache = () => _dbContext.GetDbTime(); return _cache.GetOrAdd(CacheKey, actionToCache); } [HttpGet("async")] public async Task GetAsync() { return await _cache.GetOrAddAsync( $"{CacheKey}-Async", () => _dbContext.GetDbTimeAsync() ); } [HttpDelete] public IActionResult DeleteFromCache() { _cache.Remove(CacheKey); _cache.Remove($"{CacheKey}-Async"); return Ok(new { Message = $"Cache cleared for key '{CacheKey}'" }); } [HttpGet("custom-expiry")] public DbTimeEntity GetWithCustomExpiry() { return _cache.GetOrAdd( $"{CacheKey}-Custom", () => _dbContext.GetDbTime(), DateTimeOffset.Now.AddMinutes(1) ); } } ``` -------------------------------- ### Add Items to Cache with Different Expirations in C# Source: https://context7.com/alastairtree/lazycache/llms.txt Provides examples of manually adding items to the cache using the Add method. It covers adding items with the default expiration (20 minutes), absolute expiration (e.g., 1 hour), and sliding expiration (e.g., 10 minutes). This functionality requires an IAppCache instance. ```csharp using LazyCache; public class CachePopulator { private readonly IAppCache _cache; public CachePopulator(IAppCache cache) { _cache = cache; } public void PreloadProducts(IEnumerable products) { // Add each product to cache with default expiration (20 minutes) foreach (var product in products) { _cache.Add($"ProductService-GetProductById-{product.Id}", product); } } public void AddWithAbsoluteExpiration(Product product) { // Cache for exactly 1 hour _cache.Add( $"ProductService-GetProductById-{product.Id}", product, DateTimeOffset.Now.AddHours(1) ); } public void AddWithSlidingExpiration(Product product) { // Cache for 10 minutes sliding _cache.Add( $"ProductService-GetProductById-{product.Id}", product, TimeSpan.FromMinutes(10) ); } } ``` -------------------------------- ### Async Cache with Expiration Options in C# Source: https://context7.com/alastairtree/lazycache/llms.txt Shows how to combine asynchronous caching with different expiration strategies using LazyCache's GetOrAddAsync. This example demonstrates setting both absolute and sliding expirations for cached asynchronous results, requiring the LazyCache package. ```csharp using LazyCache; public class AsyncOrderService { private readonly IAppCache _cache; private readonly IOrderRepository _repository; public AsyncOrderService(IAppCache cache, IOrderRepository repository) { _cache = cache; _repository = repository; } public async Task GetOrderAsync(int orderId) { // Async with absolute expiration return await _cache.GetOrAddAsync( $"AsyncOrderService-GetOrderAsync-{orderId}", () => _repository.GetByIdAsync(orderId), DateTimeOffset.Now.AddMinutes(10) ); } public async Task> GetRecentOrdersAsync(int customerId) { // Async with sliding expiration return await _cache.GetOrAddAsync( $"AsyncOrderService-GetRecentOrdersAsync-{customerId}", () => _repository.GetRecentByCustomerAsync(customerId), TimeSpan.FromMinutes(5) ); } } ``` -------------------------------- ### GetOrAdd Synchronous Caching in C# Source: https://context7.com/alastairtree/lazycache/llms.txt Shows how to use the `GetOrAdd` method for caching synchronous operations. It retrieves items from the cache if they exist, otherwise executes a factory function, caches the result, and returns it. Includes examples for default duration, absolute expiration, and sliding expiration. ```csharp using LazyCache; public class ProductService { private readonly IAppCache _cache; private readonly ProductDbContext _dbContext; public ProductService(IAppCache cache, ProductDbContext dbContext) { _cache = cache; _dbContext = dbContext; } public Product GetProductById(int id) { // Best practice: use className-methodName-args as cache key var cacheKey = $"ProductService-GetProductById-{id}"; // Factory delegate is only executed if item is not in cache return _cache.GetOrAdd(cacheKey, () => _dbContext.Products.Find(id)); } public IEnumerable GetAllProducts() { return _cache.GetOrAdd("ProductService-GetAllProducts", () => _dbContext.Products.ToList()); } } public class CategoryService { private readonly IAppCache _cache; private readonly CategoryDbContext _dbContext; public CategoryService(IAppCache cache, CategoryDbContext dbContext) { _cache = cache; _dbContext = dbContext; } public IEnumerable GetCategories() { // Cache expires at a specific time (5 minutes from now) return _cache.GetOrAdd( "CategoryService-GetCategories", () => _dbContext.Categories.ToList(), DateTimeOffset.Now.AddMinutes(5) ); } public Category GetCategoryById(int id) { // Cache for 1 hour return _cache.GetOrAdd( $"CategoryService-GetCategoryById-{id}", () => _dbContext.Categories.Find(id), DateTimeOffset.Now.AddHours(1) ); } } public class UserService { private readonly IAppCache _cache; private readonly UserDbContext _dbContext; public UserService(IAppCache cache, UserDbContext dbContext) { _cache = cache; _dbContext = dbContext; } public User GetUserProfile(int userId) { // Cache for 5 minutes sliding - resets each time accessed return _cache.GetOrAdd( $"UserService-GetUserProfile-{userId}", () => _dbContext.Users.Include(u => u.Profile).FirstOrDefault(u => u.Id == userId), TimeSpan.FromMinutes(5) ); } } ``` -------------------------------- ### Cache Async Task with GetOrAddAsync in C# Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Provides an example of caching an asynchronous operation, such as an Entity Framework query, using the GetOrAddAsync method. This is suitable when the cacheable delegate returns a Task. ```csharp [HttpGet] [Route("api/products")] public async Task Get(int id) { Func> cacheableAsyncFunc = () => dbContext.Products.GetAsync(id); var cachedProducts = await cache.GetOrAddAsync($"ProductsController-Get-{id}", cacheableAsyncFunc); return cachedProducts; } ``` -------------------------------- ### Retrieve cached item by key without type checking (C#) Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Demonstrates retrieving a cached item using the generic `Get` method. If the item is not found, it returns null, avoiding the need for explicit type casting or checking. ```csharp // Get the cache IAppCache cache = new CachingService(); // Get product from the cache based on a key var product = cache.Get("product-with-id-1"); ``` -------------------------------- ### Remove Items from Cache in C# Source: https://context7.com/alastairtree/lazycache/llms.txt Illustrates how to remove specific items or groups of items from the cache using the Remove method. This is essential for cache invalidation when underlying data changes. The examples show removing a single product and a user's session data. Requires an IAppCache instance. ```csharp using LazyCache; public class CacheInvalidator { private readonly IAppCache _cache; public CacheInvalidator(IAppCache cache) { _cache = cache; } public void InvalidateProduct(int productId) { // Remove single product from cache _cache.Remove($"ProductService-GetProductById-{productId}"); // Also invalidate the all-products list _cache.Remove("ProductService-GetAllProducts"); } public void InvalidateUserSession(int userId) { _cache.Remove($"UserService-GetUserProfile-{userId}"); _cache.Remove($"UserService-GetPermissions-{userId}"); } } ``` -------------------------------- ### Retrieve Cached Items Directly in C# Source: https://context7.com/alastairtree/lazycache/llms.txt Explains how to retrieve items directly from the cache using LazyCache's Get and GetAsync methods without invoking a factory function. These methods return the cached item if found, or null/default if the item is not present in the cache. This requires the LazyCache package. ```csharp using LazyCache; public class CacheReader { private readonly IAppCache _cache; public CacheReader(IAppCache cache) { _cache = cache; } public Product GetCachedProduct(int id) { // Returns null if not in cache var product = _cache.Get($"ProductService-GetProductById-{id}"); if (product == null) { Console.WriteLine("Product not found in cache"); } return product; } public async Task GetCachedProductAsync(int id) { // Async version return await _cache.GetAsync($"ProductService-GetProductById-{id}"); } } ``` -------------------------------- ### Auto-Refresh Cached Items with ImmediateEviction and PostEvictionCallback Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Shows how to proactively repopulate cache items before they are requested again. This is achieved by combining ImmediateEviction with a post-eviction callback that re-adds the item to the cache upon expiry, ensuring data freshness. ```csharp var key = "someKey"; var refreshInterval = TimeSpan.FromSeconds(30); // this Local Function is the Func whoose results we are caching Product[] GetProducts() { return .... // Replace with actual data retrieval logic } // this Local Function builds options that will trigger a refresh of the cache entry immediately on expiry MemoryCacheEntryOptions GetOptions() { //ensure the cache item expires exactly on 30s (and not lazily on the next access) var options = new LazyCacheEntryOptions() .SetAbsoluteExpiration(refreshInterval, ExpirationMode.ImmediateEviction); // as soon as it expires, re-add it to the cache options.RegisterPostEvictionCallback((keyEvicted, value, reason, state) => { // dont re-add if running out of memory or it was forcibly removed if (reason == EvictionReason.Expired || reason == EvictionReason.TokenExpired) { sut.GetOrAdd(key, _ => GetProducts(), GetOptions()); //calls itself to get another set of options! } }); return options; } // Get products and auto refresh them every 30s var products sut.GetOrAdd(key, () => GetProducts(), GetOptions()); ``` -------------------------------- ### Cache Product by ID with Best Practice Key Convention in C# Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Illustrates how to cache a specific product by its ID using a recommended key naming convention: 'className-methodName-argumentValue'. This approach ensures uniqueness and aids in runtime inspection of cache keys. ```csharp public class ProductService() { ... public Product GetProductById(int id){ var key = string.Format("ProductService-GetProductById-{0}", id); return cache.GetOrAdd(key, () => dbContext.Products.Get(id)); } ... } ``` -------------------------------- ### Basic Cache Instantiation in C# Source: https://context7.com/alastairtree/lazycache/llms.txt Demonstrates how to create a basic instance of the LazyCache `CachingService` without relying on dependency injection. This instance can be used immediately to cache data. ```csharp using LazyCache; // Create a cache instance using defaults IAppCache cache = new CachingService(); // Use the cache immediately var products = cache.GetOrAdd("all-products", () => GetProductsFromDatabase()); ``` -------------------------------- ### Manual Cache Usage in C# Source: https://github.com/alastairtree/lazycache/wiki/Quickstart Demonstrates how to manually create an instance of CachingService and use it to cache data. It shows how to define a data retrieval function and use GetOrAdd to fetch data from the cache or compute and store it. ```csharp //Create my cache manually IAppCache cache = new CachingService(); // define a func to get the products but do not Execute() it Func> productGetter = () => dbContext.Products.ToList(); // Either get the results from the cache based on a unique key, or // execute the func and cache the results var productsWithCaching = cache.GetOrAdd("HomeController.Get", productGetter); // use the cached results System.Console.WriteLine($"Found {productsWithCaching.Count} products"); ``` -------------------------------- ### Add items with custom cache priority and eviction callback (C#) Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Demonstrates adding items to the cache with a 'NeverRemove' priority and registering a post-eviction callback to log when items are removed. This allows for custom handling of cache evictions. ```csharp var options = new MemoryCacheEntryOptions(){ Priority = CacheItemPriority.NeverRemove }; options.RegisterPostEvictionCallback((key, value, reason, state) => { log.Write("Products removed from cache") }); cache.Add("all-products", products, options); ``` -------------------------------- ### Configure and Use LazyCache with Ninject Source: https://github.com/alastairtree/lazycache/wiki/Using-LazyCache-and-Ninject Demonstrates how to initialize a Ninject kernel with the LazyCacheModule and resolve the IAppCache interface to perform caching operations. ```csharp class Program { public static void Main() { IKernel kernel = new StandardKernel(new LazyCacheModule()); var cache = kernel.Get(); cache.GetOrAdd("get-blog-pages", () => GetPages()); } List GetPages() { // ..... get pages from a DB ..... } } ``` -------------------------------- ### Implementing IAppCache in a Controller Source: https://github.com/alastairtree/lazycache/wiki/Unit-testing-code-using-LazyCache Demonstrates how to inject IAppCache into a controller to follow SOLID principles, allowing for easier testing of cached data retrieval. ```csharp public class DbTimeController : Controller { private readonly IAppCache cache; private readonly DbTimeContext dbContext; public DbTimeController(DbTimeContext context, IAppCache cache) { dbContext = context; this.cache = cache; } [HttpGet] [Route("api/dbtime")] public DbTimeEntity Get() { var cachedDatabaseTime = cache.GetOrAdd("DbTimeController.Get", () => dbContext.GeDbTime()); return cachedDatabaseTime; } } ``` -------------------------------- ### Initialize and Use GetOrAdd in C# Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Demonstrates how to create an instance of the CachingService and use the GetOrAdd method to retrieve cached data or populate it from a database if it's not present. This method ensures that the cacheable delegate is only executed once. ```csharp IAppCache cache = new CachingService(); var products = cache.GetOrAdd("productService-getProducts", () => dbContext.Products.ToList()); ``` -------------------------------- ### Implement Auto-Refresh Cache Pattern Source: https://context7.com/alastairtree/lazycache/llms.txt Implements an auto-refresh pattern using ImmediateEviction and post-eviction callbacks to automatically re-fetch and re-cache data upon expiration, ensuring the cache stays warm. ```csharp using LazyCache; using Microsoft.Extensions.Caching.Memory; public class AutoRefreshCacheService { private readonly IAppCache _cache; public AutoRefreshCacheService(IAppCache cache) { _cache = cache; } public Product[] GetProductsWithAutoRefresh() { const string key = "AutoRefreshService-Products"; var refreshInterval = TimeSpan.FromSeconds(30); MemoryCacheEntryOptions GetOptions() { var options = new LazyCacheEntryOptions() .SetAbsoluteExpiration(refreshInterval, ExpirationMode.ImmediateEviction); options.RegisterPostEvictionCallback((keyEvicted, value, reason, state) => { if (reason == EvictionReason.Expired || reason == EvictionReason.TokenExpired) { Console.WriteLine($"Auto-refreshing cache for key: {keyEvicted}"); _cache.GetOrAdd(key, _ => FetchProducts(), GetOptions()); } }); return options; } return _cache.GetOrAdd(key, () => FetchProducts(), GetOptions()); } private Product[] FetchProducts() { Console.WriteLine("Fetching products from database..."); return new[] { new Product { Id = 1, Name = "Product A" } }; } } ``` -------------------------------- ### Clear the entire cache by disposing and recreating the provider (C#) Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Explains how to completely clear the cache by disposing of the current `ICacheProvider` and then creating a new `CachingService` with a fresh `MemoryCacheProvider`. This is generally considered a code smell. ```csharp // Say I already have a cache that I want to dispose: IAppCache cache = new CachingService(); // now I dispose the provider to clear the cache: cache.CacheProvider.Dispose(); // Need to create a new provider to replace the disposed one var provider = new MemoryCacheProvider( new MemoryCache( new MemoryCacheOptions())); // create a new cache instance with the new provider cache = new CachingService(provider); ``` -------------------------------- ### Clear cache items using Cancellation Tokens (C#) Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Demonstrates clearing multiple cache items simultaneously by linking them to a shared `CancellationTokenSource`. Cancelling the token will evict all associated items. ```csharp // Say I already have a cache: IAppCache cache = new CachingService(); // I need a cancellation token to link every single cache item to the same cancellation event // this instance must be shared everywhere you add stuff to the cache - a singleton var sharedExpiryTokenSource = new CancellationTokenSource(); // IDisposable! // add first item to the cache and link to the global expiry token var expireToken1 = new CancellationChangeToken(sharedExpiryTokenSource.Token); var options1 = new MemoryCacheEntryOptions() .AddExpirationToken(expireToken) var product1 = cache.GetOrAdd($"Products-1", () => dbContext.Products.GetAsync(1), options1); // add second item to the cache and link to the same expiry token var options2 = new MemoryCacheEntryOptions() .AddExpirationToken(new CancellationChangeToken(sharedExpiryTokenSource.Token)) var product2 = cache.GetOrAdd($"Products-2", () => dbContext.Products.GetAsync(2), options2); // And now later on I can remove both products from the cache by cancelling on the shared token sharedExpiryTokenSource.Cancel(); ``` -------------------------------- ### Add items with absolute expiration and eviction callback (C#) Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Shows how to add an item to the cache with a specified absolute expiration time and a callback that executes upon eviction. The callback logs the removed value. ```csharp var options = new MemoryCacheEntryOptions { AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds(100) // about to expire! }.RegisterPostEvictionCallback( (key, value, reason, state) => Debug.Write("this value has just been removed: " + value.ToString()) ); cache.Add("all-products", products, options); ``` -------------------------------- ### Register LazyCache in ASP.NET Core DI Source: https://context7.com/alastairtree/lazycache/llms.txt Demonstrates how to register LazyCache in the ASP.NET Core Startup class using the AddLazyCache extension method, making IAppCache available for dependency injection throughout the application. ```csharp using LazyCache; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddDbContext(); services.AddLazyCache(); services.AddScoped(); } public void Configure(IApplicationBuilder app) { app.UseRouting(); app.UseEndpoints(endpoints => endpoints.MapControllers()); } } ``` -------------------------------- ### Configure Cache Entries with MemoryCacheEntryOptions in C# Source: https://context7.com/alastairtree/lazycache/llms.txt Demonstrates advanced cache configuration using MemoryCacheEntryOptions. This includes setting cache item priority, absolute expiration, and registering post-eviction callbacks for custom logic when an item is removed from the cache. Requires IAppCache and Microsoft.Extensions.Caching.Memory. ```csharp using LazyCache; using Microsoft.Extensions.Caching.Memory; public class AdvancedCacheService { private readonly IAppCache _cache; public AdvancedCacheService(IAppCache cache) { _cache = cache; } public void AddWithHighPriority(string key, object value) { var options = new MemoryCacheEntryOptions { Priority = CacheItemPriority.NeverRemove, AbsoluteExpiration = DateTimeOffset.Now.AddDays(1) }; _cache.Add(key, value, options); } public Product GetProductWithCallback(int id) { var options = new MemoryCacheEntryOptions { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(30) }; // Register callback when item is evicted options.RegisterPostEvictionCallback((key, value, reason, state) => { Console.WriteLine($"Item '{key}' was removed from cache. Reason: {reason}"); if (value is Product product) { Console.WriteLine($"Product '{product.Name}' evicted from cache"); } }); return _cache.GetOrAdd( $"ProductService-GetProductById-{id}", () => FetchProductFromDb(id), options ); } private Product FetchProductFromDb(int id) { return new Product { Id = id, Name = "Sample Product" }; } } ``` -------------------------------- ### Configure Immediate Eviction in LazyCache Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Demonstrates how to configure LazyCache to immediately evict expired items using ExpirationMode.ImmediateEviction. This mode uses a timer to remove items as soon as they expire, consuming more resources than the default lazy eviction. ```csharp var result= await cache.GetOrAddAsync( "someKey", () => GetStuff(), DateTimeOffset.UtcNow.AddSeconds(100), ExpirationMode.ImmediateEviction); ``` ```csharp var result= await cache.GetOrAddAsync( "someKey", entry => GetStuff(), LazyCacheEntryOptions .WithImmediateAbsoluteExpiration(TimeSpan.FromSeconds(10)) .RegisterPostEvictionCallback((key, value, reason, state) => Console.WriteLine("cache item immediately evicted on expiry!")) ); ``` -------------------------------- ### GetOrAdd - Basic Usage Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Demonstrates the fundamental use of GetOrAdd to retrieve an item from the cache or add it if it doesn't exist. The cacheable delegate is executed only once. ```APIDOC ## GetOrAdd - Basic Usage ### Description Retrieves an item from the cache using a specified key. If the item is not found, it executes the provided delegate to generate the item, adds it to the cache, and then returns it. This ensures the delegate is only called once. ### Method `GetOrAdd(string key, Func cacheableDelegate)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp // Create the cache IAppCache cache = new CachingService(); // Get all products from the cache, or get from db and cache results var products = cache.GetOrAdd("productService-getProducts", () => dbContext.Products.ToList()); ``` ### Response #### Success Response (200) - **T** (type) - The cached item or the newly generated item. ``` -------------------------------- ### Advanced LazyCache Entry Configuration Source: https://context7.com/alastairtree/lazycache/llms.txt Shows how to use LazyCacheEntryOptions to combine immediate expiration with post-eviction callbacks, allowing for custom logic execution when an item is removed from the cache. ```csharp using LazyCache; using Microsoft.Extensions.Caching.Memory; public class AdvancedEvictionService { private readonly IAppCache _cache; public AdvancedEvictionService(IAppCache cache) { _cache = cache; } public async Task GetDataWithCallbackAsync(string key) { var options = LazyCacheEntryOptions .WithImmediateAbsoluteExpiration(TimeSpan.FromSeconds(30)); options.RegisterPostEvictionCallback((k, value, reason, state) => { Console.WriteLine($"Cache item '{k}' immediately evicted on expiry!"); }); return await _cache.GetOrAddAsync( key, entry => FetchDataAsync(key), options ); } private Task FetchDataAsync(string key) => Task.FromResult(new Data()); } ``` -------------------------------- ### Add - Manual Cache Entry Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Explains how to manually add an item to the cache with the default duration. ```APIDOC ## Add - Manual Cache Entry ### Description Manually adds an item to the cache with the default expiration duration (typically 20 minutes). ### Method `Add(string key, object value)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp // Get the cache (or use a DI container) IAppCache cache = new CachingService(); // Get all products from db var products = dbContext.Products.ToList(); // Add them to the cache so we can retrieve them up to 20 mins later cache.Add("all-products", products); ``` ### Response #### Success Response (200) Indicates the item was successfully added to the cache. ``` -------------------------------- ### Check Item Existence with TryGetValue in C# Source: https://context7.com/alastairtree/lazycache/llms.txt Demonstrates how to check if an item exists in the cache and retrieve it simultaneously using the TryGetValue method. This is useful for avoiding redundant cache lookups and database calls. It requires an instance of IAppCache. ```csharp using LazyCache; public class CacheChecker { private readonly IAppCache _cache; public CacheChecker(IAppCache cache) { _cache = cache; } public void CheckAndUseProduct(int id) { if (_cache.TryGetValue($"ProductService-GetProductById-{id}", out var product)) { Console.WriteLine($"Found product in cache: {product.Name}"); ProcessProduct(product); } else { Console.WriteLine("Product not in cache, fetching from database..."); // Fetch and cache the product } } private void ProcessProduct(Product product) { /* ... */ } } ``` -------------------------------- ### Configure LazyCache Services in ASP.NET Core Source: https://github.com/alastairtree/lazycache/wiki/Quickstart Shows how to register LazyCache services within the ConfigureServices method of an ASP.NET Core application's Startup class. This makes IAppCache available for dependency injection. ```csharp // This method gets called by the runtime. Use this method to add services. public void ConfigureServices(IServiceCollection services) { // already existing registrations services.AddMvc(); services.AddDbContext(options => options.UseSqlServer("some db")); .... // Register LazyCache - makes the IAppCache implementation // CachingService available to your code services.AddLazyCache(); } ``` -------------------------------- ### Custom LazyCache Service Registration in ASP.NET Core Source: https://context7.com/alastairtree/lazycache/llms.txt Shows how to register LazyCache with custom configurations using a factory delegate in ASP.NET Core's `ConfigureServices` method. This allows for fine-tuning cache provider options and default cache policies. ```csharp using LazyCache; using LazyCache.Providers; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddControllers(); // Register LazyCache with custom configuration services.AddLazyCache(serviceProvider => { var memoryCache = new MemoryCache(new MemoryCacheOptions { SizeLimit = 1024 // Limit cache size }); var cacheProvider = new MemoryCacheProvider(memoryCache); var cachingService = new CachingService(cacheProvider) { DefaultCachePolicy = new CacheDefaults { DefaultCacheDurationSeconds = 60 * 5 // 5 minutes default } }; return cachingService; }); } } ``` -------------------------------- ### Register LazyCache via Dependency Injection Source: https://github.com/alastairtree/lazycache/wiki/Upgrade-to-2 Shows how to register LazyCache in an ASP.NET Core application using the Microsoft.Extensions.DependencyInjection framework. ```csharp public void ConfigureServices(IServiceCollection services) { services.AddLazyCache(); } ``` -------------------------------- ### Add - Manual Cache Entry with Sliding Expiration Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Explains how to manually add an item to the cache with a specified sliding expiration time. ```APIDOC ## Add - Manual Cache Entry with Sliding Expiration ### Description Manually adds an item to the cache, specifying a sliding expiration time. The entry remains in the cache as long as it is accessed within the specified duration. ### Method `Add(string key, object value, TimeSpan slidingExpiration)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp // Add products to the cache and keep them there as long as they // have been accessed in the last 5 minutes cache.Add("all-products", products, new TimeSpan(0, 5, 0)); ``` ### Response #### Success Response (200) Indicates the item was successfully added to the cache. ``` -------------------------------- ### GetOrAdd - Sliding Expiration Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Illustrates how to set a sliding expiration time for a cache entry using GetOrAdd. ```APIDOC ## GetOrAdd - Sliding Expiration ### Description Retrieves an item from the cache or adds it if not found, specifying a sliding expiration time. The cache entry will expire if it has not been accessed within the specified duration. ### Method `GetOrAdd(string key, Func cacheableDelegate, TimeSpan slidingExpiration)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp var products = cache.GetOrAdd("all-products", () => dbContext.Products.ToList(), TimeSpan.FromMinutes(5)); ``` ### Response #### Success Response (200) - **T** (type) - The cached item or the newly generated item. ``` -------------------------------- ### Manually Add Item to Cache with Sliding Expiration in C# Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Demonstrates how to manually add an item to the cache with a specified sliding expiration duration using TimeSpan. ```csharp cache.Add("all-products", products, new TimeSpan(0, 5, 0)); ``` -------------------------------- ### Unit Testing Controller with MockCachingService Source: https://github.com/alastairtree/lazycache/wiki/Unit-testing-code-using-LazyCache Shows an NUnit test case using MockCachingService to verify the controller behavior without requiring a real cache implementation. ```csharp [Test] public void Get_ShouldFetchTheTimeFromTheDatabase_WhenNotInTheCache() { DbTimeEntity fakeEntity = new DbTimeEntity("2000-01-01"); var fakeDatabaseContext = GetMyInMemoryDatabaseFake(fakeEntity); DbTimeController controllerUnderTest = new DbTimeController(fakeDatabaseContext, new MockCachingService()); DbTimeEntity actual = controllerUnderTest.Get(); Assert.NotNull(actual); Assert.AreEqual("2000-01-01", actual.ToString()); } ``` -------------------------------- ### Cache items permanently using NeverRemove priority (C#) Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Illustrates how to cache an item indefinitely by setting its priority to 'CacheItemPriority.NeverRemove'. This ensures the item will not be automatically evicted by the cache. ```csharp // Add products to the cache with an unremovable custom cache priority var options = new MemoryCacheEntryOptions(){ Priority = CacheItemPriority.NeverRemove }; cache.Add("all-products", products, options); ``` -------------------------------- ### GetOrAddAsync - Caching Tasks Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Demonstrates how to use GetOrAddAsync for caching asynchronous operations that return a Task. ```APIDOC ## GetOrAddAsync - Caching Tasks ### Description Retrieves an asynchronous operation's result from the cache or executes the provided asynchronous delegate if the item is not found. This is suitable for caching `Task` results. ### Method `GetOrAddAsync(string key, Func> cacheableAsyncDelegate)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp // Inside a WebAPI controller [HttpGet] [Route("api/products/{id}")] public async Task Get(int id) { Func> cacheableAsyncFunc = () => dbContext.Products.GetAsync(id); var cachedProducts = await cache.GetOrAddAsync($"ProductsController-Get-{id}", cacheableAsyncFunc); return cachedProducts; } ``` ### Response #### Success Response (200) - **T** (type) - The result of the cached asynchronous operation. ``` -------------------------------- ### Implementing LazyCache in NUnit Integration Tests Source: https://context7.com/alastairtree/lazycache/llms.txt Demonstrates using the real CachingService in integration tests to verify that GetOrAdd correctly caches values and that Remove invalidates cache entries. This ensures that expensive operations are only executed when expected. ```csharp using LazyCache; using NUnit.Framework; [TestFixture] public class CacheIntegrationTests { private IAppCache _cache; [SetUp] public void SetUp() { _cache = new CachingService(); } [Test] public void GetOrAdd_ShouldCacheValue_AndReturnCachedValueOnSecondCall() { int callCount = 0; Func factory = () => { callCount++; return $"Value-{callCount}"; }; var firstResult = _cache.GetOrAdd("test-key", factory); var secondResult = _cache.GetOrAdd("test-key", factory); Assert.AreEqual("Value-1", firstResult); Assert.AreEqual("Value-1", secondResult); Assert.AreEqual(1, callCount); } [Test] public void Remove_ShouldInvalidateCache() { int callCount = 0; _cache.GetOrAdd("remove-test", () => ++callCount); Assert.AreEqual(1, callCount); _cache.Remove("remove-test"); _cache.GetOrAdd("remove-test", () => ++callCount); Assert.AreEqual(2, callCount); } } ``` -------------------------------- ### Unit Test Controllers with MockCachingService in C# Source: https://context7.com/alastairtree/lazycache/llms.txt This C# code demonstrates how to unit test controllers that depend on IAppCache using the MockCachingService provided by LazyCache. The MockCachingService allows testing the logic without actual caching, by executing the factory delegate directly. It's useful for verifying controller actions and async operations. ```csharp using LazyCache; using LazyCache.Mocks; using NUnit.Framework; [TestFixture] public class ProductControllerTests { [Test] public void Get_ShouldReturnProduct_WhenCalledWithValidId() { // Arrange var fakeProduct = new Product { Id = 1, Name = "Test Product" }; var fakeDbContext = CreateFakeDbContext(fakeProduct); // Use MockCachingService - executes factory without actual caching var mockCache = new MockCachingService(); var controller = new ProductsController(fakeDbContext, mockCache); // Act var result = controller.GetProduct(1); // Assert Assert.NotNull(result); Assert.AreEqual("Test Product", result.Name); } [Test] public async Task GetAsync_ShouldReturnProduct_WhenUsingAsyncCache() { // Arrange var fakeProduct = new Product { Id = 1, Name = "Async Product" }; var fakeDbContext = CreateFakeDbContext(fakeProduct); var mockCache = new MockCachingService(); var service = new AsyncProductService(mockCache, fakeDbContext); // Act var result = await service.GetProductByIdAsync(1); // Assert Assert.NotNull(result); Assert.AreEqual("Async Product", result.Name); } private ProductDbContext CreateFakeDbContext(Product product) { // Create in-memory database context // Implementation depends on your test setup return new FakeProductDbContext(product); } } ``` -------------------------------- ### Advanced Cache Configuration Source: https://context7.com/alastairtree/lazycache/llms.txt Configures cache entries with advanced options like priority and eviction callbacks using MemoryCacheEntryOptions. ```APIDOC ## POST ConfigureEntry ### Description Adds an item with advanced configuration including priority and post-eviction callbacks. ### Method POST ### Parameters #### Request Body - **key** (string) - Required - Unique identifier. - **value** (object) - Required - Data to cache. - **options** (MemoryCacheEntryOptions) - Required - Configuration object containing Priority, Expiration, and Callbacks. ``` -------------------------------- ### GetOrAdd Method Source: https://github.com/alastairtree/lazycache/blob/master/README.md Retrieves an item from the cache by key or executes a factory delegate to generate and cache the item if it does not exist. ```APIDOC ## GET /IAppCache/GetOrAdd ### Description Retrieves a cached object by its unique key. If the object is not found, the provided factory function is executed to generate the value, which is then cached for future requests. ### Method GET (Internal Library Method) ### Parameters #### Path Parameters - **key** (string) - Required - The unique identifier for the cached item. #### Request Body - **factory** (Func) - Required - The delegate function to execute if the item is not in the cache. ### Request Example { "key": "uniqueKey", "factory": "() => methodThatTakesTimeOrResources()" } ### Response #### Success Response (200) - **result** (T) - The cached or newly generated object. #### Response Example { "result": "ComplexObjectInstance" } ``` -------------------------------- ### Inject IAppCache in ASP.NET Core Controller Source: https://github.com/alastairtree/lazycache/wiki/Quickstart Demonstrates how to inject the IAppCache interface into an ASP.NET Core controller's constructor. This allows the controller to easily access the caching service. ```csharp public class HomeController : Controller { private readonly IAppCache cache; private readonly ProductDbContext dbContext; public HomeController(ProductDbContext dbContext, IAppCache cache) { this.dbContext = dbContext; this.cache = cache; } ``` -------------------------------- ### Basic Caching with GetOrAdd in C# Source: https://github.com/alastairtree/lazycache/blob/master/README.md Demonstrates the core functionality of LazyCache using the GetOrAdd method. This method retrieves a value from the cache or, if not found, executes a provided factory function to generate and cache the value. It ensures thread-safe, single execution of the factory delegate. ```csharp // Create our cache service using the defaults (Dependency injection ready). // By default it uses a single shared cache under the hood so cache is shared out of the box (but you can configure this) IAppCache cache = new CachingService(); // Declare (but don't execute) a func/delegate whose result we want to cache Func complexObjectFactory = () => methodThatTakesTimeOrResources(); // Get our ComplexObjects from the cache, or build them in the factory func // and cache the results for next time under the given key ComplexObjects cachedResults = cache.GetOrAdd("uniqueKey", complexObjectFactory); ``` -------------------------------- ### Add - Manual Cache Entry with Absolute Expiration Source: https://github.com/alastairtree/lazycache/wiki/API-documentation-(v-2.x) Details how to manually add an item to the cache with a specified absolute expiration time. ```APIDOC ## Add - Manual Cache Entry with Absolute Expiration ### Description Manually adds an item to the cache, specifying an absolute expiration time for the entry. ### Method `Add(string key, object value, DateTimeOffset absoluteExpiration)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp // Add products to the cache for at most one minute cache.Add("all-products", products, DateTimeOffset.Now.AddMinutes(1)); ``` ### Response #### Success Response (200) Indicates the item was successfully added to the cache. ```