Skip to content

Commit

Permalink
IAsyncConfigureOptions (OrchardCMS#14759)
Browse files Browse the repository at this point in the history
  • Loading branch information
jtkech authored and urbanit committed Mar 18, 2024
1 parent c65f184 commit fb86085
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Microsoft.Extensions.Options;

namespace OrchardCore.DataProtection.Azure;

public class BlobOptions
public class BlobOptions : IAsyncOptions
{
public string ConnectionString { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace OrchardCore.DataProtection.Azure;

public class BlobOptionsSetup
public class BlobOptionsSetup : IAsyncConfigureOptions<BlobOptions>
{
private readonly FluidParser _fluidParser = new();

Expand All @@ -32,14 +32,14 @@ public BlobOptionsSetup(
_logger = logger;
}

public async Task ConfigureAsync(BlobOptions options)
public async ValueTask ConfigureAsync(BlobOptions options)
{
_configuration.Bind("OrchardCore_DataProtection_Azure", options);
await ConfigureContainerNameAsync(options);
await ConfigureBlobNameAsync(options);
}

private async Task ConfigureContainerNameAsync(BlobOptions options)
private async ValueTask ConfigureContainerNameAsync(BlobOptions options)
{
try
{
Expand Down Expand Up @@ -78,7 +78,7 @@ private async Task ConfigureContainerNameAsync(BlobOptions options)
}
}

private async Task ConfigureBlobNameAsync(BlobOptions options)
private async ValueTask ConfigureBlobNameAsync(BlobOptions options)
{
if (string.IsNullOrEmpty(options.BlobName))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ public override void ConfigureServices(IServiceCollection services)
if (!string.IsNullOrWhiteSpace(connectionString))
{
services
.AddSingleton(new BlobOptions())
.AddTransient<BlobOptionsSetup>()
.Configure<BlobOptions, BlobOptionsSetup>()
.AddDataProtection()
.PersistKeysToAzureBlobStorage(sp =>
{
Expand All @@ -40,13 +39,6 @@ public override void ConfigureServices(IServiceCollection services)
options.ContainerName,
options.BlobName);
});

services.Initialize(async sp =>
{
var options = sp.GetRequiredService<BlobOptions>();
var setup = sp.GetRequiredService<BlobOptionsSetup>();
await setup.ConfigureAsync(options);
});
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Threading.Tasks;

namespace Microsoft.Extensions.Options;

/// <summary>
/// Used to configure asynchronously a type of options just after a tenant container is created.
/// </summary>
public interface IAsyncConfigureOptions<TOptions> where TOptions : class, IAsyncOptions
{
/// <summary>
/// Configures asynchronously an options instance.
/// </summary>
ValueTask ConfigureAsync(TOptions options);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Microsoft.Extensions.Options;

/// <summary>
/// Marks a type of options intended to be registered as a singleton and configured asynchronously
/// by an <see cref="IAsyncConfigureOptions{TOptions}"/> just after a tenant container is created.
/// </summary>
public interface IAsyncOptions
{
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,63 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using OrchardCore.Environment.Shell.Builders;

namespace Microsoft.Extensions.DependencyInjection;

public static class ServiceCollectionExtensions
{
/// <summary>
/// Registers a delegate to be invoked asynchronously after a tenant container is created.
/// Registers a delegate to be invoked asynchronously just after a tenant container is created.
/// </summary>
public static IServiceCollection Initialize(this IServiceCollection services, Func<IServiceProvider, ValueTask> _initializeAsync)
=> services.Configure<ShellContainerOptions>(options => options.Initializers.Add(_initializeAsync));
public static IServiceCollection Initialize(this IServiceCollection services, Func<IServiceProvider, ValueTask> initializeAsync)
=> services.Configure<ShellContainerOptions>(options => options.Initializers.Add(initializeAsync));

/// <summary>
/// Registers a delegate used to configure asynchronously a type of options just after a tenant container is created.
/// </summary>
public static IServiceCollection Configure<TOptions>(
this IServiceCollection services, Func<IServiceProvider, TOptions, ValueTask> configureAsync)
where TOptions : class, IAsyncOptions, new()
{
if (!services.Any(d => d.ServiceType == typeof(TOptions)))
{
services.AddSingleton(new TOptions());
}

services.Initialize(async sp =>
{
var options = sp.GetRequiredService<TOptions>();
await configureAsync(sp, options);
});

return services;
}

/// <summary>
/// Registers an <see cref="IAsyncConfigureOptions{TOptions}"/> used to configure
/// asynchronously a type of options just after a tenant container is created.
/// </summary>
public static IServiceCollection Configure<TOptions, TConfigure>(this IServiceCollection services)
where TOptions : class, IAsyncOptions, new() where TConfigure : IAsyncConfigureOptions<TOptions>
{
if (!services.Any(d => d.ServiceType == typeof(TOptions)))
{
services.AddSingleton(new TOptions());
}

if (!services.Any(d => d.ServiceType == typeof(TConfigure)))
{
services.AddTransient(typeof(TConfigure));
services.Initialize(async sp =>
{
var options = sp.GetRequiredService<TOptions>();
var setup = sp.GetRequiredService<TConfigure>();
await setup.ConfigureAsync(options);
});
}

return services;
}
}

0 comments on commit fb86085

Please sign in to comment.