ItemsCache.Refresh.Polling.Metrics 0.0.1-preview.18

This is a prerelease version of ItemsCache.Refresh.Polling.Metrics.
dotnet add package ItemsCache.Refresh.Polling.Metrics --version 0.0.1-preview.18
                    
NuGet\Install-Package ItemsCache.Refresh.Polling.Metrics -Version 0.0.1-preview.18
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ItemsCache.Refresh.Polling.Metrics" Version="0.0.1-preview.18" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ItemsCache.Refresh.Polling.Metrics" Version="0.0.1-preview.18" />
                    
Directory.Packages.props
<PackageReference Include="ItemsCache.Refresh.Polling.Metrics" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ItemsCache.Refresh.Polling.Metrics --version 0.0.1-preview.18
                    
#r "nuget: ItemsCache.Refresh.Polling.Metrics, 0.0.1-preview.18"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ItemsCache.Refresh.Polling.Metrics@0.0.1-preview.18
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ItemsCache.Refresh.Polling.Metrics&version=0.0.1-preview.18&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=ItemsCache.Refresh.Polling.Metrics&version=0.0.1-preview.18&prerelease
                    
Install as a Cake Tool

ItemsCache

CI NuGet License: MIT

A high-performance, flexible caching library for ASP.NET Core applications that provides automatic data loading, background refresh, and retry logic with SOLID principles.

Features

  • 🚀 High Performance: Optimized for speed with minimal memory overhead
  • 🔄 Background Refresh: Automatic cache refresh with configurable intervals
  • 🛡️ Retry Logic: Built-in retry policies using Polly for resilient operations
  • 🏗️ SOLID Principles: Clean architecture with proper abstractions
  • 📦 Modular Design: Use only what you need with separate packages
  • 🔧 Easy Integration: Simple setup with dependency injection
  • 📊 Observability: Built-in logging and monitoring support

Packages

Package Description NuGet
ItemsCache.All Complete package with all features NuGet
ItemsCache Core caching functionality NuGet
ItemsCache.Refresh Background refresh capabilities NuGet
ItemsCache.Refresh.Polling Polling-based refresh implementation NuGet
ItemsCache.RetryPolicy Retry policy implementations with Polly NuGet

Quick Start

Installation

For the complete experience, install the main package:

dotnet add package ItemsCache.All

Or install individual packages based on your needs:

dotnet add package ItemsCache
dotnet add package ItemsCache.Refresh.Polling
dotnet add package ItemsCache.RetryPolicy

Basic Usage

  1. Register services in your Program.cs:
using ItemsCache.Core.Abstraction.Interfaces;
using ItemsCache.Core.Extensions;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add database context (example with Entity Framework Core)
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseInMemoryDatabase("InMemoryDb"));

// Register ItemsCache service
builder.Services.AddItemsCache<int, Product>();

// Register your data source
builder.Services.AddScoped<IDataSource<int, Product>, DataFromDbSource>();

var app = builder.Build();
  1. Create a data source implementing IDataSource<TKey, TCacheItem>:
using ItemsCache.Core.Abstraction.Interfaces;
using Microsoft.EntityFrameworkCore;

public class DataFromDbSource : IDataSource<int, Product>
{
    private readonly AppDbContext _dbContext;

    public DataFromDbSource(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<IEnumerable<KeyValuePair<int, Product>>> LoadAllAsync(
        CancellationToken cancellationToken = default)
    {
        var products = await _dbContext.Set<Product>().ToListAsync(cancellationToken);
        return products.ToDictionary(p => p.Id);
    }
}
  1. Use the cache service in your controllers:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IItemsCacheService<int, Product> _productItemsCache;
    
    public ProductsController(IItemsCacheService<int, Product> productItemsCache)
    {
        _productItemsCache = productItemsCache;
    }
    
    [HttpGet("{id}")]
    public ActionResult<Product> GetProduct(int id)
    {
        if (_productItemsCache.TryGetByKey(id, out var product))
        {
            return Ok(product);
        }
        return NotFound($"Product with ID {id} not found");
    }
    
    [HttpGet]
    public ActionResult<IEnumerable<Product>> GetAllProducts()
    {
        var products = _productItemsCache.GetAll().ToDictionary();
        return Ok(products.Values);
    }
}

