Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,9 @@ public class HybridCacheOptions
/// should not be visible in metrics systems.
/// </remarks>
public bool ReportTagMetrics { get; set; }

/// <summary>
/// Gets or sets the key used to resolve the distributed cache service from the <see cref="System.IServiceProvider"/>.
/// </summary>
public object? DistributedCacheServiceKey { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.Extensions.Caching.Hybrid;
using Microsoft.Extensions.Caching.Hybrid.Internal;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.Shared.Diagnostics;

namespace Microsoft.Extensions.DependencyInjection;
Expand All @@ -17,28 +18,111 @@ public static class HybridCacheServiceExtensions
/// <summary>
/// Adds support for multi-tier caching services.
/// </summary>
/// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> system.</returns>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
/// <param name="setupAction">A delegate to run to configure the <see cref="HybridCacheOptions"/> instance.</param>
/// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> service.</returns>
public static IHybridCacheBuilder AddHybridCache(this IServiceCollection services, Action<HybridCacheOptions> setupAction)
{
_ = Throw.IfNull(setupAction);
_ = AddHybridCache(services);

var builder = AddHybridCache(services);
_ = services.Configure(setupAction);
return new HybridCacheBuilder(services);

return builder;
}

/// <summary>
/// Adds support for multi-tier caching services.
/// </summary>
/// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> system.</returns>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
/// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> service.</returns>
public static IHybridCacheBuilder AddHybridCache(this IServiceCollection services)
{
_ = Throw.IfNull(services);
var builder = PrepareServices(services);

services.TryAddSingleton<HybridCache, DefaultHybridCache>();

return builder;
}

/// <summary>
/// Adds support for multi-tier caching services with a keyed registration.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
/// <param name="serviceKey">The key for the service registration.</param>
/// <param name="setupAction">A delegate to run to configure the <see cref="HybridCacheOptions"/> instance.</param>
/// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> service.</returns>
public static IHybridCacheBuilder AddKeyedHybridCache(this IServiceCollection services, object? serviceKey, Action<HybridCacheOptions> setupAction) =>
AddKeyedHybridCache(services, serviceKey, serviceKey?.ToString() ?? Options.Options.DefaultName, setupAction);

/// <summary>
/// Adds support for multi-tier caching services with a keyed registration.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
/// <param name="serviceKey">The key for the service registration.</param>
/// <param name="optionsName">The named options name to use for the <see cref="HybridCacheOptions"/> instance.</param>
/// <param name="setupAction">A delegate to run to configure the <see cref="HybridCacheOptions"/> instance.</param>
/// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> service.</returns>
public static IHybridCacheBuilder AddKeyedHybridCache(this IServiceCollection services, object? serviceKey, string optionsName, Action<HybridCacheOptions> setupAction)
{
_ = Throw.IfNull(setupAction);

var builder = AddKeyedHybridCache(services, serviceKey, optionsName);
_ = services.AddOptions<HybridCacheOptions>(optionsName).Configure(setupAction);

return builder;
}

/// <summary>
/// Adds support for multi-tier caching services with a keyed registration.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
/// <param name="serviceKey">The key for the service registration.</param>
/// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> service.</returns>
public static IHybridCacheBuilder AddKeyedHybridCache(this IServiceCollection services, object? serviceKey) =>
AddKeyedHybridCache(services, serviceKey, serviceKey?.ToString() ?? Options.Options.DefaultName);

/// <summary>
/// Adds support for multi-tier caching services with a keyed registration.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the service to.</param>
/// <param name="serviceKey">The key for the service registration.</param>
/// <param name="optionsName">The named options name to use for the <see cref="HybridCacheOptions"/> instance.</param>
/// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> service.</returns>
public static IHybridCacheBuilder AddKeyedHybridCache(this IServiceCollection services, object? serviceKey, string optionsName)
{
_ = Throw.IfNull(optionsName);

var builder = PrepareServices(services);
_ = services.AddOptions<HybridCacheOptions>(optionsName);

_ = services.AddKeyedSingleton<HybridCache, DefaultHybridCache>(serviceKey, (sp, key) =>
{
var optionsService = sp.GetRequiredService<IOptionsMonitor<HybridCacheOptions>>();
var options = optionsService.Get(optionsName);

return new DefaultHybridCache(options, sp);
});

return builder;
}

/// <summary>
/// Adds the services required for hybrid caching.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to prepare with <see cref="HybridCache"/> prerequisites.</param>
/// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> service.</returns>
private static HybridCacheBuilder PrepareServices(IServiceCollection services)
{
_ = Throw.IfNull(services);

services.TryAddSingleton(TimeProvider.System);
_ = services.AddOptions().AddMemoryCache();
services.TryAddSingleton<IHybridCacheSerializerFactory, DefaultJsonSerializerFactory>();
services.TryAddSingleton<IHybridCacheSerializer<string>>(InbuiltTypeSerializer.Instance);
services.TryAddSingleton<IHybridCacheSerializer<byte[]>>(InbuiltTypeSerializer.Instance);
services.TryAddSingleton<HybridCache, DefaultHybridCache>();

return new HybridCacheBuilder(services);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,23 @@ internal enum CacheFeatures
internal bool HasBackendCache => (_features & CacheFeatures.BackendCache) != 0;

public DefaultHybridCache(IOptions<HybridCacheOptions> options, IServiceProvider services)
: this(Throw.IfNull(options).Value, services)
{
}

public DefaultHybridCache(HybridCacheOptions options, IServiceProvider services)
{
_services = Throw.IfNull(services);
_localCache = services.GetRequiredService<IMemoryCache>();
_options = options.Value;
_options = options;
_logger = services.GetService<ILoggerFactory>()?.CreateLogger(typeof(HybridCache)) ?? NullLogger.Instance;
_clock = services.GetService<TimeProvider>() ?? TimeProvider.System;
_backendCache = services.GetService<IDistributedCache>(); // note optional

// The backend cache service is optional; if not provided, we operate as a pure L1 cache.
// If a service key is provided, the service must be present.
_backendCache = _options.DistributedCacheServiceKey is null
? services.GetService<IDistributedCache>()
: services.GetRequiredKeyedService<IDistributedCache>(_options.DistributedCacheServiceKey);

// ignore L2 if it is really just the same L1, wrapped
// (note not just an "is" test; if someone has a custom subclass, who knows what it does?)
Expand Down
Binary file not shown.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,4 @@
<PackageReference Include="Xunit.SkippableFact" />
</ItemGroup>

<ItemGroup>
<None Update="BasicConfig.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
Loading
Loading