Skip to content

Commit 4b059f0

Browse files
authored
Fix Azure DataProtection (OrchardCMS#18067)
1 parent 7783107 commit 4b059f0

File tree

8 files changed

+93
-27
lines changed

8 files changed

+93
-27
lines changed

src/OrchardCore.Modules/OrchardCore.DataProtection.Azure/BlobModularTenantEvents.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Azure.Storage.Blobs;
22
using Microsoft.Extensions.Logging;
3+
using Microsoft.Extensions.Options;
34
using OrchardCore.Environment.Shell.Removing;
45
using OrchardCore.Modules;
56

@@ -14,10 +15,10 @@ internal sealed class BlobModularTenantEvents : ModularTenantEvents
1415
private readonly ILogger _logger;
1516

1617
public BlobModularTenantEvents(
17-
BlobOptions blobOptions,
18+
IOptions<BlobOptions> blobOptions,
1819
ILogger<BlobModularTenantEvents> logger)
1920
{
20-
_blobOptions = blobOptions;
21+
_blobOptions = blobOptions.Value;
2122
_logger = logger;
2223
}
2324

src/OrchardCore.Modules/OrchardCore.DataProtection.Azure/BlobOptions.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
using Microsoft.Extensions.Options;
2-
31
namespace OrchardCore.DataProtection.Azure;
42

5-
public class BlobOptions : IAsyncOptions
3+
public class BlobOptions
64
{
75
public string ConnectionString { get; set; }
86

src/OrchardCore.Modules/OrchardCore.DataProtection.Azure/BlobOptionsSetup.cs renamed to src/OrchardCore.Modules/OrchardCore.DataProtection.Azure/BlobOptionsConfiguration.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
namespace OrchardCore.DataProtection.Azure;
1111

12-
public class BlobOptionsSetup : IAsyncConfigureOptions<BlobOptions>
12+
internal sealed class BlobOptionsConfiguration : IConfigureOptions<BlobOptions>
1313
{
1414
private readonly FluidParser _fluidParser = new();
1515

@@ -18,28 +18,28 @@ public class BlobOptionsSetup : IAsyncConfigureOptions<BlobOptions>
1818
private readonly ShellSettings _shellSettings;
1919
private readonly ILogger _logger;
2020

21-
public BlobOptionsSetup(
21+
public BlobOptionsConfiguration(
2222
IShellConfiguration configuration,
2323
IOptions<ShellOptions> shellOptions,
2424
ShellSettings shellSettings,
25-
ILogger<BlobOptionsSetup> logger)
25+
ILogger<BlobOptionsConfiguration> logger)
2626
{
2727
_configuration = configuration;
2828
_shellOptions = shellOptions.Value;
2929
_shellSettings = shellSettings;
3030
_logger = logger;
3131
}
3232

33-
public async ValueTask ConfigureAsync(BlobOptions options)
33+
public void Configure(BlobOptions options)
3434
{
3535
_logger.LogDebug("Configuring BlobOptions in BlobOptionsSetup");
3636

3737
_configuration.Bind("OrchardCore_DataProtection_Azure", options);
38-
await ConfigureContainerNameAsync(options);
39-
await ConfigureBlobNameAsync(options);
38+
ConfigureContainerName(options);
39+
ConfigureBlobName(options);
4040
}
4141

42-
private async ValueTask ConfigureContainerNameAsync(BlobOptions options)
42+
private void ConfigureContainerName(BlobOptions options)
4343
{
4444
_logger.LogDebug("Configuring BlobOptions.ContainerName in BlobOptionsSetup");
4545

@@ -54,7 +54,7 @@ private async ValueTask ConfigureContainerNameAsync(BlobOptions options)
5454
var template = _fluidParser.Parse(options.ContainerName);
5555

5656
// Container name must be lowercase.
57-
var containerName = (await template.RenderAsync(templateContext, NullEncoder.Default)).ToLower();
57+
var containerName = template.Render(templateContext, NullEncoder.Default).ToLowerInvariant();
5858
options.ContainerName = containerName.Replace("\r", string.Empty).Replace("\n", string.Empty);
5959

6060
if (_logger.IsEnabled(LogLevel.Debug))
@@ -74,7 +74,7 @@ private async ValueTask ConfigureContainerNameAsync(BlobOptions options)
7474
{
7575
_logger.LogDebug("Testing data protection container {ContainerName} existence", options.ContainerName);
7676
var blobContainer = new BlobContainerClient(options.ConnectionString, options.ContainerName);
77-
var response = await blobContainer.CreateIfNotExistsAsync(PublicAccessType.None);
77+
var response = blobContainer.CreateIfNotExistsAsync(PublicAccessType.None).GetAwaiter().GetResult();
7878
_logger.LogDebug("Data protection container {ContainerName} created.", options.ContainerName);
7979
}
8080
catch (Exception e)
@@ -85,7 +85,7 @@ private async ValueTask ConfigureContainerNameAsync(BlobOptions options)
8585
}
8686
}
8787

88-
private async ValueTask ConfigureBlobNameAsync(BlobOptions options)
88+
private void ConfigureBlobName(BlobOptions options)
8989
{
9090
_logger.LogDebug("Configuring BlobOptions.BlobName in BlobOptionsSetup");
9191

@@ -111,7 +111,7 @@ private async ValueTask ConfigureBlobNameAsync(BlobOptions options)
111111

112112
var template = _fluidParser.Parse(options.BlobName);
113113

114-
var blobName = await template.RenderAsync(templateContext, NullEncoder.Default);
114+
var blobName = template.Render(templateContext, NullEncoder.Default);
115115
options.BlobName = blobName.Replace("\r", string.Empty).Replace("\n", string.Empty);
116116

117117
if (_logger.IsEnabled(LogLevel.Debug))

src/OrchardCore.Modules/OrchardCore.DataProtection.Azure/Startup.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.Extensions.Configuration;
44
using Microsoft.Extensions.DependencyInjection;
55
using Microsoft.Extensions.Logging;
6+
using Microsoft.Extensions.Options;
67
using OrchardCore.Environment.Shell.Configuration;
78
using OrchardCore.Modules;
89

@@ -28,23 +29,37 @@ public override void ConfigureServices(IServiceCollection services)
2829

2930
if (!string.IsNullOrWhiteSpace(connectionString))
3031
{
32+
if (_logger.IsEnabled(LogLevel.Debug))
33+
{
34+
_logger.LogDebug("OrchardCore_DataProtection_Azure:ConnectionString was found. Adding 'OrchardCore.DataProtection.Azure' feature services.");
35+
}
36+
3137
services
32-
.Configure<BlobOptions, BlobOptionsSetup>()
3338
.AddDataProtection()
3439
.PersistKeysToAzureBlobStorage(sp =>
3540
{
36-
var options = sp.GetRequiredService<BlobOptions>();
41+
var options = sp.GetRequiredService<IOptions<BlobOptions>>().Value;
42+
43+
var logger = sp.GetRequiredService<ILogger<Startup>>();
44+
45+
if (logger.IsEnabled(LogLevel.Debug))
46+
{
47+
logger.LogDebug("Creating BlobClient instance using '{ContainerName}' as container name and '{BlobName}' as blob name.", options.ContainerName, options.BlobName);
48+
}
49+
3750
return new BlobClient(
3851
options.ConnectionString,
3952
options.ContainerName,
4053
options.BlobName);
4154
});
4255

56+
services.AddSingleton<IConfigureOptions<BlobOptions>, BlobOptionsConfiguration>();
57+
4358
services.AddScoped<IModularTenantEvents, BlobModularTenantEvents>();
4459
}
4560
else
4661
{
47-
_logger.LogCritical("No connection string was supplied for OrchardCore.DataProtection.Azure. Ensure that an application setting containing a valid Azure Storage connection string is available at `Modules:OrchardCore.DataProtection.Azure:ConnectionString`.");
62+
_logger.LogCritical("No connection string was supplied for OrchardCore.DataProtection.Azure. Ensure that an application setting containing a valid Azure Storage connection string is available at `OrchardCore:OrchardCore_DataProtection_Azure:ConnectionString`.");
4863
}
4964
}
5065
}

src/OrchardCore/OrchardCore.Abstractions/Shell/Builders/Extensions/ServiceCollectionExtensions.cs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Microsoft.Extensions.Logging;
12
using Microsoft.Extensions.Options;
23
using OrchardCore.Environment.Shell.Builders;
34

@@ -23,10 +24,11 @@ public static IServiceCollection Configure<TOptions>(
2324
services.AddSingleton(new TOptions());
2425
}
2526

26-
services.Initialize(async sp =>
27+
services.Initialize(sp =>
2728
{
2829
var options = sp.GetRequiredService<TOptions>();
29-
await configureAsync(sp, options);
30+
31+
return configureAsync(sp, options);
3032
});
3133

3234
return services;
@@ -36,21 +38,38 @@ public static IServiceCollection Configure<TOptions>(
3638
/// Registers an <see cref="IAsyncConfigureOptions{TOptions}"/> used to configure
3739
/// asynchronously a type of options just after a tenant container is created.
3840
/// </summary>
39-
public static IServiceCollection Configure<TOptions, TConfigure>(this IServiceCollection services)
40-
where TOptions : class, IAsyncOptions, new() where TConfigure : IAsyncConfigureOptions<TOptions>
41+
public static IServiceCollection Configure<TOptions, TConfigure>(this IServiceCollection services, ILogger logger = null)
42+
where TOptions : class, IAsyncOptions, new()
43+
where TConfigure : IAsyncConfigureOptions<TOptions>
4144
{
4245
if (!services.Any(d => d.ServiceType == typeof(TOptions)))
4346
{
47+
if (logger is not null && logger.IsEnabled(LogLevel.Debug))
48+
{
49+
logger.LogDebug("Adding IAsyncOptions type '{OptionsType}' instance to the service collection.", typeof(TOptions).FullName);
50+
}
51+
4452
services.AddSingleton(new TOptions());
4553
}
4654

4755
if (!services.Any(d => d.ServiceType == typeof(TConfigure)))
4856
{
57+
if (logger is not null && logger.IsEnabled(LogLevel.Debug))
58+
{
59+
logger.LogDebug("Adding IAsyncConfigureOptions type '{ConfigureType}' instance to the service collection.", typeof(TConfigure).FullName);
60+
}
61+
4962
services.AddTransient(typeof(TConfigure));
5063
services.Initialize(sp =>
5164
{
5265
var options = sp.GetRequiredService<TOptions>();
5366
var setup = sp.GetRequiredService<TConfigure>();
67+
var logger = sp.GetRequiredService<ILogger<TConfigure>>();
68+
69+
if (logger.IsEnabled(LogLevel.Debug))
70+
{
71+
logger.LogDebug("Invoking the ConfigureAsync method on '{ConfigureType}' to configure the '{OptionsType}'", typeof(TConfigure).FullName, typeof(TOptions).FullName);
72+
}
5473

5574
return setup.ConfigureAsync(options);
5675
});

src/OrchardCore/OrchardCore/Shell/Builders/ShellContainerFactory.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.Extensions.DependencyInjection;
33
using Microsoft.Extensions.DependencyInjection.Extensions;
44
using Microsoft.Extensions.Hosting;
5+
using Microsoft.Extensions.Logging;
56
using OrchardCore.Environment.Extensions;
67
using OrchardCore.Environment.Extensions.Features;
78
using OrchardCore.Environment.Shell.Builders.Models;
@@ -17,21 +18,29 @@ public class ShellContainerFactory : IShellContainerFactory
1718
private readonly IExtensionManager _extensionManager;
1819
private readonly IServiceProvider _serviceProvider;
1920
private readonly IServiceCollection _applicationServices;
21+
private readonly ILogger _logger;
2022

2123
public ShellContainerFactory(
2224
IHostEnvironment hostingEnvironment,
2325
IExtensionManager extensionManager,
2426
IServiceProvider serviceProvider,
25-
IServiceCollection applicationServices)
27+
IServiceCollection applicationServices,
28+
ILogger<ShellContainerFactory> logger)
2629
{
2730
_hostingEnvironment = hostingEnvironment;
2831
_extensionManager = extensionManager;
2932
_applicationServices = applicationServices;
33+
_logger = logger;
3034
_serviceProvider = serviceProvider;
3135
}
3236

3337
public async Task<IServiceProvider> CreateContainerAsync(ShellSettings settings, ShellBlueprint blueprint)
3438
{
39+
if (_logger.IsEnabled(LogLevel.Debug))
40+
{
41+
_logger.LogDebug("Creating service provider container for tenant '{TenantName}'", settings.Name);
42+
}
43+
3544
var tenantServiceCollection = _serviceProvider.CreateChildContainer(_applicationServices);
3645

3746
tenantServiceCollection.AddSingleton(settings);
@@ -46,7 +55,6 @@ public async Task<IServiceProvider> CreateContainerAsync(ShellSettings settings,
4655
tenantServiceCollection.AddSingleton(blueprint);
4756

4857
// Execute IStartup registrations
49-
5058
foreach (var dependency in blueprint.Dependencies.Where(t => typeof(IStartup).IsAssignableFrom(t.Key)))
5159
{
5260
tenantServiceCollection.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IStartup), dependency.Key));
@@ -132,6 +140,11 @@ public async Task<IServiceProvider> CreateContainerAsync(ShellSettings settings,
132140
var typeFeatureProvider = shellServiceProvider.GetRequiredService<ITypeFeatureProvider>();
133141
PopulateTypeFeatureProvider(typeFeatureProvider, featureAwareServiceCollection);
134142

143+
if (_logger.IsEnabled(LogLevel.Debug))
144+
{
145+
_logger.LogDebug("Done Creating service provider container for tenant '{TenantName}'", settings.Name);
146+
}
147+
135148
return shellServiceProvider;
136149
}
137150

src/OrchardCore/OrchardCore/Shell/Builders/ShellContextFactory.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,36 @@ public async Task<ShellContext> CreateDescribedContextAsync(ShellSettings settin
7979
var blueprint = await _compositionStrategy.ComposeAsync(settings, shellDescriptor);
8080
var provider = await _shellContainerFactory.CreateContainerAsync(settings, blueprint);
8181

82-
var options = provider.GetService<IOptions<ShellContainerOptions>>().Value;
82+
var options = provider.GetRequiredService<IOptions<ShellContainerOptions>>().Value;
83+
84+
if (_logger.IsEnabled(LogLevel.Debug))
85+
{
86+
_logger.LogDebug("Invoking shell container initializers described context for tenant '{TenantName}'. There are a total of '{TotalInitializers}' initializers to invoke", settings.Name, options.Initializers.Count);
87+
}
88+
8389
foreach (var initializeAsync in options.Initializers)
8490
{
8591
await initializeAsync(provider);
8692
}
8793

94+
if (_logger.IsEnabled(LogLevel.Debug))
95+
{
96+
_logger.LogDebug("Done creating described context for tenant '{TenantName}'", settings.Name);
97+
}
98+
8899
return new ShellContext
89100
{
90101
Settings = settings,
91102
Blueprint = blueprint,
92103
ServiceProvider = provider,
93104
};
94105
}
106+
catch (Exception ex)
107+
{
108+
_logger.LogError(ex, "Error occurred while creating described context for tenant '{TenantName}'", settings.Name);
109+
110+
throw;
111+
}
95112
finally
96113
{
97114
Interlocked.Decrement(ref settings._shellCreating);

test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@ public ShellContainerFactoryTests()
3333
applicationServices.AddSingleton<IHostSingletonAndScopedOfTheSameType, HostSingletonOfTheSameTypeAsScoped>();
3434
applicationServices.AddScoped<IHostSingletonAndScopedOfTheSameType, HostScopedOfTheSameTypeAsSingleton>();
3535

36+
var loggerMock = new Mock<ILogger<ShellContainerFactory>>();
37+
3638
_shellContainerFactory = new ShellContainerFactory(
3739
new StubHostingEnvironment(),
3840
new StubExtensionManager(),
3941
_applicationServiceProvider = applicationServices.BuildServiceProvider(),
40-
applicationServices
42+
applicationServices,
43+
loggerMock.Object
4144
);
4245
}
4346

0 commit comments

Comments
 (0)