Complete Example

This example demonstrates a complete setup with all features: basic cache, grouped cache, polling refresh, and metrics.

Step 1: Define Your Model

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public string? Description { get; set; }
    public decimal Price { get; set; }
    public string? Category { get; set; }
    public bool IsActive { get; set; } = true;
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public DateTime? UpdatedAt { get; set; }
    public DateTime? DeletedAt { get; set; }
}

Step 2: Configure appsettings.json

{
  "CacheOptions": {
    "RefreshInterval": "00:00:30"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "ItemsCache": "Information"
    }
  }
}

Step 3: Complete Program.cs Setup

using ItemsCache.Core.Abstraction.Interfaces;
using ItemsCache.Core.Extensions;
using ItemsCache.Core.Metrics.Extensions;
using ItemsCache.Refresh.Polling.Extensions;
using ItemsCache.Refresh.Polling.Metrics.Extensions;
using Microsoft.EntityFrameworkCore;
using Prometheus;
using SampleApi.Data;
using SampleApi.Models;
using SampleApi.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Database setup
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseInMemoryDatabase("InMemoryDb"));

// Register ItemsCache service
builder.Services.AddItemsCache<int, Product>();

// Register grouped cache services
builder.Services.AddItemsCacheGrouped<int, Product, string>(p => p.Category ?? "Uncategorized");
builder.Services.AddItemsCacheGrouped<int, Product, bool>(p => p.IsActive);

// Register Prometheus metrics (optional)
var prometheusRecorder = new PrometheusMetricsRecorder<int, Product>();
builder.Services.AddItemsCacheMetrics<int, Product>(prometheusRecorder);
builder.Services.AddItemsCacheGroupedMetrics<int, Product, string>();
builder.Services.AddItemsCacheGroupedMetrics<int, Product, bool>();

// Register data source
builder.Services.AddScoped<IDataSource<int, Product>, DataFromDbSource>();

// Register polling refresh (optional)
builder.Services.AddPollingRefreshItemCacheHandler<int, Product, RefreshContext>(builder.Configuration);
builder.Services.AddPollingRefreshMetrics<int, Product, RefreshContext>();

// Register refresh data source
builder.Services.AddScoped<IDataSourceWithRefresh<int, Product, RefreshContext>, 
    DataFromDbSourceWithRefresh>();

var app = builder.Build();

// Configure Prometheus metrics endpoint
app.UseHttpMetrics();
app.MapMetrics();

app.MapControllers();

// Seed database (example)
using (var scope = app.Services.CreateScope())
{
    var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
    context.Database.EnsureCreated();
    // Seed your data here
}

app.Run();

Step 4: Implement Data Source with Refresh

For polling refresh, implement IDataSourceWithRefresh:

using ItemsCache.Refresh.Abstraction.Models;
using ItemsCache.Refresh.Polling.Abstraction.Interfaces;
using ItemsCache.Refresh.Polling.Abstraction.Models;
using Microsoft.EntityFrameworkCore;

public class DataFromDbSourceWithRefresh : IDataSourceWithRefresh<int, Product, RefreshContext>
{
    private readonly AppDbContext _dbContext;

