MethodCache 1.0.0-rc.2

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

MethodCache

Cache any .NET method with one attribute. MethodCache's source generator writes the caching code for you at compile time: no reflection, no hand-written keys, no TryGetValue boilerplate, and it works with Native AOT.

using MethodCache;

public interface IUserService
{
    [Cache(Duration = "00:10:00", Tags = ["user:{id}"])]
    Task<User> GetUserAsync(int id);

    [CacheInvalidate(Tags = ["user:{id}"])]
    Task RenameAsync(int id, string name);
}
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddMethodCache();
  • One attribute, zero boilerplate. Keys are built from the method and its arguments, including records and collections (GetAsync:42, ByIdsAsync:[3:1:2:3]; values of different types never share a key, nested ones included); your service stays plain code. Register services before AddMethodCache; missing registrations need explicit AutoRegister(lifetime) and an unambiguous generated module. Startup configuration uses MethodCacheBuilder.
  • Fast. A hit with simple arguments allocates nothing on .NET 10, on x64 is about 10 % faster than hand-written IMemoryCache code, faster than HybridCache and 8 to 9 times faster than FusionCache.
  • Compile-time, not runtime. A Roslyn source generator writes the decorators, analyzers catch mistakes in the editor, and Native AOT is tested in CI. Previously compiled contract-1 vendor decorators keep working without regeneration, with both inline and materialized keys.
  • Tags that understand your arguments. "user:{id}" becomes user:42, so an update invalidates exactly what it changed.
  • Tune it without redeploying. Durations and tags come from attributes, a global default, appsettings.json (reloaded live) or runtime overrides.
  • Third-party clients too. [assembly: CacheInterface(typeof(IFxClient), nameof(IFxClient.GetRateAsync))] caches chosen methods of an SDK client's own interface, no wrapper needed.
  • HTTP responses as well. AddHttpCaching() (package MethodCache.HttpCaching) on an HttpClient honors Cache-Control and revalidates with ETags. Register AddMethodCache too: Core owns a separate 100 MiB HTTP budget, or uses its configured native Redis/SQL transport exclusively. KeepCookies preserves cookies and bypasses response caching; confirmed mutations retire shared generations. Graceful async disposal retries pending invalidations once and reports any lost count; recovery is not durable across process exit. Local client-tag invalidation reclaims matching bodies through a scan of resident HTTP entries.
  • One line to go distributed. AddMethodCache(mc => mc.UseRedis(...)) or mc.UseSqlServer(...) (packages MethodCache.Redis and MethodCache.SqlServer) shares results between instances and keeps every instance's memory cache in sync.
  • Built for production. Stampede protection, fail-safe, a W-TinyLFU memory cache that stays within its size limit under load, admin endpoints, a health check and OpenTelemetry tracing and metrics.

Documentation, benchmarks and a runnable demo: https://github.com/eoniclabs/MethodCache

Additional behavior

With a distributed cache, values are JSON by default, public fields included, so value tuples and structs with fields are shared. Each value is read back before it is shared; a method whose values don't come back unchanged (private setters, a derived type returned as its base type, object) is cached in memory only for that type, with one warning. Entries an earlier build wrote for types with public fields are read without those fields until they expire.

Manual TryGetAsync reads a fresh entry, including a cached null, also when refresh-ahead is due. This lookup does not start a factory or background refresh.

Overloaded generic methods include generic arity in their policy ids and key prefixes: Get(int), Get``1(int) and Get``2(int) remain distinct. Generator and runtime configuration use the same ids; earlier keys for overloaded generic methods become cold misses.

Caller cancellation stops the wait during an L2 read or a slow factory, including bulk reads and fail-safe waits. L2 reads pass cancellation to the backend; shared factory work may finish for other callers. Caller cancellation is not reported as a dependency failure.

Bulk reads guard their source work against key, tag and clear invalidation: an invalidated batch result is returned to its caller but is not published. Collection subclasses keep their own public properties and fields in hashed keys, as well as their elements. Static tags do not format arguments; templates format only the parameters they reference. Redis backplane publications honor caller cancellation, and a cancelled unsubscribe acknowledgement does not fail application shutdown. SQL backplane gaps never hold newer invalidations behind a locked transaction, and HTTP variant schema changes retire their publication epoch once; a failed deletion after a successful rotation does not retire a newer concurrent publication.

Published policy tags are owned, read-only snapshots. Mutating the collection supplied by application code cannot change a published policy or bypass its version/change notifications.

A keyed ICacheManager registration remains independent of the default unkeyed manager. Registering another service key does not suppress AddMethodCache() or its default administration services.

