RepletoryLib.Caching.Abstractions 1.0.0

dotnet add package RepletoryLib.Caching.Abstractions --version 1.0.0
                    
NuGet\Install-Package RepletoryLib.Caching.Abstractions -Version 1.0.0
                    
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="RepletoryLib.Caching.Abstractions" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RepletoryLib.Caching.Abstractions" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="RepletoryLib.Caching.Abstractions" />
                    
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 RepletoryLib.Caching.Abstractions --version 1.0.0
                    
#r "nuget: RepletoryLib.Caching.Abstractions, 1.0.0"
                    
#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 RepletoryLib.Caching.Abstractions@1.0.0
                    
#: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=RepletoryLib.Caching.Abstractions&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=RepletoryLib.Caching.Abstractions&version=1.0.0
                    
Install as a Cake Tool

RepletoryLib.Caching.Abstractions

Caching abstractions and interfaces for the RepletoryLib ecosystem.

Part of the RepletoryLib ecosystem -- standalone, reusable .NET 10 libraries with zero business logic.

NuGet .NET 10 License: MIT


Overview

RepletoryLib.Caching.Abstractions defines the contracts for caching and distributed locking in the RepletoryLib ecosystem. By programming against these interfaces, your application code remains decoupled from any specific caching technology -- you can swap between in-memory, Redis, or hybrid caching without changing a single line of business logic.

This package contains interfaces only -- no implementations. Choose one of the implementation packages below based on your needs.

Choosing an Implementation

Package Technology Best For
RepletoryLib.Caching.InMemory IMemoryCache Single-instance apps, development, unit testing
RepletoryLib.Caching.Redis StackExchange.Redis + RedLock.net Distributed apps, production, persistent cache
RepletoryLib.Caching.Hybrid InMemory (L1) + Redis (L2) Best performance -- local speed with distributed consistency

Key Features

  • ICacheService -- Get, set, remove, exists, prefix-based eviction, and cache-aside pattern
  • IDistributedLockService -- Acquire and release distributed locks for concurrency control
  • CacheOptions -- Shared configuration for default expiry, key prefix, and compression

Installation

dotnet add package RepletoryLib.Caching.Abstractions

Or add to your .csproj:

<PackageReference Include="RepletoryLib.Caching.Abstractions" Version="1.0.0" />

Note: RepletoryLib packages are published to a local BaGet feed. See the main repository README for feed configuration.

Dependencies

Package Type
RepletoryLib.Common RepletoryLib

Usage Examples

Cache-Aside Pattern

The most common caching pattern -- check the cache first, fall back to the data source, and populate the cache for next time:

using RepletoryLib.Caching.Abstractions.Interfaces;

public class ProductService
{
    private readonly ICacheService _cache;
    private readonly IProductRepository _repository;

    public ProductService(ICacheService cache, IProductRepository repository)
    {
        _cache = cache;
        _repository = repository;
    }

    public async Task<Product?> GetProductAsync(Guid id)
    {
        var cacheKey = $"product:{id}";

        return await _cache.GetOrSetAsync(cacheKey, async () =>
        {
            return await _repository.GetByIdAsync(id);
        }, TimeSpan.FromMinutes(30));
    }
}

Basic Get / Set / Remove

using RepletoryLib.Caching.Abstractions.Interfaces;

public class SessionService
{
    private readonly ICacheService _cache;

    public SessionService(ICacheService cache) => _cache = cache;

    public async Task CreateSessionAsync(string sessionId, UserSession session)
    {
        await _cache.SetAsync($"session:{sessionId}", session, TimeSpan.FromHours(1));
    }

    public async Task<UserSession?> GetSessionAsync(string sessionId)
    {
        return await _cache.GetAsync<UserSession>($"session:{sessionId}");
    }

    public async Task EndSessionAsync(string sessionId)
    {
        await _cache.RemoveAsync($"session:{sessionId}");
    }

    public async Task<bool> IsActiveAsync(string sessionId)
    {
        return await _cache.ExistsAsync($"session:{sessionId}");
    }
}

Prefix-Based Cache Invalidation

Invalidate all cache entries that share a prefix:

// Cache product data with a shared prefix
await _cache.SetAsync("product:123:details", product);
await _cache.SetAsync("product:123:reviews", reviews);
await _cache.SetAsync("product:123:pricing", pricing);

// When the product is updated, evict everything related to it
await _cache.RemoveByPrefixAsync("product:123:");

Distributed Locking

Use IDistributedLockService to prevent concurrent access to shared resources:

using RepletoryLib.Caching.Abstractions.Interfaces;

public class PaymentProcessor
{
    private readonly IDistributedLockService _locks;

    public PaymentProcessor(IDistributedLockService locks) => _locks = locks;

    public async Task ProcessPaymentAsync(Guid orderId, decimal amount)
    {
        var lockId = await _locks.AcquireAsync(
            resource: $"payment:{orderId}",
            expiry: TimeSpan.FromSeconds(30));

        if (lockId is null)
            throw new InvalidOperationException("Payment already being processed");

        try
        {
            // Only one instance can process this payment at a time
            await ChargeCustomerAsync(orderId, amount);
        }
        finally
        {
            await _locks.ReleaseAsync(lockId);
        }
    }
}

