CasCap.Common.Caching 4.17.0

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

CasCap.Common.Caching

Multi-tier distributed caching library implementing the cache-aside pattern with support for Memory, Disk, and Redis cache layers.

Installation

dotnet add package CasCap.Common.Caching

Target frameworks: netstandard2.0, net8.0, net9.0, net10.0

Usage

For local memory caching, disable the remote tier explicitly:

using System;
using CasCap.Common.Models;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using AppCache = CasCap.Common.Abstractions.IDistributedCache;

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddCasCapCaching(options =>
    options.RemoteCache = options.RemoteCache with { IsEnabled = false });

using var host = builder.Build();
await host.StartAsync();
var cache = host.Services.GetRequiredService<AppCache>();

await cache.Set("greeting", "Hello", slidingExpiration: TimeSpan.FromMinutes(5));
Console.WriteLine(await cache.Get<string>("greeting")); // Hello
await host.StopAsync();

CasCap.Common.Abstractions.IDistributedCache is the object-cache API, not Microsoft's byte-cache interface with the same name. Get<T> can take an asynchronous factory for a cache miss. Concurrent misses for the same key run the factory once per application instance, and once across instances when DistributedLockingEnabled is set. Waiting callers re-read the populated entry. If the distributed lock times out, the factory still runs so the caller never receives a spurious miss. Set, Delete and DeleteAll affect the enabled layers.

To use application configuration, replace the registration with builder.Services.AddCasCapCaching(builder.Configuration). The section defaults to CasCap:CachingConfig. Overloads also accept a CachingConfig instance or an Action<CachingConfig>. A non-empty connection string opens Redis during registration and returns its ConnectionMultiplexer for reuse. Without one, registration supplies NullRemoteCache; it does not automatically turn off RemoteCache.IsEnabled.

Select memory or disk with the LocalCacheType argument. This selects the implementation; enabling DiskCache in JSON alone does not switch from memory to disk.

Cache Layers

Service Description
DistributedCacheService Reads local first, then an enabled remote tier, then an optional factory; supports opt-in Redis locking
RedisCacheService IRemoteCache implementation wrapping StackExchange.Redis with optional Lua script support
NullRemoteCache No-op IRemoteCache implementation used for local-only caching. Redis infrastructure properties throw NotSupportedException
MemoryCacheService ILocalCache implementation backed by IMemoryCache
DiskCacheService ILocalCache implementation persisting cache entries to disk
CacheExpiryBgService Coordinates expiry subscribers when Redis is registered and CacheExpiryServiceEnabled is true
LocalCacheExpiryService Handles local cache entry expiration. Disable via LocalCacheExpiryServiceEnabled
RemoteCacheExpiryService Handles remote cache entry expiration. Disable via RemoteCacheExpiryServiceEnabled

Leadership Election

The current checkout also provides ILeadershipRunner on .NET 8 and later. This API is provisional and not yet available in the published package; use local Debug project references while validating consumers, without publishing a package for each contract refinement.

Inject the runner into a background feature and await RunAsync("example-worker", RunProtectedWorkAsync, stoppingToken). All replicas of the same worker must use the same logical resource. RunProtectedWorkAsync(CancellationToken) must stay active until cancelled, pass its token to all I/O and child work, and await cleanup before returning.

  • Registration uses the existing Redis connection, database, key format and distributed-lock factory. Configure Redis and DistributedLockingEnabled: true. The runner is registered only when a lock factory is available; an elected consumer without those prerequisites fails dependency resolution rather than running unprotected. Local-only caching and disabled locking remain usable with startup dependency validation enabled, without registering an elected consumer.
  • Leadership uses Redlock.GetTimings(RedlockProfiles.LeaderElection); short cache-miss locks still use root timings and never enter the election loop.
  • Redlock.LeadershipCheckIntervalMs defaults to 1000, and controls lease-state observation only. RedLock.net renews the lease. A failed acquisition waits the profile retry interval before contending again.
  • Observed loss cancels the worker, awaits its cleanup, disposes the lease, then reacquires. Graceful shutdown awaits cleanup before releasing a still-held lease.
  • Worker failures and unexpected normal completion propagate instead of restarting silently. Cleanup has no runner timeout: configure the host and container termination budgets explicitly. An uncooperative worker is not abandoned and no replacement run starts while it is still active.
  • Lease polling has a detection delay; it is not downstream fencing or an exactly-once guarantee.

All caching registration overloads expose the same CachingConfig.Redlock instance through IOptions<RedlockConfig>. Repeated registration preserves the first configuration. Root timings, named profile timings and the leadership check interval are validated through the caching options.

Configuration

