From 084ddc4b567eae6d04a0399f648d55c2a8daa4c8 Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 2 Nov 2026 15:02:07 +0100 Subject: [PATCH] refactor(application): introduce MessagingServiceApplicationConfiguration builder Replace the implicit IConfiguration-based DI registration with an explicit builder that validates required steps at startup. - Add MessagingServiceApplicationConfiguration with mandatory steps: SetLuckyPennySoftLicenseKey(), ConfigureEmailAccounts() / PublishOnly() - EnsureConfigured() throws at registration time if either step is missing, surfacing misconfiguration before the app starts - Keep the IConfiguration convenience overload as a thin wrapper over the builder for backward-compatible call sites - Move DependencyInjection.cs into a DependencyInjection/ subfolder alongside the new configuration class --- .../DependencyInjection.cs | 27 ++++--- ...essagingServiceApplicationConfiguration.cs | 78 +++++++++++++++++++ 2 files changed, 94 insertions(+), 11 deletions(-) rename src/core/DigitalData.MessagingService.Application/{ => DependencyInjection}/DependencyInjection.cs (56%) create mode 100644 src/core/DigitalData.MessagingService.Application/DependencyInjection/MessagingServiceApplicationConfiguration.cs diff --git a/src/core/DigitalData.MessagingService.Application/DependencyInjection.cs b/src/core/DigitalData.MessagingService.Application/DependencyInjection/DependencyInjection.cs similarity index 56% rename from src/core/DigitalData.MessagingService.Application/DependencyInjection.cs rename to src/core/DigitalData.MessagingService.Application/DependencyInjection/DependencyInjection.cs index 636508e..ba20e18 100644 --- a/src/core/DigitalData.MessagingService.Application/DependencyInjection.cs +++ b/src/core/DigitalData.MessagingService.Application/DependencyInjection/DependencyInjection.cs @@ -1,46 +1,51 @@ #if NET -using DigitalData.MessagingService.Application.Common.Options; using FluentValidation; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System.Reflection; -namespace DigitalData.MessagingService.Application; +namespace DigitalData.MessagingService.Application.DependencyInjection; /// /// Dependency injection configuration for Application layer. /// public static class DependencyInjection { - public static IServiceCollection AddMessagingServiceApplication(this IServiceCollection services, IConfiguration configuration) + public static IServiceCollection AddMessagingServiceApplication(this IServiceCollection services, Action configure) { var assembly = Assembly.GetExecutingAssembly(); - // Read LuckyPennySoft license key from appsettings.json - var licenseKey = configuration.GetValue("LuckyPennySoftLicenseKey") - ?? throw new InvalidOperationException("LuckyPennySoftLicenseKey not found in configuration"); + var configuration = new MessagingServiceApplicationConfiguration(services); + configure(configuration); + configuration.EnsureConfigured(); // MediatR - Register all handlers services.AddMediatR(config => { - config.LicenseKey = licenseKey; + config.LicenseKey = configuration.LuckyPennySoftLicenseKey; config.RegisterServicesFromAssembly(assembly); }); // AutoMapper - Use built-in DI extension (AutoMapper 16.2.0+) services.AddAutoMapper(config => { - config.LicenseKey = licenseKey; + config.LicenseKey = configuration.LuckyPennySoftLicenseKey; config.AddMaps(assembly); }); // FluentValidation - Register all validators services.AddValidatorsFromAssembly(assembly); - // Register EmailAccounts configuration (IOptions) - services.Configure(configuration.GetSection(EmailAccountsOptions.SectionName)); - return services; } + + public static IServiceCollection AddMessagingServiceApplication(this IServiceCollection services, IConfiguration configuration) + { + return services.AddMessagingServiceApplication(cfg => + { + cfg.SetLuckyPennySoftLicenseKey(configuration); + cfg.ConfigureEmailAccounts(configuration); + }); + } } #endif \ No newline at end of file diff --git a/src/core/DigitalData.MessagingService.Application/DependencyInjection/MessagingServiceApplicationConfiguration.cs b/src/core/DigitalData.MessagingService.Application/DependencyInjection/MessagingServiceApplicationConfiguration.cs new file mode 100644 index 0000000..ec82c2b --- /dev/null +++ b/src/core/DigitalData.MessagingService.Application/DependencyInjection/MessagingServiceApplicationConfiguration.cs @@ -0,0 +1,78 @@ +#if NET +using DigitalData.MessagingService.Application.Common.Options; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace DigitalData.MessagingService.Application.DependencyInjection; + +public partial class MessagingServiceApplicationConfiguration +{ + private IServiceCollection Services { get; } + + private (bool LuckyPennySoftLicenseKey, bool EmailAccounts) _configured = (LuckyPennySoftLicenseKey: false, EmailAccounts: false); + + internal MessagingServiceApplicationConfiguration(IServiceCollection services) + { + Services = services; + } + + internal void EnsureConfigured() + { + if (!_configured.LuckyPennySoftLicenseKey) + { + throw new InvalidOperationException("LuckyPennySoftLicenseKey is not configured. Please call SetLuckyPennySoftLicenseKey() or SetLuckyPennySoftLicenseKey(IConfiguration) in DI configuration."); + } + if (!_configured.EmailAccounts) + { + throw new InvalidOperationException("EmailAccountsOptions is not configured. Please call ConfigureEmailAccountsOptions() or ConfigureEmailAccounts(IConfiguration) in DI configuration."); + } + } + + #region LuckyPennySoftLicenseKey + internal string? LuckyPennySoftLicenseKey { get; set; } = null; + + public MessagingServiceApplicationConfiguration SetLuckyPennySoftLicenseKey(string licenseKey) + { + if (string.IsNullOrWhiteSpace(licenseKey)) + throw new InvalidOperationException("LuckyPennySoftLicenseKey is not configured. Please call SetLuckyPennySoftLicenseKey() or SetLuckyPennySoftLicenseKey(IConfiguration) in DI configuration."); + + LuckyPennySoftLicenseKey = licenseKey; + _configured.LuckyPennySoftLicenseKey = true; + return this; + } + + public MessagingServiceApplicationConfiguration SetLuckyPennySoftLicenseKey(IConfiguration configuration, string key = "LuckyPennySoftLicenseKey") + { + return SetLuckyPennySoftLicenseKey(configuration.GetValue(key) ?? string.Empty); + } + #endregion LuckyPennySoftLicenseKey + + #region EmailAccountsOptions + /// + /// Ignores whether EmailAccountsOptions is configured or not. Use this method if you just want to publish messages to the messaging service; not to send + /// emails. If you want to consume the messaging service to send emails, you must configure EmailAccountsOptions using ConfigureEmailAccountsOptions() or + /// ConfigureEmailAccounts(IConfiguration). + /// + /// + public MessagingServiceApplicationConfiguration PublishOnly() + { + _configured.EmailAccounts = true; + return this; + } + + public MessagingServiceApplicationConfiguration ConfigureEmailAccountsOptions(Action configureOptions) + { + Services.Configure(configureOptions); + _configured.EmailAccounts = true; + return this; + } + + public MessagingServiceApplicationConfiguration ConfigureEmailAccounts(IConfiguration configuration, string sectionName = EmailAccountsOptions.SectionName) + { + Services.Configure(configuration.GetSection(sectionName)); + _configured.EmailAccounts = true; + return this; + } + #endregion EmailAccountsOptions +} +#endif \ No newline at end of file