Keyed registrations of cached interfaces are decorated under their own service key, which is part of their cache keys, so each registration caches its own results; an interface registered only keyed is not also registered without one. A catch-all KeyedService.AnyKey registration is rejected with a named binding error; register concrete keys instead. Registrations of one interface with different implementation types under the same service key each cache their own results too: their keys carry the implementation type. Two registrations of the same implementation type share their results. A constructor parameter marked [ServiceKey] receives the application's key. Generated decorators are disposable only when the interface is, so the container no longer keeps transient decorators resolved from the root.

Misconfiguration fails when the generic host starts rather than on the first call: invalid values, unknown setting names, a single value for Tags, an invalid duration, or an unknown or repeated method id in appsettings.json; CacheWhen in defaults or a group; and a tag template that names no parameter of a method it applies to. UseRedis and UseSqlServer together throw in AddMethodCache, since there is one distributed cache. Positive invariant unit durations such as 30s are accepted. AddMethodCache(cache => cache.FromConfiguration(configuration)) reads its section at startup, so configuration sources added later apply from the first call.

The attribute-move code fix preserves semantic binding across scopes and files: attribute/type aliases are qualified as needed, and constant arguments are materialized before they leave an implementation class.

With C# 13 or newer, generated decorators preserve allows ref struct constraints when the cached values and arguments themselves are ordinary cacheable types. Potentially ref-like type parameters used as cache arguments or results receive MC0009 instead of broken generated code. The packages require .NET 10 and the .NET 10 SDK. C# 12 source remains supported when explicitly selected in that SDK.

Long namespace and type names work with EmitCompilerGeneratedFiles; generated files use short, stable names when needed.

Weighted capacity accounting remains nonnegative even for valid weights near long.MaxValue. Before an addition could overflow, the engine evicts existing weight; normal capacity/admission behavior is unchanged below that arithmetic limit.

SQL Server backplane tables require a non-nullable binary(32) Scope column. Incompatible schemas are reported without automatic upgrades; see the MethodCache.SqlServer package guide.

The cache manager has four operations with cancellation last and immutable options. WithEnabled(false) bypasses caching; WithDistributed(false) uses only memory. Policy changes retire local generations. Declarative settings share a stable L2 namespace, while runtime overrides use private namespaces. Invalidation results distinguish local mutation, confirmed L2 metadata, queued recovery and confirmed/queued backplane sends. See configuration and distributed guarantees.

Attribute settings use named arguments, for example Group, Enabled, Distributed and FailSafeRetryAfter. Durations accept invariant positive values such as 30s, 1.5h or 00:05:00. Generated keys always preserve method scope; CacheKeyAttribute has been removed. See configuration and keys.

Distributed providers use one container-bound DistributedCacheOptions.KeyPrefix for data and invalidation. Value formats and serializer schemas have separate namespaces; metadata retention and atomic epochs prevent older physical variants from reappearing after invalidation. SQL Server uses an explicit versioned schema and delivered migration scripts. See distributed caching.

Core emits MethodCache metrics and activities through the container's IMeterFactory; the OpenTelemetry add-on only subscribes with AddMethodCacheInstrumentation(). Keys/tags are off by default, histograms use seconds, and pure hits have no spans. Administrator statistics distinguish local method/HTTP entries and HTTP bytes; TotalWeight uses the configured weigher's units (one per method entry by default), with no object-memory estimate.

Dictionary hashes are process-local implementation metadata. Canonical key text, L2 identities, administration and invalidation remain stable across processes and restarts; the lookup hash is never stored or transmitted.

Memory-only asynchronous misses avoid allocating closures for inactive fail-safe and distributed-write branches.

Logical-key lookups and invalidations use the same framing and optional version as storage, including keys starting with NUL. Admin mutations return 503 while distributed invalidation awaits confirmation; recovery remains owned by the cache. Incompatible distributed scope contracts use memory only and report an actionable unhealthy status. See manual keys and monitoring.

Generated method keys and policy ids include the service assembly simple name (without its version), so equally named interfaces in different assemblies stay isolated. Get the key of a call from IMethodCacheKeys.For and a method's id from IMethodCacheKeys.MethodId; the admin method list shows every id.

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 (6)

Showing the top 5 NuGet packages that depend on MethodCache:

Package Downloads
MethodCache.OpenTelemetry

OpenTelemetry instrumentation for MethodCache: traces and metrics for cache operations

MethodCache.Redis

Redis as MethodCache's distributed cache, with a pub/sub backplane that keeps every instance's in-memory cache in sync

MethodCache.SqlServer

SQL Server as MethodCache's distributed cache, with a polling backplane that keeps every instance's in-memory cache in sync

MethodCache.AspNetCore

ASP.NET Core admin endpoints and health check for MethodCache: inspect statistics and entries, invalidate tags and clear the cache at runtime

MethodCache.HttpCaching

HTTP caching for HttpClient: ETag and Last-Modified revalidation, Cache-Control and Vary, as in RFC 9111

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-rc.2 122 10/20/2026
1.0.0-rc.1 87 10/19/2026