What is HybridCache?

The HybridCache library is designed to bridge the gaps in existing caching solutions like IDistributedCache and IMemoryCache in .NET. This powerful new tool introduces several advanced capabilities, including.

HybridCache aims to be a drop-in replacement for IDistributedCache and IMemoryCache, offering a unified API for both in-process and out-of-process caching, simplifying the caching code significantly.

Why HybridCache?

Here’s a typical example of how caching is done with IDistributedCache.

public class SomeService(IDistributedCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync(string name, int id, CancellationToken token = default)
    {
        var key = $"someinfo:{name}:{id}";
        var bytes = await cache.GetAsync(key, token);
        SomeInformation info;
        if (bytes is null)
        {
            info = await SomeExpensiveOperationAsync(name, id, token);
            bytes = SomeSerializer.Serialize(info);
            await cache.SetAsync(key, bytes, token);
        }
        else
        {
            info = SomeSerializer.Deserialize<SomeInformation>(bytes);
        }
        return info;
    }
    private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id, CancellationToken token = default)
    { /* ... */ }
}

This method involves handling serialization and potential cache stampedes manually. With HybridCache, this complexity is greatly reduced.

Simplifying with HybridCache

First, add the HybridCache library

<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0" />

Register the HybridCache service in your application.

services.AddHybridCache(); // Not shown: optional configuration API.

Now, you can simplify the caching logic as follows.

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // Unique key for this combination.
            async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
            token: token
        );
    }
}

Advanced usage and custom implementations

HybridCache supports creating custom implementations and handles all caching concerns, including concurrent operations. For high-throughput scenarios, you can use the TState pattern to avoid overhead from captured variables:

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync(string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // unique key for this combination
            (name, id), // all of the state we need for the final call, if needed
            static async (state, token) =>
                await SomeExpensiveOperationAsync(state.name, state.id, token),
            token: token
        );
    }
}

Object Reuse and Performance

HybridCache maintains the behavior of deserializing objects on each retrieval to ensure thread safety. However, if your cached objects are immutable or not modified, you can optimize performance by reusing instances.

Additional features

For more information about HybridCache, see HybridCache library in ASP.NET Core