Nanocached.Caching 0.4.4

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

Nanocached.Caching

IDistributedCache adapter for the nanocached .NET SDK: Microsoft.Extensions.Caching.Distributed.IDistributedCache implemented on Nanocached.NanocachedClient, so ASP.NET Core session state, response caching, and any application code already written against the standard SPI run against a nanocached cluster.

  • One IDistributedCache ⇄ one namespace. Each registration binds to one nanocached namespace; the same key in two registrations never collides. The SPI has no Clear, so none is exposed here (unlike the Spring adapter, which maps Cache.clear() onto the namespace CLEAR).
  • Get/Set/Refresh/Remove map onto the SDK's namespaced get/set/delete, with all of its routing, replication, hedged reads and retries.
  • Sliding expiration, which the wire protocol has no server-side concept of, is emulated client-side: see "Sliding expiration" below.
  • Values are opaque byte[] — the SPI's own type — with no serializer involved.

Install

dotnet add package Nanocached.Caching

Depends on the Nanocached SDK package of the same version.

Setup

Two ways to wire this up, matching the two ways an application already deals with a NanocachedClient.

The adapter connects its own client — the common case:

using Nanocached.Caching;

services.AddNanocachedDistributedCache(options =>
{
    options.Addresses.Add("10.0.0.1:8357");
    // options.Secret = "change-me";     // NANOCACHED_AUTH_SECRET, if configured
    // options.Namespace = "my-app-cache"; // default: "distributed-cache"
});

This registers a singleton IDistributedCache. The connection happens lazily, the first time something resolves it (typically the host building its root service provider); the client it connects is closed automatically when the container is disposed — no separate cleanup needed. In ASP.NET Core, source the values from configuration the ordinary way (property binding is the host's, nothing adapter-specific):

builder.Services.AddNanocachedDistributedCache(options =>
{
    builder.Configuration.GetSection("Nanocached").Bind(options);
});

The application already has its own NanocachedClient singleton — reuse it instead of connecting a second one:

services.AddSingleton(await NanocachedClient.ConnectAsync(new NanocachedClient.Options
{
    Addresses = { ("10.0.0.1", 8357) },
    Compress = true, // any client-level option the app needs
}));
services.AddNanocachedDistributedCache("my-app-cache"); // namespace; defaults to "distributed-cache"

This overload dials nothing and owns nothing — the client's lifecycle, disposal included, stays whoever registered it's responsibility. Use this form when the application also talks to nanocached directly (or needs a client-level option — compression, hedged reads, TLS, read repair — none of which NanocachedCacheOptions exposes; those are configured on NanocachedClient.Options itself).

Neither overload does anything by itself beyond registering the service — as with any IDistributedCache implementation, application code that wants caching still calls it (directly, or through something like ASP.NET Core session state, which is itself just a consumer of IDistributedCache).

Usage

Standard IDistributedCache — the built-in extension methods work unchanged:

IDistributedCache cache = app.Services.GetRequiredService<IDistributedCache>();

await cache.SetStringAsync("greeting", "hello",
    new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10) });
string? value = await cache.GetStringAsync("greeting");
await cache.RemoveAsync("greeting");

Get/Set/Refresh/Remove (the synchronous members of the interface) block on their async counterparts (.GetAwaiter().GetResult()) — the SDK itself is async-only.

NanocachedDistributedCache can also be constructed directly, without DI:

using NanocachedClient client = await NanocachedClient.ConnectAsync(
    new NanocachedClient.Options { Addresses = { ("10.0.0.1", 8357) } });
IDistributedCache cache = new NanocachedDistributedCache(client, "my-app-cache");

Sliding expiration

nanocached's TTL is a one-shot countdown — a key's remaining time never changes just because it was read. DistributedCacheEntryOptions.SlidingExpiration is emulated on top of that: every value is wrapped in a small envelope (one version byte, the configured sliding window, the configured absolute expiry to the millisecond, then the payload) so a later Get/Refresh knows what to recompute. Envelopes written by earlier adapter releases (version byte 0x01, whole-second absolute expiry) are still read, and the next renewal re-writes them in the current format. Get on an entry with a sliding window re-sets it — envelope and all — with a freshly computed TTL before returning, awaited (never fire-and-forget); Refresh does the same without returning the value, and is a no-op on a missing key, per the SPI's contract. An entry with no sliding window is never rewritten by Get — its TTL, if any, is fixed regardless of access, so the extra round trip would buy nothing.

Whole-second TTLs only reach the wire: a positive sub-second remainder always rounds up to 1 second, never down to 0 (which would mean "no expiry"). AbsoluteExpiration/AbsoluteExpirationRelativeToNow and SlidingExpiration may be combined — the tighter of the two always wins, exactly like a real sliding-plus-absolute cache entry. A past (or exactly-now) absolute expiration throws ArgumentOutOfRangeException, mirroring Microsoft.Extensions.Caching.Memory.MemoryDistributedCache. No options at all means no TTL — the entry lives until evicted or explicitly removed.

Namespaces

Two IDistributedCache instances bound to different namespaces are fully isolated, even over identical keys — the same guarantee NanocachedNamespace gives the SDK directly. NanocachedDistributedCache.Namespace exposes which one an instance is bound to, since the SPI itself has no notion of it — useful for an application that also reads/writes the same namespace directly through client.Namespace(...).

Policy note

Framework adapters are ecosystem-specific and live outside the six-language SDK parity policy (#25): parity applies to the SDK core only. This module exists for IDistributedCache; other ecosystems get their own idiomatic adapters (Spring CacheManager, Django cache backend, cache-manager store, JCache, Keyv) rather than mirrors of this one.

Requirements

.NET 8+, nanocached server ≥ the release that ships namespaces (issue #105) — namespaced frames need a server that understands them.

Building

cd adapters/dotnet
dotnet test tests/Nanocached.Caching.Tests
dotnet pack src/Nanocached.Caching

The build references the sibling sdk/dotnet sources directly (project reference), so a checkout needs no locally-installed SDK package.

License

MIT

Product Compatible and additional computed target framework versions.
.NET 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 was computed.  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.4.4 104 9/9/2026