    public DataFromDbSourceWithRefresh(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<CacheItemRefreshResult<int, Product, RefreshContext>> GetUpdatedItemsAsync(
        RefreshContext? lastRefreshContext, 
        CancellationToken cancellationToken = default)
    {
        var lastRefreshTime = lastRefreshContext?.LastRefresh ?? DateTime.MinValue;
        var updatedTime = DateTime.UtcNow;

        var updatedItems = await _dbContext.Products
            .Where(p => p.UpdatedAt > lastRefreshTime || 
                       (p.DeletedAt != null && p.DeletedAt > lastRefreshTime))
            .ToListAsync(cancellationToken);

        var newRefreshContext = new RefreshContext
        {
            LastRefresh = updatedTime
        };

        var cacheItems = updatedItems
            .Select(item => new RefreshCacheItem<int, Product>(
                item.Id, 
                item, 
                item.DeletedAt != null ? RefreshCacheItemStatus.Deleted : RefreshCacheItemStatus.Updated))
            .ToList();

        return new CacheItemRefreshResult<int, Product, RefreshContext>(
            cacheItems, 
            newRefreshContext);
    }
}

// RefreshContext model
public class RefreshContext
{
    public DateTime LastRefresh { get; set; }
}

Advanced Configuration

Background Refresh

ItemsCache supports automatic cache refresh using polling. The cache periodically checks for updated items and refreshes them automatically.

Configuration

Configure polling refresh in appsettings.json:

{
  "CacheOptions": {
    "RefreshInterval": "00:00:30"
  }
}

The RefreshInterval is specified as a TimeSpan string (HH:mm:ss format). The default is 30 seconds.

Register Polling Refresh
using ItemsCache.Refresh.Polling.Extensions;

// Register polling refresh handler
builder.Services.AddPollingRefreshItemCacheHandler<int, Product, RefreshContext>(
    builder.Configuration);

// Register your refresh data source
builder.Services.AddScoped<IDataSourceWithRefresh<int, Product, RefreshContext>, 
    DataFromDbSourceWithRefresh>();
Implement IDataSourceWithRefresh

To enable refresh, implement IDataSourceWithRefresh<TKey, TCacheItem, TRefreshContext>:

public class DataFromDbSourceWithRefresh : IDataSourceWithRefresh<int, Product, RefreshContext>
{
    private readonly AppDbContext _dbContext;

    public DataFromDbSourceWithRefresh(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<CacheItemRefreshResult<int, Product, RefreshContext>> GetUpdatedItemsAsync(
        RefreshContext? lastRefreshContext, 
        CancellationToken cancellationToken = default)
    {
        // Get the last refresh time from context
        var lastRefreshTime = lastRefreshContext?.LastRefresh ?? DateTime.MinValue;
        
        // Set current time before querying to avoid missing updates
        var updatedTime = DateTime.UtcNow;

        // Query for items updated or deleted since last refresh
        var updatedItems = await _dbContext.Products
            .Where(p => p.UpdatedAt > lastRefreshTime || 
                       (p.DeletedAt != null && p.DeletedAt > lastRefreshTime))
            .ToListAsync(cancellationToken);

        // Create new refresh context with current time
        var newRefreshContext = new RefreshContext
        {
            LastRefresh = updatedTime
        };

        // Map items to refresh cache items
        var cacheItems = updatedItems
            .Select(item => new RefreshCacheItem<int, Product>(
                item.Id, 
                item, 
                item.DeletedAt != null ? RefreshCacheItemStatus.Deleted : RefreshCacheItemStatus.Updated))
            .ToList();

        return new CacheItemRefreshResult<int, Product, RefreshContext>(
            cacheItems, 
            newRefreshContext);
    }
}
RefreshContext

The RefreshContext is used to track the state of the last refresh. It's passed between refresh cycles:

public class RefreshContext
{
    public DateTime LastRefresh { get; set; }
}
How It Works
  1. The polling service runs in the background at the configured interval
  2. On each cycle, it calls GetUpdatedItemsAsync with the previous RefreshContext
  3. Your implementation queries for items changed since the last refresh
  4. Updated items are automatically refreshed in the cache
  5. Deleted items are removed from the cache
  6. The new RefreshContext is stored for the next cycle
Metrics

Add metrics for polling refresh:

using ItemsCache.Refresh.Polling.Metrics.Extensions;

builder.Services.AddPollingRefreshMetrics<int, Product, RefreshContext>();

Retry Policies

Configure retry behavior:

builder.Services.AddItemsCache()
    .AddRetryPolicy(options =>
    {
        options.MaxRetryAttempts = 3;
        options.DelayBetweenRetries = TimeSpan.FromSeconds(1);
        options.UseExponentialBackoff = true;
    });

Metrics Integration

ItemsCache provides built-in support for metrics recording. You can implement your own metrics recorder or use the provided Prometheus integration.

Prometheus Metrics Setup
  1. Install Prometheus package:
dotnet add package prometheus-net.AspNetCore
  1. Create a custom metrics recorder:
using ItemsCache.Core.Abstraction.Interfaces;
using Prometheus;

public class PrometheusMetricsRecorder<TKey, TCacheItem> : IMetricsRecorder<TKey, TCacheItem>
    where TKey : notnull
    where TCacheItem : class
{
    private static readonly Counter CacheHits = Metrics
        .CreateCounter("itemscache_cache_hits_total", "Total number of cache hits", 
            new[] { "cache_type" });

    private static readonly Counter CacheMisses = Metrics
        .CreateCounter("itemscache_cache_misses_total", "Total number of cache misses", 
            new[] { "cache_type" });

    private static readonly Histogram CacheLoadDuration = Metrics
        .CreateHistogram("itemscache_cache_load_duration_seconds", 
            "Duration of cache load operations in seconds", 
            new[] { "cache_type", "success" });

    private static readonly Gauge CacheSize = Metrics
        .CreateGauge("itemscache_cache_size", "Current cache size", 
            new[] { "cache_type" });

    private readonly string _cacheTypeName;

    public PrometheusMetricsRecorder()
    {
        _cacheTypeName = typeof(TCacheItem).Name;
    }

    public void RecordCacheHit(TKey key)
    {
        CacheHits.WithLabels(_cacheTypeName).Inc();
    }

    public void RecordCacheMiss(TKey key)
    {
        CacheMisses.WithLabels(_cacheTypeName).Inc();
    }

    public void RecordCacheLoad(TimeSpan duration, int itemCount, bool success)
    {
        CacheLoadDuration
            .WithLabels(_cacheTypeName, success.ToString().ToLowerInvariant())
            .Observe(duration.TotalSeconds);
    }

    public void RecordCacheSize(int count)
    {
        CacheSize.WithLabels(_cacheTypeName).Set(count);
    }

    // Implement other IMetricsRecorder methods...
}
  1. Register metrics in Program.cs:
using ItemsCache.Core.Metrics.Extensions;
using ItemsCache.Refresh.Polling.Metrics.Extensions;
using Prometheus;

// Register cache metrics
var prometheusRecorder = new PrometheusMetricsRecorder<int, Product>();
builder.Services.AddItemsCacheMetrics<int, Product>(prometheusRecorder);

// Register grouped cache metrics
builder.Services.AddItemsCacheGroupedMetrics<int, Product, string>();
builder.Services.AddItemsCacheGroupedMetrics<int, Product, bool>();

// Register polling refresh metrics
builder.Services.AddPollingRefreshMetrics<int, Product, RefreshContext>();

var app = builder.Build();

// Configure Prometheus metrics endpoint
app.UseHttpMetrics();
app.MapMetrics();
  1. Access metrics:

Once configured, metrics are available at /metrics endpoint. The following metrics are recorded:

