v2.0.0
Major release. Breaking changes from v1.x. See docs/MIGRATION-V1-TO-V2.md.
Highlights
- Multi-target
net8.0,net9.0,net10.0(single package). KeyPrefixmandatory across all modes (replacesRedisInstanceName).- Striped lock manager with stable hashing — no per-key allocation, no leak.
- Polly v8 resilience pipelines (timeout + circuit breaker + retry) per backend.
- OpenTelemetry-native via static
CacheInstruments.ICacheTelemetryremoved. PayloadEnvelopewire format with schema-drift detection.LoggerMessagesource-gen for hot-path logs.- New API surface:
GetAsync,ExistsAsync,RefreshAsync,GetManyAsync,SetManyAsync,RemoveManyAsync. CacheCallOptions:AbsoluteExpiration,SlidingExpiration,AllowStaleFor,Tags,JitterPercentage,FactoryTimeout.CacheKey.For<T>(id).WithVariant(...).Build()canonical key builder.MessagePackCacheSerializeropt-in viaWithMessagePackSerializer().- Stale-while-revalidate orchestrator (in-process registry; bounded background refresh).
- TTL jitter (
WithTtlJitter(0.10)default). - TLS certificate audit logging +
cache.tls.validationcounter. - Credential rotation hook (
RedisConnectionRotatorreloads multiplexer on options change). - Server-side Redis MGET/MSET/KeyDelete pipelining (when
IConnectionMultiplexeris registered). - Brotli payload compression for Redis with pooled-buffer encode/decode helpers and a decompression output safety cap.
- AOT/trim verified via
Caching.NET.AotSmokesmoke project. - Testcontainers Redis integration suite, Polly chaos suite, FsCheck property suite.
- BenchmarkDotNet perf-gate via
scripts/dev.ps1 bench:gate(10% regression threshold). - SPDX 2.2 SBOM emitted with the nupkg.
- New public API surface ships under NuGet package validation (
EnablePackageValidationonCaching.NET.csproj); breaking or additive changes require an intentional baseline/package-version decision for the next tag.
Post-audit hardening
Enabled=false: skip backend DI (memory/Redis/hybrid, serializer, Polly); options validation skipped; routing still resolves and short-circuits.- Health probe: Redis/Hybrid uses multiplexer
PING+ per-process probe key suffix; avoids false-healthy whenFailOpenmasks cache errors. Liveness cancellation symmetry and readiness warm/read split. - Resilience: broader transient classification, tighter retry backoff defaults, optional Redis concurrency limiter.
- Telemetry:
cache.serialize.duration/cache.deserialize.duration; drift warning logs sampled per key fingerprint viaDriftLogSamplerwith bounded dictionary growth. - Validation: Redis connection string parse; prefix + user-key budget vs
MaximumKeyLength; full prefixed key length enforced at routing. - Correctness:
StaleEntryTrackercap/prune;RoutingCacheServiceasync disposal with hardened stale-refresh disposal/race handling; Hybrid value-typeGetAsyncmiss path; stricterPayloadEnvelopelength check; safer multiplexer rotation disposal;RedisConnectionRotator.Dispose()synchronous and deterministic. - Builder:
Enable(), environment presets,WithKeyValidator/WithKeyTransformer;CachingBuilderis configured viaAddCaching(...). - Resilience public surface: configure timeouts/breaker/retry/concurrency via
CachingBuilder.WithResilience(Action<CacheResilienceOptions>)only.CacheResiliencePipelineBuilderis not public — Polly registry types are not part of the shipped contract (Option B). - Health checks: optional Kubernetes-style split —
WithHealthChecks(splitLivenessReadiness: true)registersCachingLivenessHealthCheck+CachingHealthCheckas{name}-liveness/{name}-readinesswith tagsliveness/readiness. ICacheKeyFactory/DefaultCacheKeyFactory: DI-resolvable key builder (mirrorsCacheKey.For); register a customICacheKeyFactorybeforeAddCachingto inject tenant/segment logic.- Performance (audit §3.3):
PayloadEnvelope.Writeallocates the wirebyte[]withGC.AllocateUninitializedArray;StableStringHashusesArrayPool<byte>for large UTF-8 encodings (>512 B).ICacheServicestaysTask/Task<T>— aValueTaskmigration was prototyped and reverted before ship: the alloc savings on synchronous in-memory hits did not justify the breaking-change cost across consumer code, mocking frameworks, and decorators in mixed Hybrid/Redis production workloads. - Schema hash (B5): envelope schema hash uses
Type.FullName+ optional[CacheSchema]so library/package version bumps do not invalidate Redis entries; existing entries written with the older assembly-qualified hash may schema-drift once after upgrade. - KeyPrefix (B6):
':'is no longer allowed insideKeyPrefix— avoids ambiguous physical keys when routing inserts':'between prefix and user segment. PreferserviceName-environmentnaming (e.g.asm-api-dev). - Breaking:
ICacheSerializer.Deserialize<T>now takesReadOnlyMemory<byte>(wasReadOnlySpan<byte>). Custom serializers must update;MessagePackCacheSerializerno longer allocates viaToArray()on deserialize when paired with Redis envelope payloads (zero-copy path). - Configuration section naming: Documentation and samples use the JSON section
CacheOptionsand environment prefixCacheOptions__(matchesCacheConfigurationKeys.CacheOptions). Configurations copied from older snippets that used"Caching"must be renamed. CachingBuilderTLS controls:WithStrictCertificateValidation()andWithPermissiveRedisTls()setCacheOptions.StrictRedisCertificateValidation; fluent intent overrides configuration when either method is used (nullable builder state replaces the previous always-true strict flag).CacheSerializerOptions: When the host does not callConfigure<CacheSerializerOptions>, registration now initializesJsonSerializerOptionstoJsonSerializerDefaults.Webso[Required]/ValidateDataAnnotations+ValidateOnStart()succeed.
Samples
- Expanded
Caching.NET.Samplecoverage for v2 APIs: key hooks, custom key factory,[CacheSchema], resilience tuning, split health checks, payload compression options, optionalPOSTRedis round-trip probe (redis/validate) withCacheCallOptionsmode override, Makefilesample-redis-validate, permissive TLS example for custom-host Redis alongside strict library defaults.
Removed
- Public surface for
CachingHealthCheckandCachingLivenessHealthCheck— types are internal; useWithHealthChecks()/AddCachingHealthChecks()only (instantiation from app code is unsupported). ICacheTelemetry,NoopCacheTelemetry,OpenTelemetryCacheTelemetry.CacheOptions.RedisInstanceName,CachingBuilder.WithRedisInstanceName.RemoveAsync(IEnumerable<string>)(renamed toRemoveManyAsync).- All synchronous overloads (v2 is async-only).
Defaults changed
Mode:Hybrid→InMemory(zero-config friendlier).StrictRedisCertificateValidation:false→true.MaximumKeyLength:null→512.TtlJitterPercentage:0.0→0.10.