Skip to content

Support detect keyed dependency injected IDistributedCache as backend cache for DefaultHybridCache #117976

@ylt1534

Description

@ylt1534

Background and motivation

Microsoft.Extensions.Caching.Hybrid an API for adding a HybridCache to the application's service collection, and the AddHybridCache() method results in constructing a DefaultHybridCache singleton. DefaultHybridCache respects that an IDistributedCache service might be registered, and that cache will be used for an L2 cache provider.

Applications can use keyed services to register multiple IDistributedCache services for use throughout the application, but the DefaultHybridCache cannot consume these keyed services. Moreover, if DefaultHybridCache could respect a distributed cache service key, that would lead to the need for registering multiple HybridCache services into the collection using keyed services.

Because DefaultHybridCache is internal and can only be registered into the service collection via AddHybridCache(), there are no clear paths toward registering multiple instances that consume different keyed services for the distributed caches.

API Proposal

  namespace Microsoft.Extensions.Caching.Hybrid;
  
  public class HybridCacheOptions
  {
      public HybridCacheEntryOptions? DefaultEntryOptions { get; set; }
      public bool DisableCompression { get; set; }
      public long MaximumPayloadBytes { get; set; }
      public int MaximumKeyLength { get; set; }
      public bool ReportTagMetrics { get; set; }
+     public object? DistributedCacheServiceKey { get; set; }
  }
  namespace Microsoft.Extensions.DependencyInjection;
  public static class HybridCacheServiceExtensions
  {
      public static IHybridCacheBuilder AddHybridCache(this IServiceCollection services, Action<HybridCacheOptions> setupAction);
      public static IHybridCacheBuilder AddHybridCache(this IServiceCollection services);
+     public static IHybridCacheBuilder AddKeyedHybridCache(this IServiceCollection services, object? serviceKey, Action<HybridCacheOptions> setupAction);
+     public static IHybridCacheBuilder AddKeyedHybridCache(this IServiceCollection services, string serviceKey);
  }

API Usage

var services = new ServiceCollection();
services.AddKeyedSingleton<IDistributedCache, RedisCache>(typeof(RedisCache));
services.AddKeyedSingleton<IDistributedCache, SqlServerCache>(typeof(SqlServerCache));
services.AddKeyedHybridCache("HybridRedis", options => options.DistributedCacheServiceKey = typeof(RedisCache));
services.AddKeyedHybridCache("HybridSqlServer", options => options.DistributedCacheServiceKey = typeof(SqlServerCache));

using ServiceProvider provider = services.BuildServiceProvider();
var redisHybrid = Assert.IsType<DefaultHybridCache>(provider.GetRequiredKeyedService<HybridCache>("HybridRedis"));
var sqlHybrid = Assert.IsType<DefaultHybridCache>(provider.GetRequiredKeyedService<HybridCache>("HybridSqlServer"));

Alternative Designs

  1. Make DefaultHybridCache public and expand its API surface area to allow specification of the distributed cache service key
  2. Refactor reusable logic out of DefaultHybridCache so that other cache implementations can compose that logic differently, such as using keyed services
  3. Pass the distributed cache service key into AddKeyedHybridCache as another argument instead of adding it as a property to HybridCacheOptions. Adding to the options is preferred as this allows the cache key to be included in the application configuration without code to wire the two together.

Risks

  1. The implementation with this design is not yet complete; wiring up the keyed options still needs to be finished. It's possible the type(s) of the service key values might need to be changed.
  2. If the options are not wired up correctly into the keyed singletons, the wrong backend cache could be used.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-Extensions-Cachingpartner-impactThis issue impacts a partner who needs to be kept updated

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions