Skip to content

Commit

Permalink
Feature/keyed services (#244)
Browse files Browse the repository at this point in the history
* Initial keyed services impl
* Better keyed services support
* Better keyed services tests
* Add ChaosMemoryCache
* Re-enabled package validation build step
* Add support to use registered keyed services, on top of support for register it
* Add specific tests
  • Loading branch information
jodydonetti authored May 19, 2024
1 parent 25d6d6a commit ca78ea4
Show file tree
Hide file tree
Showing 12 changed files with 1,011 additions and 15 deletions.
54 changes: 54 additions & 0 deletions src/ZiggyCreatures.FusionCache.Chaos/ChaosMemoryCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using ZiggyCreatures.Caching.Fusion.Chaos.Internals;

namespace ZiggyCreatures.Caching.Fusion.Chaos;

/// <summary>
/// An implementation of <see cref="IMemoryCache"/> that acts on behalf of another one, but with a (controllable) amount of chaos in-between.
/// </summary>
public class ChaosMemoryCache
: AbstractChaosComponent
, IMemoryCache
{
private readonly IMemoryCache _innerCache;

/// <summary>
/// Initializes a new instance of the ChaosMemoryCache class.
/// </summary>
/// <param name="innerCache">The actual <see cref="IMemoryCache"/> used if and when chaos does not happen.</param>
/// <param name="logger">The logger to use, or <see langword="null"/>.</param>
public ChaosMemoryCache(IMemoryCache innerCache, ILogger<ChaosMemoryCache>? logger = null)
: base(logger)
{
_innerCache = innerCache ?? throw new ArgumentNullException(nameof(innerCache));
}

/// <inheritdoc/>
public ICacheEntry CreateEntry(object key)
{
MaybeChaos();
return _innerCache.CreateEntry(key);
}

/// <inheritdoc/>
public void Dispose()
{
// EMPTY
}

/// <inheritdoc/>
public void Remove(object key)
{
MaybeChaos();
_innerCache.Remove(key);
}

/// <inheritdoc/>
public bool TryGetValue(object key, out object? value)
{
MaybeChaos();
return _innerCache.TryGetValue(key, out value);
}
}
8 changes: 8 additions & 0 deletions src/ZiggyCreatures.FusionCache.Chaos/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.

using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor")]

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

346 changes: 344 additions & 2 deletions src/ZiggyCreatures.FusionCache/FusionCacheBuilderExtMethods.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ public static IServiceCollection AddFusionCache(this IServiceCollection services
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <param name="cache">The custom FusionCache instance.</param>
/// <param name="asKeyedService">Also register this FusionCache instance as a keyed service.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
public static IServiceCollection AddFusionCache(this IServiceCollection services, IFusionCache cache)
public static IServiceCollection AddFusionCache(this IServiceCollection services, IFusionCache cache, bool asKeyedService)
{
if (services is null)
throw new ArgumentNullException(nameof(services));
Expand All @@ -97,9 +98,27 @@ public static IServiceCollection AddFusionCache(this IServiceCollection services
services.AddSingleton<LazyNamedCache>(new LazyNamedCache(cache.CacheName, cache));
}

if (asKeyedService)
{
services.AddKeyedSingleton<IFusionCache>(cache.CacheName, cache);
}

return services;
}

/// <summary>
/// Adds a custom instance of <see cref="IFusionCache"/> to the <see cref="IServiceCollection" />.
/// <br/><br/>
/// <strong>DOCS:</strong> <see href="https://github.com/ZiggyCreatures/FusionCache/blob/main/docs/DependencyInjection.md"/>
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <param name="cache">The custom FusionCache instance.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
public static IServiceCollection AddFusionCache(this IServiceCollection services, IFusionCache cache)
{
return services.AddFusionCache(cache, false);
}

/// <summary>
/// Registers a named cache to the <see cref="IServiceCollection" />.
/// <br/><br/>
Expand Down Expand Up @@ -129,7 +148,7 @@ public static IFusionCacheBuilder AddFusionCache(this IServiceCollection service

services.AddFusionCacheProvider();

IFusionCacheBuilder builder = new FusionCacheBuilder(cacheName);
IFusionCacheBuilder builder = new FusionCacheBuilder(cacheName, services);

if (cacheName == FusionCacheOptions.DefaultCacheName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ namespace ZiggyCreatures.Caching.Fusion.Internals.Builder;
internal sealed class FusionCacheBuilder
: IFusionCacheBuilder
{
public FusionCacheBuilder(string cacheName)
public FusionCacheBuilder(string cacheName, IServiceCollection services)
{
CacheName = cacheName;
Services = services;

UseRegisteredLogger = true;

Expand All @@ -36,17 +37,22 @@ public FusionCacheBuilder(string cacheName)

public string CacheName { get; }

public IServiceCollection Services { get; }

public bool UseRegisteredLogger { get; set; }
public string? LoggerKeyedServiceName { get; set; }
public ILogger<FusionCache>? Logger { get; set; }
public Func<IServiceProvider, ILogger<FusionCache>>? LoggerFactory { get; set; }
public bool ThrowIfMissingLogger { get; set; }

public bool UseRegisteredMemoryCache { get; set; }
public string? MemoryCacheKeyedServiceName { get; set; }
public IMemoryCache? MemoryCache { get; set; }
public Func<IServiceProvider, IMemoryCache>? MemoryCacheFactory { get; set; }
public bool ThrowIfMissingMemoryCache { get; set; }

public bool UseRegisteredMemoryLocker { get; set; }
public string? MemoryLockerKeyedServiceName { get; set; }
public IFusionCacheMemoryLocker? MemoryLocker { get; set; }
public Func<IServiceProvider, IFusionCacheMemoryLocker>? MemoryLockerFactory { get; set; }
public bool ThrowIfMissingMemoryLocker { get; set; }
Expand All @@ -61,22 +67,26 @@ public FusionCacheBuilder(string cacheName)
public Action<FusionCacheEntryOptions>? SetupDefaultEntryOptionsAction { get; set; }

public bool UseRegisteredSerializer { get; set; }
public string? SerializerKeyedServiceName { get; set; }
public IFusionCacheSerializer? Serializer { get; set; }
public Func<IServiceProvider, IFusionCacheSerializer>? SerializerFactory { get; set; }
public bool ThrowIfMissingSerializer { get; set; }

public bool UseRegisteredDistributedCache { get; set; }
public string? DistributedCacheKeyedServiceName { get; set; }
public bool IgnoreRegisteredMemoryDistributedCache { get; set; }
public IDistributedCache? DistributedCache { get; set; }
public Func<IServiceProvider, IDistributedCache>? DistributedCacheFactory { get; set; }
public bool ThrowIfMissingDistributedCache { get; set; }

public bool UseRegisteredBackplane { get; set; }
public string? BackplaneKeyedServiceName { get; set; }
public IFusionCacheBackplane? Backplane { get; set; }
public Func<IServiceProvider, IFusionCacheBackplane>? BackplaneFactory { get; set; }
public bool ThrowIfMissingBackplane { get; set; }

public bool UseAllRegisteredPlugins { get; set; }
public string? PluginsKeyedServiceName { get; set; }
public List<IFusionCachePlugin> Plugins { get; }
public List<Func<IServiceProvider, IFusionCachePlugin>> PluginsFactories { get; }

Expand Down Expand Up @@ -145,7 +155,14 @@ public IFusionCache Build(IServiceProvider serviceProvider)

if (UseRegisteredLogger)
{
logger = serviceProvider.GetService<ILogger<FusionCache>>();
if (string.IsNullOrWhiteSpace(LoggerKeyedServiceName))
{
logger = serviceProvider.GetService<ILogger<FusionCache>>();
}
else
{
logger = serviceProvider.GetKeyedService<ILogger<FusionCache>>(LoggerKeyedServiceName);
}
}
else if (LoggerFactory is not null)
{
Expand All @@ -166,7 +183,14 @@ public IFusionCache Build(IServiceProvider serviceProvider)

if (UseRegisteredMemoryCache)
{
memoryCache = serviceProvider.GetService<IMemoryCache>();
if (string.IsNullOrWhiteSpace(LoggerKeyedServiceName))
{
memoryCache = serviceProvider.GetService<IMemoryCache>();
}
else
{
memoryCache = serviceProvider.GetKeyedService<IMemoryCache>(MemoryCacheKeyedServiceName);
}
}
else if (MemoryCacheFactory is not null)
{
Expand All @@ -187,7 +211,14 @@ public IFusionCache Build(IServiceProvider serviceProvider)

if (UseRegisteredMemoryLocker)
{
memoryLocker = serviceProvider.GetService<IFusionCacheMemoryLocker>();
if (string.IsNullOrWhiteSpace(MemoryLockerKeyedServiceName))
{
memoryLocker = serviceProvider.GetService<IFusionCacheMemoryLocker>();
}
else
{
memoryLocker = serviceProvider.GetKeyedService<IFusionCacheMemoryLocker>(MemoryLockerKeyedServiceName);
}
}
else if (MemoryLockerFactory is not null)
{
Expand All @@ -210,7 +241,15 @@ public IFusionCache Build(IServiceProvider serviceProvider)
IDistributedCache? distributedCache;
if (UseRegisteredDistributedCache)
{
distributedCache = serviceProvider.GetService<IDistributedCache>();
if (string.IsNullOrWhiteSpace(DistributedCacheKeyedServiceName))
{
distributedCache = serviceProvider.GetService<IDistributedCache>();
}
else
{
distributedCache = serviceProvider.GetKeyedService<IDistributedCache>(DistributedCacheKeyedServiceName);
}

if (IgnoreRegisteredMemoryDistributedCache && distributedCache is MemoryDistributedCache)
{
distributedCache = null;
Expand All @@ -235,7 +274,14 @@ public IFusionCache Build(IServiceProvider serviceProvider)
IFusionCacheSerializer? serializer;
if (UseRegisteredSerializer)
{
serializer = serviceProvider.GetService<IFusionCacheSerializer>();
if (string.IsNullOrWhiteSpace(SerializerKeyedServiceName))
{
serializer = serviceProvider.GetService<IFusionCacheSerializer>();
}
else
{
serializer = serviceProvider.GetKeyedService<IFusionCacheSerializer>(SerializerKeyedServiceName);
}
}
else if (SerializerFactory is not null)
{
Expand Down Expand Up @@ -266,7 +312,14 @@ public IFusionCache Build(IServiceProvider serviceProvider)
IFusionCacheBackplane? backplane;
if (UseRegisteredBackplane)
{
backplane = serviceProvider.GetService<IFusionCacheBackplane>();
if (string.IsNullOrWhiteSpace(BackplaneKeyedServiceName))
{
backplane = serviceProvider.GetService<IFusionCacheBackplane>();
}
else
{
backplane = serviceProvider.GetKeyedService<IFusionCacheBackplane>(BackplaneKeyedServiceName);
}
}
else if (BackplaneFactory is not null)
{
Expand Down Expand Up @@ -295,6 +348,11 @@ public IFusionCache Build(IServiceProvider serviceProvider)
plugins.AddRange(serviceProvider.GetServices<IFusionCachePlugin>());
}

if (string.IsNullOrWhiteSpace(PluginsKeyedServiceName) == false)
{
plugins.AddRange(serviceProvider.GetKeyedServices<IFusionCachePlugin>(PluginsKeyedServiceName));
}

if (Plugins?.Any() == true)
{
plugins.AddRange(Plugins);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
- Perf: some minor memory/cpu optimizations
</PackageReleaseNotes>
<EnablePackageValidation>true</EnablePackageValidation>
<!--<PackageValidationBaselineVersion>0.20.0</PackageValidationBaselineVersion>-->
<PackageValidationBaselineVersion>1.0.0</PackageValidationBaselineVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit ca78ea4

Please sign in to comment.