ExpressionCache.Core 6.1.0

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

ExpressionCache.Core

Cache keys from .NET method call expressions, and the base classes for ExpressionCache providers. This package turns a method call expression into a key (type name, method name and argument values), and returns the cached result or calls the method and caches what it returns. The cache itself comes from a provider.

// Cache key: ExprCache{ProductService}{GetAsync}{42}{Bypass}
string key = cache.GetKey(() => GetAsync(42, CacheAction.Bypass));

To cache in IDistributedCache (Redis, SQL Server, in-memory and others), install ExpressionCache.Distributed instead. It includes this package and has a getting started guide.

Full documentation: github.com/Baune8D/ExpressionCache

Contents

Type Description
IExpressionCacheBase GetKey, InvokeCache and InvokeCacheAsync. The interface you call.
ExpressionCacheBase Abstract class that implements IExpressionCacheBase on top of an IExpressionCacheProvider.
IExpressionCacheProvider Reads and writes values by key. Implement it for your cache.
CacheResult<TResult> The result of a provider read: Success and Content.
CacheAction Invoke, Overwrite or Bypass. See Cache actions.
ICacheKey, ICacheKeyBuilder, CacheKeyBuilder Let your own types be used as arguments.
Member of IExpressionCacheBase Returns Description
GetKey(expression) string The cache key for the call. Has overloads for Expression<Func<TResult>> and Expression<Func<Task<TResult>>>.
InvokeCache(expression, expiry, cacheAction) TResult Returns the cached result or calls the method, depending on the cache action. Takes an Expression<Func<TResult>>.
InvokeCacheAsync(expression, expiry, cacheAction) Task<TResult> The same, for methods that return Task<TResult>. Takes an Expression<Func<Task<TResult>>>.

Cache keys

A key is ExprCache followed by one {...} part for each of these:

  1. The type of the object the method is called on, without its namespace. This is the type of the expression in your code: this gives the class, a variable declared as an interface gives the interface. A static method has no object, so this part is {0x6e756c6c}.
  2. The method name.
  3. For a generic method, each type argument, with its namespace: Find<Product>() adds {MyApp.Product}.
  4. Each argument value, in order.

Argument values are converted as follows. The checks run in this order:

Value Key part Example
null CacheKeyBuilder.NullString {0x6e756c6c}
DateTime Its Ticks {639029198450000000}
Guid ToString() {3f2504e0-4f89-11d3-9a0c-0305e82c3301}
Other IConvertible types: numbers, string, bool, char, enums ToString(CultureInfo.InvariantCulture) {42}, {5.5}, {books}, {True}, {Bypass}
IEnumerable, e.g. arrays and lists One part per element new[] { 1, 2 } → {1}{2}
ICacheKey The parts added by BuildCacheKey See below
Anything else Throws ArgumentException ("... cannot be a cache key") DateTimeOffset, TimeSpan, DateOnly, records

Implement ICacheKey to use your own type as an argument. BuildCacheKey adds the values that identify an instance, converted as in the table above:

using ExpressionCache.Core;

public sealed class ProductQuery : ICacheKey
{
    public string? Category { get; init; }

    public int Page { get; init; }

    public void BuildCacheKey(ICacheKeyBuilder builder)
    {
        builder
            .By(Category)
            .By(Page);
    }
}

In ProductService, () => SearchAsync(new ProductQuery { Category = "books", Page = 2 }, CacheAction.Bypass) gets the key ExprCache{ProductService}{SearchAsync}{books}{2}{Bypass}.

A key contains only these parts, so some calls share a key, e.g. overloads called with the same values. See Keys that can collide.

Writing a provider

To use a cache, implement IExpressionCacheProvider and derive from ExpressionCacheBase. For example, for IMemoryCache:

using ExpressionCache.Core;
using Microsoft.Extensions.Caching.Memory;

public sealed class MemoryCacheProvider(IMemoryCache cache) : IExpressionCacheProvider
{
    public CacheResult<TResult> Get<TResult>(string key)
    {
        return cache.TryGetValue(key, out TResult? value)
            ? new CacheResult<TResult> { Success = true, Content = value }
            : CacheResult<TResult>.Failure();
    }

    public Task<CacheResult<TResult>> GetAsync<TResult>(string key)
    {
        return Task.FromResult(Get<TResult>(key));
    }

    public void Set<TResult>(string key, TResult value, TimeSpan expiry)
    {
        cache.Set(key, value, expiry);
    }

    public Task SetAsync<TResult>(string key, TResult value, TimeSpan expiry)
    {
        Set(key, value, expiry);
        return Task.CompletedTask;
    }
}

public sealed class MemoryExpressionCache(IMemoryCache cache)
    : ExpressionCacheBase(new MemoryCacheProvider(cache));

Register it as a singleton and inject IExpressionCacheBase:

builder.Services.AddMemoryCache();
builder.Services.AddSingleton<IExpressionCacheBase, MemoryExpressionCache>();
  • Return CacheResult<TResult>.Failure() on a miss, or Success = true with the value in Content.
  • ExpressionCacheBase only calls Set and SetAsync with non-null values.
  • Subclasses get the provider from the protected Provider property.
  • ExpressionCacheBase is IDisposable. It keeps the type and method part of each key in an IMemoryCache, which it disposes when it is disposed. The constructor that takes only a provider creates that cache. The other constructor takes it as its first argument, so don't pass a cache you use for anything else.

ExpressionCache.Distributed is built the same way: see DistributedCacheProvider and DistributedCacheService.

Limitations

  • The lambda must be a single method call, such as () => GetAsync(id, CacheAction.Bypass). Anything else, such as () => GetName() ?? "none", throws ArgumentException. The arguments can be any expression.

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on ExpressionCache.Core:

Package Downloads
ExpressionCache.Distributed

ExpressionCache service for IDistributedCache interface.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
6.1.0 117 11/2/2026
6.0.0 375 1/8/2026
5.1.0 460 12/30/2024
5.0.0 225 7/30/2024
4.0.1 434 10/18/2023
4.0.0 306 10/17/2023
3.1.0 1,007 4/14/2022
3.0.0 803 1/20/2021
2.0.0 905 11/3/2020
1.0.0 3,689 6/24/2018