  • itemscache_cache_hits_total - Total cache hits
  • itemscache_cache_misses_total - Total cache misses
  • itemscache_cache_load_duration_seconds - Cache load operation duration
  • itemscache_cache_refresh_duration_seconds - Cache refresh operation duration
  • itemscache_item_updates_total - Total item updates
  • itemscache_item_deletions_total - Total item deletions
  • itemscache_cache_size - Current cache size
  • itemscache_grouped_operations_total - Grouped cache operations
Custom Metrics Recorder

You can implement IMetricsRecorder<TKey, TCacheItem> to integrate with any metrics system:

public class CustomMetricsRecorder<TKey, TCacheItem> : IMetricsRecorder<TKey, TCacheItem>
    where TKey : notnull
    where TCacheItem : class
{
    public void RecordCacheHit(TKey key) { /* Your implementation */ }
    public void RecordCacheMiss(TKey key) { /* Your implementation */ }
    public void RecordCacheLoad(TimeSpan duration, int itemCount, bool success) { /* ... */ }
    // Implement other methods...
}

Custom Data Sources

Implement IDataSource<TKey, TCacheItem> to load data from any source. The LoadAllAsync method should return all items that will be cached.

Database Data Source Example
using ItemsCache.Core.Abstraction.Interfaces;
using Microsoft.EntityFrameworkCore;

public class DataFromDbSource : IDataSource<int, Product>
{
    private readonly AppDbContext _dbContext;

