LowCodeHub.AdvancedHybridCache
0.0.3
dotnet add package LowCodeHub.AdvancedHybridCache --version 0.0.3
NuGet\Install-Package LowCodeHub.AdvancedHybridCache -Version 0.0.3
<PackageReference Include="LowCodeHub.AdvancedHybridCache" Version="0.0.3" />
<PackageVersion Include="LowCodeHub.AdvancedHybridCache" Version="0.0.3" />
<PackageReference Include="LowCodeHub.AdvancedHybridCache" />
paket add LowCodeHub.AdvancedHybridCache --version 0.0.3
#r "nuget: LowCodeHub.AdvancedHybridCache, 0.0.3"
#:package LowCodeHub.AdvancedHybridCache@0.0.3
#addin nuget:?package=LowCodeHub.AdvancedHybridCache&version=0.0.3
#tool nuget:?package=LowCodeHub.AdvancedHybridCache&version=0.0.3
LowCodeHub.AdvancedHybridCache
A typed, region-aware wrapper over Microsoft.Extensions.Caching.Hybrid for .NET 10.
It keeps the native HybridCache behavior, including stampede protection, local cache, distributed cache support, tag invalidation, and serializer extensibility, while adding a small LowCodeHub-friendly API:
CacheKeyfor collision-safe region/key composition.IAdvancedHybridCachefor get, set, remove, and tag invalidation operations.CacheGetResult<T>for explicit cache hit/miss results.AddAdvancedHybridCache(...)for DI registration that still returnsIHybridCacheBuilder.
Why This Library?
| Feature | LowCodeHub.AdvancedHybridCache |
|---|---|
| Region-aware keys | CacheKey("products", productId.ToString()) |
| Collision-safe formatting | Length-prefixed region/key string |
| Explicit try-get | CacheGetResult<T> separates misses from cached defaults |
| Tag invalidation | Tags flow to HybridCache on get/set |
| Stampede protection | Delegates to HybridCache GetOrCreateAsync |
| Local + distributed cache | Uses the native HybridCache backend model |
| Serializer extensibility | Returns IHybridCacheBuilder for serializer chaining |
| Package conventions | Targets net10.0, ships README, MIT licensed |
Installation
dotnet add package LowCodeHub.AdvancedHybridCache
Targets net10.0.
Quick Start
using LowCodeHub.AdvancedHybridCache.Abstractions;
using LowCodeHub.AdvancedHybridCache.Extensions;
using LowCodeHub.AdvancedHybridCache.Models;
using Microsoft.Extensions.Caching.Hybrid;
builder.Services
.AddAdvancedHybridCache(options =>
{
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(10),
LocalCacheExpiration = TimeSpan.FromMinutes(2)
};
});
Use it from application services:
public sealed class ProductService(IAdvancedHybridCache cache)
{
public ValueTask<Product> GetProductAsync(Guid productId, CancellationToken cancellationToken = default)
{
var cacheKey = new CacheKey(
region: "products",
key: productId.ToString(),
tags: ["products"]);
return cache.GetOrCreateAsync(
cacheKey,
token => LoadProductAsync(productId, token),
cancellationToken);
}
private static ValueTask<Product> LoadProductAsync(Guid productId, CancellationToken cancellationToken)
{
// Load from your database, API, or other source of truth.
throw new NotImplementedException();
}
}
Try-Get Without Ambiguous Defaults
HybridCache primarily exposes GetOrCreateAsync. This package adds a try-get shape that does not confuse a cache miss with a cached default value:
var result = await cache.TryGetAsync<int>(
new CacheKey("product-inventory", productId.ToString(), ["inventory"]),
cancellationToken);
if (!result.Found)
{
return Results.NotFound();
}
return Results.Ok(result.Value);
This matters for valid cached values such as:
0falsenulldefault(T)
Use result.Found to decide whether the entry exists. Use result.Value only after that check.
Cache Keys
CacheKey has three parts:
| Property | Required | Purpose |
|---|---|---|
Region |
Yes | Logical namespace, such as products, users, or permissions |
Key |
Yes | Entry identity within the region |
Tags |
No | Tags passed to HybridCache for group invalidation |
var cacheKey = new CacheKey(
region: "tenant-settings",
key: tenantId.ToString(),
tags: [$"tenant:{tenantId}", "tenant-settings"]);
The generated cache key is length-prefixed, so regions and keys that contain : do not collide.
Set and Remove
Set a value directly:
await cache.SetAsync(
new CacheKey("feature-flags", tenantId.ToString(), [$"tenant:{tenantId}", "feature-flags"]),
flags,
cancellationToken);
Set with per-entry expiration:
await cache.SetAsync(
new CacheKey("reports", reportId.ToString(), ["reports"]),
report,
new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromHours(1),
LocalCacheExpiration = TimeSpan.FromMinutes(5)
},
cancellationToken);
Remove one entry:
await cache.RemoveAsync(new CacheKey("products", productId.ToString()), cancellationToken);
Remove entries by tag:
await cache.RemoveByTagAsync("products", cancellationToken);
Distributed Cache Backend
AddAdvancedHybridCache registers Microsoft HybridCache. If your application also registers an IDistributedCache implementation, HybridCache can use it as the distributed tier.
Redis example:
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("Redis");
});
builder.Services.AddAdvancedHybridCache();
Without a distributed cache registration, HybridCache still provides local in-process caching.
Serializers
The registration method returns IHybridCacheBuilder, so you can configure serializers exactly as you would with native HybridCache:
builder.Services
.AddAdvancedHybridCache()
.AddSerializerFactory<MyHybridCacheSerializerFactory>();
Use a serializer factory when your cached payload types need custom serialization behavior.
The wrapper stores cached values in CacheGetResult<T> so it can preserve hit/miss semantics for cached default values. Prefer serializer factories that can handle generic wrapper types, or rely on the default System.Text.Json-based serializer for regular POCO payloads.
Configuration
Example appsettings shape:
{
"HybridCache": {
"DefaultExpiration": "00:10:00",
"DefaultLocalExpiration": "00:02:00"
}
}
Example binding:
builder.Services.AddAdvancedHybridCache(options =>
{
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = builder.Configuration.GetValue<TimeSpan>("HybridCache:DefaultExpiration"),
LocalCacheExpiration = builder.Configuration.GetValue<TimeSpan>("HybridCache:DefaultLocalExpiration")
};
});
Behavior Notes
GetOrCreateAsyncuses HybridCache stampede protection for concurrent misses.TryGetAsyncnever calls a source callback; it returnsFound = falseon a miss.- Tags are not part of the cache identity; they are passed to HybridCache for invalidation.
CacheKey.RegionandCacheKey.Keymust be non-empty and non-whitespace.- If underlying data retrieval is disabled through HybridCache entry options and the entry is missing,
GetOrCreateAsyncthrowsInvalidOperationException.
| Product | Versions 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. |
-
net10.0
- Microsoft.Extensions.Caching.Hybrid (>= 10.6.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.