Skip to content

Microsoft.Extensions.Caching.StackExchangeRedis 9.0.3 - when using HybridCache RedisCacheImpl.IsHybridCacheDefined causes infinite recursion #60894

@xeonix

Description

@xeonix

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Hello guys.
Today I updated all my NuGets and my .NET 9 Back-End hanged.
I'm using the following NuGets to do the caching stuff in my project:
Microsoft.Extensions.Caching.Hybrid 9.3.0
Microsoft.Extensions.Caching.StackExchangeRedis 9.0.3
After investigating the issue and inspecting this GitHub repository I've find out what's happening:
I registered HybridCache like this:

services.AddHybridCache(options =>
        {
            options.DefaultEntryOptions = new HybridCacheEntryOptions
            {
                Expiration = TimeSpan.FromMinutes(5),
                LocalCacheExpiration = TimeSpan.FromMinutes(2.5)
            };
        });

and then added some RedisCache like this:

services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = redisCacheConnectionString;
    options.InstanceName = redisCacheKeyPrefix;
});

The problem here is with IsHybridCacheDefined method:

internal sealed class RedisCacheImpl : RedisCache
{
    public RedisCacheImpl(IOptions<RedisCacheOptions> optionsAccessor, ILogger<RedisCache> logger, IServiceProvider services)
        : base(optionsAccessor, logger)
    {
        HybridCacheActive = IsHybridCacheDefined(services);
    }

    public RedisCacheImpl(IOptions<RedisCacheOptions> optionsAccessor, IServiceProvider services)
        : base(optionsAccessor)
    {
        HybridCacheActive = IsHybridCacheDefined(services);
    }

    // HybridCache optionally uses IDistributedCache; if we're here, then *we are* the DC
    private static bool IsHybridCacheDefined(IServiceProvider services)
        => services.GetService<HybridCache>() is not null;
}

When it resolves HybridCache which then resolves IDistributedCache.
According to StackExchangeRedisCacheServiceCollectionExtensions, RedisCacheImpl is registered as:

services.Add(ServiceDescriptor.Singleton<IDistributedCache, RedisCacheImpl>());

So when resolving IDistributedCache and instantiating RedisCacheImpl, it's ctor calls IsHybridCacheDefined method, which resolves HybridCache, which resolves IDistributedCache resulting into an infinite resolution loop.
With Microsoft.Extensions.Caching.StackExchangeRedis 9.0.2 - RedisCacheImpl has no IsHybridCacheDefined method, so everything works fine.

Expected Behavior

No response

Steps To Reproduce

  1. When configuring DI - call services.AddHybridCache, then services.AddStackExchangeRedisCache
  2. Try to resolve HybridCache anywhere (i.e. Controller/Minimal API)

Exceptions (if any)

No response

.NET Version

9.0.201

Anything else?

No response

Metadata

Metadata

Assignees

Labels

area-middlewareIncludes: URL rewrite, redirect, response cache/compression, session, and other general middlewares

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions