- 
                Notifications
    
You must be signed in to change notification settings  - Fork 5.2k
 
Description
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. This presents the need for keyed hybrid caches using keyed 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);
+     public static IHybridCacheBuilder AddKeyedHybridCache(this IServiceCollection services, object? serviceKey, string optionsName);
+     public static IHybridCacheBuilder AddKeyedHybridCache(this IServiceCollection services, object? serviceKey, Action<HybridCacheOptions> setupAction);
+     public static IHybridCacheBuilder AddKeyedHybridCache(this IServiceCollection services, object? serviceKey, string optionsName, Action<HybridCacheOptions> setupAction);
  }API Usage
var services = new ServiceCollection();
services.AddKeyedSingleton<IDistributedCache, RedisCache>("Redis");
services.AddKeyedSingleton<IDistributedCache, SqlServerCache>("SqlServer", (s, k) => new SqlServerCache(new SqlServerCacheOptions { ConnectionString = "test", SchemaName = "test", TableName = "test" }));
services.AddKeyedHybridCache("HybridWithRedis", options => options.DistributedCacheServiceKey = "Redis");
services.AddKeyedHybridCache("HybridWithSqlServer", options => options.DistributedCacheServiceKey = "SqlServer");
using ServiceProvider provider = services.BuildServiceProvider();
var hybridWithRedis = provider.GetRequiredKeyedService<HybridCache>("HybridWithRedis");
var hybridWithSqlServer = provider.GetRequiredKeyedService<HybridCache>("HybridWithSqlServer");Alternative Designs
- Make DefaultHybridCache public and expand its API surface area to allow specification of the distributed cache service key
 - Refactor reusable logic out of DefaultHybridCache so that other cache implementations can compose that logic differently, such as using keyed services
 - Pass the distributed cache service key into 
AddKeyedHybridCacheas another argument instead of adding it as a property toHybridCacheOptions. 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. - Expand the scope of this request to also support adding keyed Redis cache services to DI, rather than relying on constructing the instances without the 
AddStackExchangeRedisCachehelper API. 
Risks
- There were not existing scenarios around registering keyed DI services that rely on other keyed DI services where named options are also expected to be supported. To support that scenario, we are introducing multiple overloads for providing the 
optionsName, thesetupAction, or both. - This does not add named options support for the non-keyed DI use of 
HybridCache; we could proactively add that but as of now the need is not compelling. - This does not add support for keyed local/memory cache, and the app's singleton 
MemoryCacheis shared by all hybrid caches. We could add aHybridCacheOptions.LocalCacheServiceKeyif we want to proactively add that support. - The 
AddStackExchangeRedisCacheAPI does not support adding keyed services, and it instantiates an internal, derivedRedisCacheimplementation that augments logging and telemetry that is incompatible with keyed HybridCaches. This has been reviewed though, and it's acceptable for that logging/telemetry not to work, as it's limited only to adding an "HC" library name to the telemetry captured by the hosted Redis service.