Skip to content

Commit d911b9f

Browse files
Mike Blairclaude
andcommitted
feat: register IConfigurationWriter<T> as open generic via proxy
Replace the hardcoded IConfigurationWriter<RoleConfiguration> singleton in AddAuthorization() with a generic ConfigurationWriterProxy<T> that resolves any IConfigurationWriter<T> lazily from the factory. Any endpoint can now inject a typed writer directly without per-type bridge registrations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d211ddd commit d911b9f

3 files changed

Lines changed: 54 additions & 6 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using FractalDataWorks.Configuration;
5+
using FractalDataWorks.Results;
6+
7+
namespace FractalDataWorks.Configuration.Writers;
8+
9+
/// <summary>
10+
/// Open-generic proxy that resolves a typed <see cref="IConfigurationWriter{TConfiguration}"/>
11+
/// lazily from <see cref="IConfigurationWriterFactory"/> on first use.
12+
/// Registered as <c>services.AddSingleton(typeof(IConfigurationWriter&lt;&gt;), typeof(ConfigurationWriterProxy&lt;&gt;))</c>
13+
/// so that any endpoint can inject <c>IConfigurationWriter&lt;T&gt;</c> directly without
14+
/// requiring per-type registrations.
15+
/// </summary>
16+
/// <typeparam name="TConfiguration">The configuration type.</typeparam>
17+
internal sealed class ConfigurationWriterProxy<TConfiguration> : IConfigurationWriter<TConfiguration>
18+
where TConfiguration : class, IGenericConfiguration
19+
{
20+
private readonly Lazy<IConfigurationWriter<TConfiguration>> _inner;
21+
22+
public ConfigurationWriterProxy(IConfigurationWriterFactory factory)
23+
{
24+
if (factory == null) throw new ArgumentNullException(nameof(factory));
25+
26+
_inner = new Lazy<IConfigurationWriter<TConfiguration>>(() =>
27+
{
28+
var result = factory.Create<TConfiguration>();
29+
if (result.IsFailure)
30+
{
31+
throw new InvalidOperationException(
32+
$"Failed to create IConfigurationWriter<{typeof(TConfiguration).Name}>: {result.CurrentMessage}");
33+
}
34+
35+
return result.Value!;
36+
});
37+
}
38+
39+
/// <inheritdoc />
40+
public Task<IGenericResult<TConfiguration>> Save(TConfiguration configuration, CancellationToken ct = default)
41+
=> _inner.Value.Save(configuration, ct);
42+
43+
/// <inheritdoc />
44+
public Task<IGenericResult> Delete(Guid id, CancellationToken ct = default)
45+
=> _inner.Value.Delete(id, ct);
46+
47+
/// <inheritdoc />
48+
public Task<IGenericResult> Delete(string name, CancellationToken ct = default)
49+
=> _inner.Value.Delete(name, ct);
50+
}

src/FractalDataWorks.Configuration.Writers/ConfigurationWriterServiceCollectionExtensions.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ public static IServiceCollection AddConfigurationWriters(
4848
services.TryAddSingleton<IConfigurationReloader, DefaultConfigurationReloader>();
4949
services.TryAddSingleton<IConfigurationWriterFactory, DefaultConfigurationWriterFactory>();
5050

51+
// Open-generic proxy: any IConfigurationWriter<T> resolves lazily from the factory.
52+
// Endpoints can inject IConfigurationWriter<T> directly instead of using IConfigurationWriterFactory.
53+
services.TryAddSingleton(typeof(IConfigurationWriter<>), typeof(ConfigurationWriterProxy<>));
54+
5155
return services;
5256
}
5357

src/FractalDataWorks.Hosting/Builders/ServiceTypeRegistrationBuilder.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using FractalDataWorks.Hosting.Logging;
55
using FractalDataWorks.Services.Authentication;
66
using FractalDataWorks.Services.Authorization;
7-
using FractalDataWorks.Services.Authorization.Configuration;
87
using FractalDataWorks.Services.Connections;
98
using FractalDataWorks.Services.Data;
109
using FractalDataWorks.Services.Etl;
@@ -102,11 +101,6 @@ public ServiceTypeRegistrationBuilder AddAuthorization()
102101
HostingLog.ServiceTypeRegistrationPhase(_logger, "Configure", "Authorization");
103102
_builder.Services.AddFrameworkAuthorizationPolicies();
104103

105-
// Bridge typed configuration writer for role endpoints.
106-
// The lambda resolves lazily after InitializeFrameworkServiceTypes() has set up the factory.
107-
_builder.Services.AddSingleton<IConfigurationWriter<RoleConfiguration>>(sp =>
108-
sp.GetRequiredService<IConfigurationWriterFactory>().Create<RoleConfiguration>().Value!);
109-
110104
State.HasAuthorization = true;
111105
return this;
112106
}

0 commit comments

Comments
 (0)