Type Description
CachingConfig Main configuration record — RemoteCacheConnectionString, PubSubPrefix, MemoryCacheSizeLimit, UseBuiltInLuaScripts, DiskCacheFolder, ExpirationSyncMode, DistributedLockingEnabled, CacheAsideDisabled, CacheKeyFormat, HealthCheckRedis, CacheExpiryServiceEnabled, LocalCacheExpiryServiceEnabled, RemoteCacheExpiryServiceEnabled, Redlock
RedlockConfig Timing parameters for Redis distributed locks with named profile support — root defaults (ExpiryMs 5s, WaitMs 5s, RetryMs 250ms) tuned for cache-miss protection. RedisKeyFormat for lock key prefixing. Built-in LeaderElection profile (30s/60s/5s) for long-lived locks. Custom profiles via Profiles dictionary
RedlockProfiles Well-known profile name constants — CacheMiss, LeaderElection
RedlockTimingProfile Timing values for a single named lock profile — ExpiryMs, WaitMs, RetryMs
CacheParameters Per-layer enablement, database, startup clearing and serialization

CacheParameters exposes IsEnabled, DatabaseId, ClearOnStartup and SerializationType; entry lifetimes are passed to Get or Set, not stored in this record. ClearOnStartup defaults to false. Enabling it can delete existing cache data.

Important defaults:

Setting Default
RemoteCacheConnectionString null; no Redis registration
MemoryCache.IsEnabled, DiskCache.IsEnabled, RemoteCache.IsEnabled true; select and configure layers deliberately
MemoryCache.SerializationType None
DiskCache.SerializationType Json
RemoteCache.SerializationType MessagePack
LocalCacheInvalidationEnabled true
CacheExpiryServiceEnabled, LocalCacheExpiryServiceEnabled, RemoteCacheExpiryServiceEnabled true
ExpirationSyncMode None
DistributedLockingEnabled, UseBuiltInLuaScripts, CacheAsideDisabled false
HealthCheckRedis Liveness; Redis health-check registration is .NET 8+ only
MemoryCacheSizeLimit null; no configured limit
CacheKeyFormat {0}
Redlock.LeadershipCheckIntervalMs 1000; .NET 8+ leadership observation only

PubSubPrefix distinguishes this instance's own invalidation messages; choose a distinct value per instance when overriding it. HealthCheckRedis: None suppresses Redis check registration.

Serialization and Expiration Modes

Enum Values
CacheType None, Memory, Disk, Redis
SerializationType None, Json, MessagePack
ExpirationSyncType None, ExpireViaPubSub, ExtendRemoteExpiry

Service Architecture

Multi-tier caching infrastructure with cache-aside pattern:

flowchart TD
    CLIENT["Application Code"]

    subgraph CachingServices["Caching Services"]
        DIST["DistributedCacheService<br/>(Multi-tier orchestrator)"]

        subgraph LocalCaches["Local Cache Implementations"]
            MEM["MemoryCacheService<br/>(IMemoryCache)"]
            DISK["DiskCacheService<br/>(File system)"]
        end

        subgraph RemoteCaches["Remote Cache"]
            REDIS["RedisCacheService<br/>(StackExchange.Redis)"]
            NULL_REMOTE["NullRemoteCache<br/>(Local-only no-op)"]
        end

        subgraph BackgroundServices["Background Services"]
            EXPIRY_BG["CacheExpiryBgService"]
            LOCAL_EXP["LocalCacheExpiryService"]
            REMOTE_EXP["RemoteCacheExpiryService"]
        end
    end

    REDIS_SERVER[("Redis Server<br/>(Pub/Sub)")]
    LOCK["AsyncDuplicateLock<br/>(In-process coordination)"]
    REDLOCK["IDistributedLockFactory<br/>(RedLock.net — optional)"]
    LEADER["LeadershipRunner<br/>(.NET 8+)"]

    CLIENT --> DIST
    DIST -->|Choose one local implementation| MEM
    DIST -->|Choose one local implementation| DISK
    DIST --> REDIS
    DIST -.local-only.-> NULL_REMOTE
    DIST -.uses.-> LOCK
    DIST -."opt-in distributed lock".-> REDLOCK
    CLIENT --> LEADER
    LEADER --> REDLOCK

    REDIS <--> REDIS_SERVER
    REDLOCK -."Redlock algorithm".-> REDIS_SERVER

    EXPIRY_BG --> LOCAL_EXP
    EXPIRY_BG --> REMOTE_EXP

    REDIS_SERVER -."Pub/Sub expiry sync".-> LOCAL_EXP
    REDIS_SERVER -."Pub/Sub expiry sync".-> REMOTE_EXP

    LOCAL_EXP -.expires.-> MEM
    LOCAL_EXP -.expires.-> DISK
    REMOTE_EXP -.expires.-> REDIS

Configuration Examples

The configuration overload reads CasCap:CachingConfig. Omitted properties retain record defaults. The examples below are alternatives, not a set of sections to merge indiscriminately.

Minimal — local memory cache only

{
  "CasCap": {
    "CachingConfig": {
      "RemoteCache": {
        "IsEnabled": false
      }
    }
  }
}

Redis remote cache with JSON serialization

{
  "CasCap": {
    "CachingConfig": {
      "RemoteCacheConnectionString": "redis.example.com:6379,abortConnect=false",
      "RemoteCache": {
        "SerializationType": "Json"
      }
    }
  }
}

Disabling the expiry background services