    public DataFromDbSource(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<IEnumerable<KeyValuePair<int, Product>>> LoadAllAsync(
        CancellationToken cancellationToken = default)
    {
        var products = await _dbContext.Set<Product>().ToListAsync(cancellationToken);
        return products.ToDictionary(p => p.Id);
    }
}
HTTP API Data Source Example
using ItemsCache.Core.Abstraction.Interfaces;
using System.Net.Http.Json;

public class ApiDataSource : IDataSource<string, User>
{
    private readonly HttpClient _httpClient;

    public ApiDataSource(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<IEnumerable<KeyValuePair<string, User>>> LoadAllAsync(
        CancellationToken cancellationToken = default)
    {
        var users = await _httpClient.GetFromJsonAsync<List<User>>("/api/users", cancellationToken);
        return users?.ToDictionary(u => u.Id) ?? new Dictionary<string, User>();
    }
}
Register Your Data Source
// Register as scoped service
builder.Services.AddScoped<IDataSource<int, Product>, DataFromDbSource>();

Grouped Cache

ItemsCache supports pre-computed grouped indexes that are automatically maintained in memory. This trades memory for CPU performance, providing O(1) lookups for grouped data.

Register Grouped Cache Services
// First, register the base cache service
builder.Services.AddItemsCache<int, Product>();

// Group by category (string key)
builder.Services.AddItemsCacheGrouped<int, Product, string>(
    p => p.Category ?? "Uncategorized");

// Group by active status (bool key)
builder.Services.AddItemsCacheGrouped<int, Product, bool>(
    p => p.IsActive);
Use Grouped Cache in Controllers
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IItemsCacheService<int, Product> _productItemsCache;
    private readonly IItemsCacheGroupedService<Product, string> _categoryGroupedCache;
    private readonly IItemsCacheGroupedService<Product, bool> _activeGroupedCache;
    private readonly ILogger<ProductsController> _logger;

    public ProductsController(
        IItemsCacheService<int, Product> productItemsCache,
        IItemsCacheGroupedService<Product, string> categoryGroupedCache,
        IItemsCacheGroupedService<Product, bool> activeGroupedCache,
        ILogger<ProductsController> logger)
    {
        _productItemsCache = productItemsCache;
        _categoryGroupedCache = categoryGroupedCache;
        _activeGroupedCache = activeGroupedCache;
        _logger = logger;
    }

    // Get all products
    [HttpGet]
    public ActionResult<IEnumerable<Product>> GetAllProducts()
    {
        var products = _productItemsCache.GetAll().ToDictionary();
        return Ok(products.Values);
    }

    // Get product by ID
    [HttpGet("{id}")]
    public ActionResult<Product> GetProduct(int id)
    {
        if (_productItemsCache.TryGetByKey(id, out var product))
        {
            return Ok(product);
        }
        return NotFound($"Product with ID {id} not found");
    }

    // Get products by category
    [HttpGet("grouped/category/{category}")]
    public ActionResult<IEnumerable<Product>> GetProductsByCategory(string category)
    {
        var products = _categoryGroupedCache.GetByGroupKey(category).ToList();
        return Ok(products);
    }

    // Get active products
    [HttpGet("grouped/active")]
    public ActionResult<IEnumerable<Product>> GetProductsGroupedByActive()
    {
        var products = _activeGroupedCache.GetByGroupKey(true);
        return Ok(products);
    }

    // Get cache statistics
    [HttpGet("cache/stats")]
    public ActionResult<object> GetCacheStats()
    {
        var allProducts = _productItemsCache.GetAll().ToDictionary();
        var stats = new
        {
            TotalProducts = allProducts.Count,
            ActiveProducts = allProducts.Values.Count(p => p.IsActive),
            Categories = allProducts.Values.Select(p => p.Category).Distinct().Count(),
            LastRetrieved = DateTime.UtcNow
        };
        return Ok(stats);
    }
}
API Endpoints Example

With the above controller, you have the following endpoints:

