Skip to content

feat(DataProtection): add overloads for PersistKeysToStackExchangeRedis to accept IServiceProvider #62759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
@@ -1 +1,3 @@
#nullable enable
static Microsoft.AspNetCore.DataProtection.StackExchangeRedisDataProtectionBuilderExtensions.PersistKeysToStackExchangeRedis(this Microsoft.AspNetCore.DataProtection.IDataProtectionBuilder! builder, System.Func<System.IServiceProvider!, StackExchange.Redis.IDatabase!>! databaseFactory) -> Microsoft.AspNetCore.DataProtection.IDataProtectionBuilder!
static Microsoft.AspNetCore.DataProtection.StackExchangeRedisDataProtectionBuilderExtensions.PersistKeysToStackExchangeRedis(this Microsoft.AspNetCore.DataProtection.IDataProtectionBuilder! builder, System.Func<System.IServiceProvider!, StackExchange.Redis.IDatabase!>! databaseFactory, StackExchange.Redis.RedisKey key) -> Microsoft.AspNetCore.DataProtection.IDataProtectionBuilder!
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.AspNetCore.DataProtection.StackExchangeRedis;
using Microsoft.AspNetCore.Shared;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using StackExchange.Redis;

namespace Microsoft.AspNetCore.DataProtection;
Expand All @@ -28,7 +29,7 @@ public static IDataProtectionBuilder PersistKeysToStackExchangeRedis(this IDataP
{
ArgumentNullThrowHelper.ThrowIfNull(builder);
ArgumentNullThrowHelper.ThrowIfNull(databaseFactory);
return PersistKeysToStackExchangeRedisInternal(builder, databaseFactory, key);
return PersistKeysToStackExchangeRedisInternal(builder, _ => databaseFactory(), key);
}

/// <summary>
Expand All @@ -53,15 +54,44 @@ public static IDataProtectionBuilder PersistKeysToStackExchangeRedis(this IDataP
{
ArgumentNullThrowHelper.ThrowIfNull(builder);
ArgumentNullThrowHelper.ThrowIfNull(connectionMultiplexer);
return PersistKeysToStackExchangeRedisInternal(builder, () => connectionMultiplexer.GetDatabase(), key);
return PersistKeysToStackExchangeRedisInternal(builder, _ => connectionMultiplexer.GetDatabase(), key);
}

/// <summary>
/// Configures the data protection system to persist keys to the default key ('DataProtection-Keys') in Redis database
/// </summary>
/// <param name="builder">The builder instance to modify.</param>
/// <param name="databaseFactory">A factory function that uses <see cref="IServiceProvider"/> to create an <see cref="IDatabase"/> instance.</param>
/// <returns>A reference to the <see cref="IDataProtectionBuilder" /> after this operation has completed.</returns>
public static IDataProtectionBuilder PersistKeysToStackExchangeRedis(this IDataProtectionBuilder builder, Func<IServiceProvider, IDatabase> databaseFactory)
{
return PersistKeysToStackExchangeRedis(builder, databaseFactory, DataProtectionKeysName);
}

/// <summary>
/// Configures the data protection system to persist keys to the specified key in Redis database
/// </summary>
/// <param name="builder">The builder instance to modify.</param>
/// <param name="databaseFactory">A factory function that uses <see cref="IServiceProvider"/> to create an <see cref="IDatabase"/> instance.</param>
/// <param name="key">The <see cref="RedisKey"/> used to store key list.</param>
/// <returns>A reference to the <see cref="IDataProtectionBuilder" /> after this operation has completed.</returns>
public static IDataProtectionBuilder PersistKeysToStackExchangeRedis(this IDataProtectionBuilder builder, Func<IServiceProvider, IDatabase> databaseFactory, RedisKey key)
{
ArgumentNullThrowHelper.ThrowIfNull(builder);
ArgumentNullThrowHelper.ThrowIfNull(databaseFactory);
return PersistKeysToStackExchangeRedisInternal(builder, databaseFactory, key);
}

private static IDataProtectionBuilder PersistKeysToStackExchangeRedisInternal(IDataProtectionBuilder builder, Func<IDatabase> databaseFactory, RedisKey key)
private static IDataProtectionBuilder PersistKeysToStackExchangeRedisInternal(IDataProtectionBuilder builder, Func<IServiceProvider, IDatabase> databaseFactory, RedisKey key)
{
builder.Services.Configure<KeyManagementOptions>(options =>
builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services =>
{
options.XmlRepository = new RedisXmlRepository(databaseFactory, key);
return new ConfigureOptions<KeyManagementOptions>(options =>
{
options.XmlRepository = new RedisXmlRepository(() => databaseFactory(services), key);
Comment on lines +87 to +91
Copy link
Preview

Copilot AI Jul 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The lambda parameter services shadows the builder.Services property and may confuse readers. Consider renaming the parameter to sp or serviceProvider to clarify its purpose.

Copilot uses AI. Check for mistakes.

});
});

return builder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,21 @@ public void PersistKeysToRedis_UsesRedisXmlRepository()
var options = services.GetRequiredService<IOptions<KeyManagementOptions>>();
Assert.IsType<RedisXmlRepository>(options.Value.XmlRepository);
}

[Fact]
public void PersistKeysToRedis_FactoryMethod_UsesRedisXmlRepository()
{
// Arrange
var connection = Mock.Of<IConnectionMultiplexer>();
var serviceCollection = new ServiceCollection();
var builder = serviceCollection.AddDataProtection();

// Act
builder.PersistKeysToStackExchangeRedis(services => services.GetRequiredService<IConnectionMultiplexer>().GetDatabase());
var services = serviceCollection.BuildServiceProvider();

// Assert
var options = services.GetRequiredService<IOptions<KeyManagementOptions>>();
Assert.IsType<RedisXmlRepository>(options.Value.XmlRepository);
}
}
Loading