Each background service can be switched off independently. CacheExpiryServiceEnabled: false prevents the CacheExpiryBgService hosted service being registered at all; the two granular toggles keep the hosted service registered but skip the individual subscriber.

{
  "CasCap": {
    "CachingConfig": {
      "RemoteCacheConnectionString": "redis.example.com:6379,abortConnect=false",
      "CacheExpiryServiceEnabled": true,
      "LocalCacheExpiryServiceEnabled": false,
      "RemoteCacheExpiryServiceEnabled": true
    }
  }
}

Distributed locking enabled (cache-miss protection)

{
  "CasCap": {
    "CachingConfig": {
      "RemoteCacheConnectionString": "redis.example.com:6379,abortConnect=false",
      "DistributedLockingEnabled": true,
      "RemoteCache": {
        "SerializationType": "Json"
      }
    }
  }
}

Distributed locking with custom Redlock profiles

{
  "CasCap": {
    "CachingConfig": {
      "RemoteCacheConnectionString": "redis.example.com:6379,abortConnect=false",
      "DistributedLockingEnabled": true,
      "RemoteCache": {
        "SerializationType": "Json"
      },
      "Redlock": {
        "ExpiryMs": 5000,
        "WaitMs": 5000,
        "RetryMs": 250,
        "Profiles": {
          "LeaderElection": {
            "ExpiryMs": 30000,
            "WaitMs": 60000,
            "RetryMs": 5000
          }
        }
      }
    }
  }
}

Extended Configuration

{
  "CasCap": {
    "CachingConfig": {
      "RemoteCacheConnectionString": "redis.example.com:6379,abortConnect=false,connectTimeout=1000",
      "DistributedLockingEnabled": true,
      "CacheKeyFormat": "Example:{0}",
      "MemoryCacheSizeLimit": 500,
      "UseBuiltInLuaScripts": true,
      "DiskCacheFolder": "./cache",
      "ExpirationSyncMode": "ExpireViaPubSub",
      "MemoryCache": {
        "IsEnabled": true,
        "ClearOnStartup": false,
        "SerializationType": "None"
      },
      "DiskCache": {
        "IsEnabled": false,
        "SerializationType": "Json"
      },
      "RemoteCache": {
        "IsEnabled": true,
        "DatabaseId": 1,
        "ClearOnStartup": false,
        "SerializationType": "MessagePack"
      },
      "Redlock": {
        "RedisKeyFormat": "Example:RedLock:{0}",
        "ExpiryMs": 5000,
        "WaitMs": 5000,
        "RetryMs": 250,
        "Profiles": {
          "LeaderElection": {
            "ExpiryMs": 30000,
            "WaitMs": 60000,
            "RetryMs": 5000
          },
          "LongRunningJob": {
            "ExpiryMs": 120000,
            "WaitMs": 30000,
            "RetryMs": 10000
          }
        }
      }
    }
  }
}

Replace the example endpoint and supply authentication through a secret provider, not tracked JSON. For Redis expiration housekeeping, enable expired-key event notifications on the server, such as notify-keyspace-events Ex. Run the application host so its enabled subscribers execute.

Distributed locking coordinates factory execution across instances but is not a guarantee of exactly-once work. Handle a missing cache result if lock acquisition fails. Use CacheAsideDisabled to call the factory directly; sets and deletes then become no-ops.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  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 was computed.  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 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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (8)

Showing the top 5 NuGet packages that depend on CasCap.Common.Caching:

Package Downloads
CasCap.Common.AI

AI and LLM integration abstractions for OpenAI, Ollama, and Model Context Protocol.

CasCap.Api.Knx

.NET client library for KNX building automation — connects via KNXnet/IP tunnelling or routing, monitors group-address telegrams, and fans events out to configurable sinks.

CasCap.Api.DoorBird

.NET client library for DoorBird IP video door station — captures doorbell, motion and RFID events via the local LAN API and dispatches them to configurable sinks.

CasCap.Api.DoorBird.Sinks

Pluggable event sink implementations (Redis, Azure Tables, Azure Blob Storage) for the CasCap.Api.DoorBird door station integration library.

CasCap.Api.Fronius.Sinks

Pluggable event sink implementations (Redis, Azure Tables) for the CasCap.Api.Fronius solar inverter integration library.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.17.0 117 10/24/2026
4.16.0 188 10/21/2026
4.15.0 141 10/6/2026
4.14.4 152 10/4/2026
4.14.3 151 9/28/2026
4.14.2 178 9/25/2026
4.14.1 188 9/23/2026
4.14.0 471 9/19/2026
4.13.0 145 9/15/2026
4.12.8 262 9/10/2026
4.12.7 210 9/4/2026
4.12.6 147 9/1/2026
4.12.5 208 8/20/2026
4.12.4 248 8/18/2026
4.12.3 304 7/15/2026
4.12.2 318 6/26/2026
4.12.1 304 6/14/2026
4.12.0 289 6/12/2026
4.11.9 295 6/10/2026
4.11.8 294 5/27/2026
Loading failed