  • GET /api/products - Get all products
  • GET /api/products/{id} - Get product by ID
  • GET /api/products/grouped/category/{category} - Get products by category (e.g., "Electronics", "Furniture")
  • GET /api/products/grouped/active - Get all active products
  • GET /api/products/cache/stats - Get cache statistics
Key Features
  • Automatic Updates: Grouped indexes are automatically updated when cache items change
  • Memory Efficient: Pre-computed indexes eliminate CPU overhead on retrieval
  • Multiple Groupings: Register multiple grouped services for different grouping strategies
  • Thread Safe: All operations are thread-safe
  • Type Safe: Strongly typed group keys (string, bool, int, etc.)

Sample Project

A complete working example is available in the samples/SampleApi directory. This sample demonstrates all features of ItemsCache including:

  • Basic cache operations
  • Grouped cache by category and active status
  • Polling refresh with database change detection
  • Prometheus metrics integration
  • Entity Framework Core integration
  • RESTful API endpoints

Running the Sample

  1. Navigate to the sample directory:
cd samples/SampleApi
  1. Restore and build:
dotnet restore
dotnet build
  1. Run the application:
dotnet run
  1. Access the API:
  • Swagger UI: https://localhost:5001/swagger (or the port shown in console)
  • Prometheus Metrics: https://localhost:5001/metrics

Sample API Endpoints

The sample provides the following endpoints:

Method Endpoint Description
GET /api/products Get all products from cache
GET /api/products/{id} Get a specific product by ID
GET /api/products/grouped/category/{category} Get products by category
GET /api/products/grouped/active Get active products
GET /api/products/cache/stats Get cache statistics

Sample Features Demonstrated

  1. Database Integration: Uses Entity Framework Core with in-memory database
  2. Initial Data Load: Products are loaded from database on startup
  3. Polling Refresh: Cache automatically refreshes every 30 seconds (configurable)
  4. Change Detection: Only updated/deleted items are refreshed
  5. Grouped Queries: Fast O(1) lookups by category and active status
  6. Metrics: Prometheus metrics for monitoring cache performance

Sample Configuration

The sample uses the following configuration in appsettings.json:

{
  "CacheOptions": {
    "RefreshInterval": "00:00:30"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "ItemsCache": "Information"
    }
  }
}

Exploring the Sample Code

Key files to examine:

  • Program.cs - Complete service registration and configuration
  • Controllers/ProductsController.cs - API endpoints using cache services
  • Services/DataFromDbSource.cs - Initial data loading implementation
  • Services/DataFromDbSourceWithRefresh.cs - Polling refresh implementation
  • Services/PrometheusMetricsRecorder.cs - Custom metrics recorder
  • Models/Product.cs - Product entity model
  • Models/RefreshContext.cs - Refresh context for polling

Architecture

ItemsCache follows SOLID principles with a clean, modular architecture:

ItemsCache.Core.Abstraction
├── IDataSource<T>
├── IItemsCacheService<T>
└── IItemsCacheServiceWithModifications<T>

ItemsCache.Core
├── ItemsCacheService<T>
├── ItemsCacheLoader<T>
└── CacheInitHostedService

ItemsCache.Refresh.Abstraction
├── IRefreshItemCacheHandler<T>
└── IRefreshItemCacheHandlerFactory<T>

ItemsCache.Refresh.Core
├── RefreshItemCacheHandler<T>
└── RefreshItemCacheHandlerFactory<T>

ItemsCache.Refresh.Polling
├── PollingRefreshService<T>
└── PollingRefreshHostedService<T>

ItemsCache.RetryPolicy.Abstraction
├── IRetryPolicy<T>
└── RetryPolicyOptions<T>

ItemsCache.RetryPolicy.Polly
└── PollyRetryPolicy<T>

Performance Considerations

  • Memory Efficient: Uses weak references and proper disposal patterns
  • Thread Safe: All operations are thread-safe and optimized for concurrent access
  • Lazy Loading: Data is loaded only when needed
  • Background Processing: Refresh operations don't block main thread
  • Configurable Limits: Set memory and performance limits as needed

Contributing

We welcome contributions! Please see our Contributing Guidelines for details.

Development Setup

  1. Clone the repository
  2. Install .NET 9.0 SDK
  3. Run dotnet restore
  4. Run dotnet build
  5. Run dotnet test

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Changelog

See CHANGELOG.md for a list of changes and version history.


Made with ❤️ by the ItemsCache Contributors

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.1-preview.18 97 12/12/2025