API Reference

ICacheService

public interface ICacheService
{
    Task<T?> GetAsync<T>(string key, CancellationToken cancellationToken = default);

    Task SetAsync<T>(string key, T value, TimeSpan? expiry = null,
        CancellationToken cancellationToken = default);

    Task RemoveAsync(string key, CancellationToken cancellationToken = default);

    Task RemoveByPrefixAsync(string prefix, CancellationToken cancellationToken = default);

    Task<bool> ExistsAsync(string key, CancellationToken cancellationToken = default);

    Task<T?> GetOrSetAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiry = null,
        CancellationToken cancellationToken = default);
}
Method Description
GetAsync<T> Retrieves a cached value by key. Returns null if not found.
SetAsync<T> Stores a value with an optional expiry. Uses default expiry if not specified.
RemoveAsync Removes a single cached entry.
RemoveByPrefixAsync Removes all entries whose keys start with the given prefix.
ExistsAsync Checks if a key exists in the cache.
GetOrSetAsync<T> Cache-aside pattern -- returns cached value or invokes factory, caches the result, and returns it.

IDistributedLockService

public interface IDistributedLockService
{
    Task<string?> AcquireAsync(string resource, TimeSpan expiry,
        CancellationToken cancellationToken = default);

    Task ReleaseAsync(string lockId, CancellationToken cancellationToken = default);
}
Method Description
AcquireAsync Attempts to acquire a lock on a resource. Returns a lock ID on success, null if the resource is already locked. The lock expires automatically after the specified duration.
ReleaseAsync Releases a previously acquired lock by its lock ID.

CacheOptions

public class CacheOptions
{
    public int DefaultExpiryMinutes { get; set; } = 60;
    public string KeyPrefix { get; set; } = "";
    public bool EnableCompression { get; set; }
}
Property Type Default Description
DefaultExpiryMinutes int 60 Default cache entry lifetime when no expiry is specified
KeyPrefix string "" Prefix prepended to all cache keys (useful for namespace isolation)
EnableCompression bool false Enable compression for serialized cache values

Integration with Other RepletoryLib Packages

Package Relationship
RepletoryLib.Common Direct dependency -- provides base types
RepletoryLib.Caching.InMemory In-memory implementation of ICacheService
RepletoryLib.Caching.Redis Redis implementation of ICacheService and IDistributedLockService
RepletoryLib.Caching.Hybrid L1/L2 implementation combining InMemory + Redis
RepletoryLib.Auth.Jwt Uses ICacheService for token blacklist caching
RepletoryLib.Testing Provides MockCacheService for unit testing

Testing

Use MockCacheService from RepletoryLib.Testing to test code that depends on ICacheService:

using RepletoryLib.Testing;

public class ProductServiceTests : TestBase
{
    [Fact]
    public async Task GetProduct_caches_result()
    {
        Setup();
        Services.AddTransient<ProductService>();
        var provider = BuildServiceProvider();
        var service = provider.GetRequiredService<ProductService>();

        var product = await service.GetProductAsync(Guid.NewGuid());

        MockCache.SetCalls.Should().HaveCount(1);
    }

    [Fact]
    public async Task GetProduct_returns_cached_value()
    {
        Setup();
        var productId = Guid.NewGuid();
        var expected = new Product { Id = productId, Name = "Widget" };
        await MockCache.SetAsync($"product:{productId}", expected);

        Services.AddTransient<ProductService>();
        var provider = BuildServiceProvider();
        var service = provider.GetRequiredService<ProductService>();

        var result = await service.GetProductAsync(productId);

        result.Should().BeEquivalentTo(expected);
    }
}

Troubleshooting

Issue Solution
ICacheService not registered in DI You need to install and register an implementation package (InMemory, Redis, or Hybrid)
IDistributedLockService returns null Only the Redis implementation supports distributed locks. InMemory has no lock support.
Cache keys colliding across services Use CacheOptions.KeyPrefix to namespace keys per service or per tenant

License

This project is licensed under the MIT License.

Copyright (c) 2024-2026 Repletory.


For complete documentation, infrastructure setup, and configuration reference, see the RepletoryLib main repository.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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 (7)

Showing the top 5 NuGet packages that depend on RepletoryLib.Caching.Abstractions:

Package Downloads
RepletoryLib.Caching.InMemory

In-memory caching implementation for RepletoryLib

RepletoryLib.Caching.Redis

Redis caching implementation for RepletoryLib

RepletoryLib.Testing

Test helpers, mocks, and base classes for RepletoryLib

RepletoryLib.Auth.Jwt

JWT authentication and token management for RepletoryLib

RepletoryLib.Ai.ContentGeneration

Template-based AI content generation with variable substitution, streaming, and optional caching for RepletoryLib

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 112 3/2/2026