refactor: adopt ZB.MOM.WW.Configuration in MxGateway (behaviour-preserving)

This commit is contained in:
Joseph Doherty
2026-06-01 18:22:21 -04:00
parent 437ab65fc1
commit 459a88b3e7
7 changed files with 92 additions and 107 deletions
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Options; using Microsoft.Extensions.Configuration;
using ZB.MOM.WW.Configuration;
namespace ZB.MOM.WW.MxGateway.Server.Configuration; namespace ZB.MOM.WW.MxGateway.Server.Configuration;
@@ -6,15 +7,14 @@ public static class GatewayConfigurationServiceCollectionExtensions
{ {
/// <summary>Registers gateway configuration services in the dependency injection container.</summary> /// <summary>Registers gateway configuration services in the dependency injection container.</summary>
/// <param name="services">The service collection.</param> /// <param name="services">The service collection.</param>
/// <param name="configuration">The configuration to bind gateway options from.</param>
/// <returns>The service collection for chaining.</returns> /// <returns>The service collection for chaining.</returns>
public static IServiceCollection AddGatewayConfiguration(this IServiceCollection services) public static IServiceCollection AddGatewayConfiguration(
this IServiceCollection services, IConfiguration configuration)
{ {
services services.AddValidatedOptions<GatewayOptions, GatewayOptionsValidator>(
.AddOptions<GatewayOptions>() configuration, GatewayOptions.SectionName);
.BindConfiguration(GatewayOptions.SectionName)
.ValidateOnStart();
services.AddSingleton<IValidateOptions<GatewayOptions>, GatewayOptionsValidator>();
services.AddSingleton<IGatewayConfigurationProvider, GatewayConfigurationProvider>(); services.AddSingleton<IGatewayConfigurationProvider, GatewayConfigurationProvider>();
return services; return services;
@@ -1,9 +1,9 @@
using Microsoft.Extensions.Options; using ZB.MOM.WW.Configuration;
using ZB.MOM.WW.MxGateway.Contracts; using ZB.MOM.WW.MxGateway.Contracts;
namespace ZB.MOM.WW.MxGateway.Server.Configuration; namespace ZB.MOM.WW.MxGateway.Server.Configuration;
public sealed class GatewayOptionsValidator : IValidateOptions<GatewayOptions> public sealed class GatewayOptionsValidator : OptionsValidatorBase<GatewayOptions>
{ {
private const int MinimumMaxMessageBytes = 1024; private const int MinimumMaxMessageBytes = 1024;
private const int MaximumMaxMessageBytes = 256 * 1024 * 1024; private const int MaximumMaxMessageBytes = 256 * 1024 * 1024;
@@ -11,33 +11,26 @@ public sealed class GatewayOptionsValidator : IValidateOptions<GatewayOptions>
/// <summary> /// <summary>
/// Validates gateway configuration options. /// Validates gateway configuration options.
/// </summary> /// </summary>
/// <param name="name">Options name.</param> /// <param name="builder">The accumulator to record failures on.</param>
/// <param name="options">Gateway options to validate.</param> /// <param name="options">Gateway options to validate.</param>
/// <returns>Validation result.</returns> protected override void Validate(ValidationBuilder builder, GatewayOptions options)
public ValidateOptionsResult Validate(string? name, GatewayOptions options)
{ {
List<string> failures = []; ValidateAuthentication(options.Authentication, builder);
ValidateLdap(options.Ldap, builder);
ValidateAuthentication(options.Authentication, failures); ValidateWorker(options.Worker, builder);
ValidateLdap(options.Ldap, failures); ValidateSessions(options.Sessions, builder);
ValidateWorker(options.Worker, failures); ValidateEvents(options.Events, builder);
ValidateSessions(options.Sessions, failures); ValidateDashboard(options.Dashboard, builder);
ValidateEvents(options.Events, failures); ValidateProtocol(options.Protocol, builder);
ValidateDashboard(options.Dashboard, failures); ValidateAlarms(options.Alarms, builder);
ValidateProtocol(options.Protocol, failures); ValidateTls(options.Tls, builder);
ValidateAlarms(options.Alarms, failures);
ValidateTls(options.Tls, failures);
return failures.Count == 0
? ValidateOptionsResult.Success
: ValidateOptionsResult.Fail(failures);
} }
private static void ValidateAuthentication(AuthenticationOptions options, List<string> failures) private static void ValidateAuthentication(AuthenticationOptions options, ValidationBuilder builder)
{ {
if (!Enum.IsDefined(options.Mode)) if (!Enum.IsDefined(options.Mode))
{ {
failures.Add("MxGateway:Authentication:Mode must be a supported authentication mode."); builder.Add("MxGateway:Authentication:Mode must be a supported authentication mode.");
return; return;
} }
@@ -46,67 +39,67 @@ public sealed class GatewayOptionsValidator : IValidateOptions<GatewayOptions>
AddIfBlank( AddIfBlank(
options.SqlitePath, options.SqlitePath,
"MxGateway:Authentication:SqlitePath is required when API-key authentication is enabled.", "MxGateway:Authentication:SqlitePath is required when API-key authentication is enabled.",
failures); builder);
AddIfInvalidPath( AddIfInvalidPath(
options.SqlitePath, options.SqlitePath,
"MxGateway:Authentication:SqlitePath must be a valid filesystem path.", "MxGateway:Authentication:SqlitePath must be a valid filesystem path.",
failures); builder);
AddIfBlank( AddIfBlank(
options.PepperSecretName, options.PepperSecretName,
"MxGateway:Authentication:PepperSecretName is required when API-key authentication is enabled.", "MxGateway:Authentication:PepperSecretName is required when API-key authentication is enabled.",
failures); builder);
} }
} }
private static void ValidateLdap(LdapOptions options, List<string> failures) private static void ValidateLdap(LdapOptions options, ValidationBuilder builder)
{ {
if (!options.Enabled) if (!options.Enabled)
{ {
return; return;
} }
AddIfBlank(options.Server, "MxGateway:Ldap:Server is required when LDAP login is enabled.", failures); AddIfBlank(options.Server, "MxGateway:Ldap:Server is required when LDAP login is enabled.", builder);
AddIfBlank(options.SearchBase, "MxGateway:Ldap:SearchBase is required when LDAP login is enabled.", failures); AddIfBlank(options.SearchBase, "MxGateway:Ldap:SearchBase is required when LDAP login is enabled.", builder);
AddIfBlank( AddIfBlank(
options.ServiceAccountDn, options.ServiceAccountDn,
"MxGateway:Ldap:ServiceAccountDn is required when LDAP login is enabled.", "MxGateway:Ldap:ServiceAccountDn is required when LDAP login is enabled.",
failures); builder);
AddIfBlank( AddIfBlank(
options.ServiceAccountPassword, options.ServiceAccountPassword,
"MxGateway:Ldap:ServiceAccountPassword is required when LDAP login is enabled.", "MxGateway:Ldap:ServiceAccountPassword is required when LDAP login is enabled.",
failures); builder);
AddIfBlank( AddIfBlank(
options.UserNameAttribute, options.UserNameAttribute,
"MxGateway:Ldap:UserNameAttribute is required when LDAP login is enabled.", "MxGateway:Ldap:UserNameAttribute is required when LDAP login is enabled.",
failures); builder);
AddIfBlank( AddIfBlank(
options.DisplayNameAttribute, options.DisplayNameAttribute,
"MxGateway:Ldap:DisplayNameAttribute is required when LDAP login is enabled.", "MxGateway:Ldap:DisplayNameAttribute is required when LDAP login is enabled.",
failures); builder);
AddIfBlank( AddIfBlank(
options.GroupAttribute, options.GroupAttribute,
"MxGateway:Ldap:GroupAttribute is required when LDAP login is enabled.", "MxGateway:Ldap:GroupAttribute is required when LDAP login is enabled.",
failures); builder);
AddIfNotPositive(options.Port, "MxGateway:Ldap:Port must be greater than zero.", failures); AddIfNotPositive(options.Port, "MxGateway:Ldap:Port must be greater than zero.", builder);
if (!options.UseTls && !options.AllowInsecureLdap) if (!options.UseTls && !options.AllowInsecureLdap)
{ {
failures.Add("MxGateway:Ldap:AllowInsecureLdap must be true when UseTls is false."); builder.Add("MxGateway:Ldap:AllowInsecureLdap must be true when UseTls is false.");
} }
} }
private static void ValidateWorker(WorkerOptions options, List<string> failures) private static void ValidateWorker(WorkerOptions options, ValidationBuilder builder)
{ {
AddIfBlank(options.ExecutablePath, "MxGateway:Worker:ExecutablePath is required.", failures); AddIfBlank(options.ExecutablePath, "MxGateway:Worker:ExecutablePath is required.", builder);
AddIfInvalidPath( AddIfInvalidPath(
options.ExecutablePath, options.ExecutablePath,
"MxGateway:Worker:ExecutablePath must be a valid filesystem path.", "MxGateway:Worker:ExecutablePath must be a valid filesystem path.",
failures); builder);
if (!string.IsNullOrWhiteSpace(options.ExecutablePath) if (!string.IsNullOrWhiteSpace(options.ExecutablePath)
&& !string.Equals(Path.GetExtension(options.ExecutablePath), ".exe", StringComparison.OrdinalIgnoreCase)) && !string.Equals(Path.GetExtension(options.ExecutablePath), ".exe", StringComparison.OrdinalIgnoreCase))
{ {
failures.Add("MxGateway:Worker:ExecutablePath must point to a .exe file."); builder.Add("MxGateway:Worker:ExecutablePath must point to a .exe file.");
} }
if (!string.IsNullOrWhiteSpace(options.WorkingDirectory)) if (!string.IsNullOrWhiteSpace(options.WorkingDirectory))
@@ -114,94 +107,94 @@ public sealed class GatewayOptionsValidator : IValidateOptions<GatewayOptions>
AddIfInvalidPath( AddIfInvalidPath(
options.WorkingDirectory, options.WorkingDirectory,
"MxGateway:Worker:WorkingDirectory must be a valid filesystem path.", "MxGateway:Worker:WorkingDirectory must be a valid filesystem path.",
failures); builder);
} }
if (!Enum.IsDefined(options.RequiredArchitecture)) if (!Enum.IsDefined(options.RequiredArchitecture))
{ {
failures.Add("MxGateway:Worker:RequiredArchitecture must be a supported worker architecture."); builder.Add("MxGateway:Worker:RequiredArchitecture must be a supported worker architecture.");
} }
AddIfNotPositive( AddIfNotPositive(
options.StartupTimeoutSeconds, options.StartupTimeoutSeconds,
"MxGateway:Worker:StartupTimeoutSeconds must be greater than zero.", "MxGateway:Worker:StartupTimeoutSeconds must be greater than zero.",
failures); builder);
AddIfNotPositive( AddIfNotPositive(
options.StartupProbeRetryAttempts, options.StartupProbeRetryAttempts,
"MxGateway:Worker:StartupProbeRetryAttempts must be greater than zero.", "MxGateway:Worker:StartupProbeRetryAttempts must be greater than zero.",
failures); builder);
AddIfNotPositive( AddIfNotPositive(
options.StartupProbeRetryDelayMilliseconds, options.StartupProbeRetryDelayMilliseconds,
"MxGateway:Worker:StartupProbeRetryDelayMilliseconds must be greater than zero.", "MxGateway:Worker:StartupProbeRetryDelayMilliseconds must be greater than zero.",
failures); builder);
AddIfNotPositive( AddIfNotPositive(
options.PipeConnectAttemptTimeoutMilliseconds, options.PipeConnectAttemptTimeoutMilliseconds,
"MxGateway:Worker:PipeConnectAttemptTimeoutMilliseconds must be greater than zero.", "MxGateway:Worker:PipeConnectAttemptTimeoutMilliseconds must be greater than zero.",
failures); builder);
AddIfNotPositive( AddIfNotPositive(
options.ShutdownTimeoutSeconds, options.ShutdownTimeoutSeconds,
"MxGateway:Worker:ShutdownTimeoutSeconds must be greater than zero.", "MxGateway:Worker:ShutdownTimeoutSeconds must be greater than zero.",
failures); builder);
AddIfNotPositive( AddIfNotPositive(
options.HeartbeatIntervalSeconds, options.HeartbeatIntervalSeconds,
"MxGateway:Worker:HeartbeatIntervalSeconds must be greater than zero.", "MxGateway:Worker:HeartbeatIntervalSeconds must be greater than zero.",
failures); builder);
AddIfNotPositive( AddIfNotPositive(
options.HeartbeatGraceSeconds, options.HeartbeatGraceSeconds,
"MxGateway:Worker:HeartbeatGraceSeconds must be greater than zero.", "MxGateway:Worker:HeartbeatGraceSeconds must be greater than zero.",
failures); builder);
if (options.HeartbeatGraceSeconds < options.HeartbeatIntervalSeconds) if (options.HeartbeatGraceSeconds < options.HeartbeatIntervalSeconds)
{ {
failures.Add( builder.Add(
"MxGateway:Worker:HeartbeatGraceSeconds must be greater than or equal to HeartbeatIntervalSeconds."); "MxGateway:Worker:HeartbeatGraceSeconds must be greater than or equal to HeartbeatIntervalSeconds.");
} }
if (options.MaxMessageBytes is < MinimumMaxMessageBytes or > MaximumMaxMessageBytes) if (options.MaxMessageBytes is < MinimumMaxMessageBytes or > MaximumMaxMessageBytes)
{ {
failures.Add( builder.Add(
$"MxGateway:Worker:MaxMessageBytes must be between {MinimumMaxMessageBytes} and {MaximumMaxMessageBytes}."); $"MxGateway:Worker:MaxMessageBytes must be between {MinimumMaxMessageBytes} and {MaximumMaxMessageBytes}.");
} }
} }
private static void ValidateSessions(SessionOptions options, List<string> failures) private static void ValidateSessions(SessionOptions options, ValidationBuilder builder)
{ {
AddIfNotPositive( AddIfNotPositive(
options.DefaultCommandTimeoutSeconds, options.DefaultCommandTimeoutSeconds,
"MxGateway:Sessions:DefaultCommandTimeoutSeconds must be greater than zero.", "MxGateway:Sessions:DefaultCommandTimeoutSeconds must be greater than zero.",
failures); builder);
AddIfNotPositive(options.MaxSessions, "MxGateway:Sessions:MaxSessions must be greater than zero.", failures); AddIfNotPositive(options.MaxSessions, "MxGateway:Sessions:MaxSessions must be greater than zero.", builder);
AddIfNotPositive( AddIfNotPositive(
options.MaxPendingCommandsPerSession, options.MaxPendingCommandsPerSession,
"MxGateway:Sessions:MaxPendingCommandsPerSession must be greater than zero.", "MxGateway:Sessions:MaxPendingCommandsPerSession must be greater than zero.",
failures); builder);
AddIfNotPositive( AddIfNotPositive(
options.DefaultLeaseSeconds, options.DefaultLeaseSeconds,
"MxGateway:Sessions:DefaultLeaseSeconds must be greater than zero.", "MxGateway:Sessions:DefaultLeaseSeconds must be greater than zero.",
failures); builder);
AddIfNotPositive( AddIfNotPositive(
options.LeaseSweepIntervalSeconds, options.LeaseSweepIntervalSeconds,
"MxGateway:Sessions:LeaseSweepIntervalSeconds must be greater than zero.", "MxGateway:Sessions:LeaseSweepIntervalSeconds must be greater than zero.",
failures); builder);
if (options.AllowMultipleEventSubscribers) if (options.AllowMultipleEventSubscribers)
{ {
failures.Add( builder.Add(
"MxGateway:Sessions:AllowMultipleEventSubscribers is not supported until event fan-out is implemented."); "MxGateway:Sessions:AllowMultipleEventSubscribers is not supported until event fan-out is implemented.");
} }
} }
private static void ValidateEvents(EventOptions options, List<string> failures) private static void ValidateEvents(EventOptions options, ValidationBuilder builder)
{ {
AddIfNotPositive(options.QueueCapacity, "MxGateway:Events:QueueCapacity must be greater than zero.", failures); AddIfNotPositive(options.QueueCapacity, "MxGateway:Events:QueueCapacity must be greater than zero.", builder);
if (!Enum.IsDefined(options.BackpressurePolicy)) if (!Enum.IsDefined(options.BackpressurePolicy))
{ {
failures.Add("MxGateway:Events:BackpressurePolicy must be a supported backpressure policy."); builder.Add("MxGateway:Events:BackpressurePolicy must be a supported backpressure policy.");
} }
} }
private static void ValidateDashboard(DashboardOptions options, List<string> failures) private static void ValidateDashboard(DashboardOptions options, ValidationBuilder builder)
{ {
// GroupToRole shape is validated even when the dashboard is disabled so // GroupToRole shape is validated even when the dashboard is disabled so
// misconfiguration surfaces at startup; emptiness is allowed, with the // misconfiguration surfaces at startup; emptiness is allowed, with the
@@ -212,13 +205,13 @@ public sealed class GatewayOptionsValidator : IValidateOptions<GatewayOptions>
{ {
if (string.IsNullOrWhiteSpace(entry.Key)) if (string.IsNullOrWhiteSpace(entry.Key))
{ {
failures.Add("MxGateway:Dashboard:GroupToRole keys (LDAP group names) must be non-blank."); builder.Add("MxGateway:Dashboard:GroupToRole keys (LDAP group names) must be non-blank.");
} }
if (!string.Equals(entry.Value, Dashboard.DashboardRoles.Admin, StringComparison.Ordinal) if (!string.Equals(entry.Value, Dashboard.DashboardRoles.Admin, StringComparison.Ordinal)
&& !string.Equals(entry.Value, Dashboard.DashboardRoles.Viewer, StringComparison.Ordinal)) && !string.Equals(entry.Value, Dashboard.DashboardRoles.Viewer, StringComparison.Ordinal))
{ {
failures.Add( builder.Add(
$"MxGateway:Dashboard:GroupToRole['{entry.Key}'] must be '{Dashboard.DashboardRoles.Admin}' or '{Dashboard.DashboardRoles.Viewer}'."); $"MxGateway:Dashboard:GroupToRole['{entry.Key}'] must be '{Dashboard.DashboardRoles.Admin}' or '{Dashboard.DashboardRoles.Viewer}'.");
} }
} }
@@ -226,18 +219,18 @@ public sealed class GatewayOptionsValidator : IValidateOptions<GatewayOptions>
AddIfNotPositive( AddIfNotPositive(
options.SnapshotIntervalMilliseconds, options.SnapshotIntervalMilliseconds,
"MxGateway:Dashboard:SnapshotIntervalMilliseconds must be greater than zero.", "MxGateway:Dashboard:SnapshotIntervalMilliseconds must be greater than zero.",
failures); builder);
AddIfNegative( AddIfNegative(
options.RecentFaultLimit, options.RecentFaultLimit,
"MxGateway:Dashboard:RecentFaultLimit must be greater than or equal to zero.", "MxGateway:Dashboard:RecentFaultLimit must be greater than or equal to zero.",
failures); builder);
AddIfNegative( AddIfNegative(
options.RecentSessionLimit, options.RecentSessionLimit,
"MxGateway:Dashboard:RecentSessionLimit must be greater than or equal to zero.", "MxGateway:Dashboard:RecentSessionLimit must be greater than or equal to zero.",
failures); builder);
} }
private static void ValidateAlarms(AlarmsOptions options, List<string> failures) private static void ValidateAlarms(AlarmsOptions options, ValidationBuilder builder)
{ {
if (!options.Enabled) if (!options.Enabled)
{ {
@@ -251,14 +244,14 @@ public sealed class GatewayOptionsValidator : IValidateOptions<GatewayOptions>
if (string.IsNullOrWhiteSpace(options.SubscriptionExpression) if (string.IsNullOrWhiteSpace(options.SubscriptionExpression)
&& string.IsNullOrWhiteSpace(options.DefaultArea)) && string.IsNullOrWhiteSpace(options.DefaultArea))
{ {
failures.Add( builder.Add(
"MxGateway:Alarms requires either a non-blank SubscriptionExpression or a non-blank DefaultArea when Enabled is true."); "MxGateway:Alarms requires either a non-blank SubscriptionExpression or a non-blank DefaultArea when Enabled is true.");
} }
if (!string.IsNullOrWhiteSpace(options.SubscriptionExpression) if (!string.IsNullOrWhiteSpace(options.SubscriptionExpression)
&& !options.SubscriptionExpression.StartsWith(@"\\", StringComparison.Ordinal)) && !options.SubscriptionExpression.StartsWith(@"\\", StringComparison.Ordinal))
{ {
failures.Add( builder.Add(
@"MxGateway:Alarms:SubscriptionExpression must start with '\\' (canonical \\<host>\Galaxy!<area> shape)."); @"MxGateway:Alarms:SubscriptionExpression must start with '\\' (canonical \\<host>\Galaxy!<area> shape).");
} }
} }
@@ -266,11 +259,11 @@ public sealed class GatewayOptionsValidator : IValidateOptions<GatewayOptions>
private const int MinimumCertValidityYears = 1; private const int MinimumCertValidityYears = 1;
private const int MaximumCertValidityYears = 100; private const int MaximumCertValidityYears = 100;
private static void ValidateTls(TlsOptions options, List<string> failures) private static void ValidateTls(TlsOptions options, ValidationBuilder builder)
{ {
if (options.ValidityYears is < MinimumCertValidityYears or > MaximumCertValidityYears) if (options.ValidityYears is < MinimumCertValidityYears or > MaximumCertValidityYears)
{ {
failures.Add( builder.Add(
$"MxGateway:Tls:ValidityYears must be between {MinimumCertValidityYears} and {MaximumCertValidityYears}."); $"MxGateway:Tls:ValidityYears must be between {MinimumCertValidityYears} and {MaximumCertValidityYears}.");
} }
@@ -278,61 +271,52 @@ public sealed class GatewayOptionsValidator : IValidateOptions<GatewayOptions>
AddIfBlank( AddIfBlank(
options.SelfSignedCertPath, options.SelfSignedCertPath,
"MxGateway:Tls:SelfSignedCertPath must not be blank.", "MxGateway:Tls:SelfSignedCertPath must not be blank.",
failures); builder);
AddIfInvalidPath( AddIfInvalidPath(
options.SelfSignedCertPath, options.SelfSignedCertPath,
"MxGateway:Tls:SelfSignedCertPath must be a valid filesystem path.", "MxGateway:Tls:SelfSignedCertPath must be a valid filesystem path.",
failures); builder);
foreach (string dns in options.AdditionalDnsNames) foreach (string dns in options.AdditionalDnsNames)
{ {
if (string.IsNullOrWhiteSpace(dns)) if (string.IsNullOrWhiteSpace(dns))
{ {
failures.Add("MxGateway:Tls:AdditionalDnsNames entries must be non-blank."); builder.Add("MxGateway:Tls:AdditionalDnsNames entries must be non-blank.");
} }
} }
} }
private static void ValidateProtocol(ProtocolOptions options, List<string> failures) private static void ValidateProtocol(ProtocolOptions options, ValidationBuilder builder)
{ {
if (options.WorkerProtocolVersion != GatewayContractInfo.WorkerProtocolVersion) if (options.WorkerProtocolVersion != GatewayContractInfo.WorkerProtocolVersion)
{ {
failures.Add( builder.Add(
$"MxGateway:Protocol:WorkerProtocolVersion must be {GatewayContractInfo.WorkerProtocolVersion}."); $"MxGateway:Protocol:WorkerProtocolVersion must be {GatewayContractInfo.WorkerProtocolVersion}.");
} }
if (options.MaxGrpcMessageBytes is < MinimumMaxMessageBytes or > MaximumMaxMessageBytes) if (options.MaxGrpcMessageBytes is < MinimumMaxMessageBytes or > MaximumMaxMessageBytes)
{ {
failures.Add( builder.Add(
$"MxGateway:Protocol:MaxGrpcMessageBytes must be between {MinimumMaxMessageBytes} and {MaximumMaxMessageBytes}."); $"MxGateway:Protocol:MaxGrpcMessageBytes must be between {MinimumMaxMessageBytes} and {MaximumMaxMessageBytes}.");
} }
} }
private static void AddIfBlank(string? value, string message, List<string> failures) private static void AddIfBlank(string? value, string message, ValidationBuilder builder)
{ {
if (string.IsNullOrWhiteSpace(value)) builder.RequireThat(!string.IsNullOrWhiteSpace(value), message);
{
failures.Add(message);
}
} }
private static void AddIfNotPositive(int value, string message, List<string> failures) private static void AddIfNotPositive(int value, string message, ValidationBuilder builder)
{ {
if (value <= 0) builder.RequireThat(value > 0, message);
{
failures.Add(message);
}
} }
private static void AddIfNegative(int value, string message, List<string> failures) private static void AddIfNegative(int value, string message, ValidationBuilder builder)
{ {
if (value < 0) builder.RequireThat(value >= 0, message);
{
failures.Add(message);
}
} }
private static void AddIfInvalidPath(string? value, string message, List<string> failures) private static void AddIfInvalidPath(string? value, string message, ValidationBuilder builder)
{ {
if (string.IsNullOrWhiteSpace(value)) if (string.IsNullOrWhiteSpace(value))
{ {
@@ -345,15 +329,15 @@ public sealed class GatewayOptionsValidator : IValidateOptions<GatewayOptions>
} }
catch (ArgumentException) catch (ArgumentException)
{ {
failures.Add(message); builder.Add(message);
} }
catch (NotSupportedException) catch (NotSupportedException)
{ {
failures.Add(message); builder.Add(message);
} }
catch (PathTooLongException) catch (PathTooLongException)
{ {
failures.Add(message); builder.Add(message);
} }
} }
} }
@@ -65,7 +65,7 @@ public static class GatewayApplication
builder.AddZbSerilog(o => o.ServiceName = "mxgateway"); builder.AddZbSerilog(o => o.ServiceName = "mxgateway");
builder.Services.AddGatewayConfiguration(); builder.Services.AddGatewayConfiguration(builder.Configuration);
builder.Services.AddSqliteAuthStore(); builder.Services.AddSqliteAuthStore();
builder.Services.AddGatewayGrpcAuthorization(); builder.Services.AddGatewayGrpcAuthorization();
builder.Services.AddHealthChecks() builder.Services.AddHealthChecks()
@@ -6,6 +6,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.76.0" /> <PackageReference Include="Grpc.AspNetCore" Version="2.76.0" />
<PackageReference Include="ZB.MOM.WW.Configuration" Version="0.1.0" />
<PackageReference Include="ZB.MOM.WW.Health" Version="0.1.0" /> <PackageReference Include="ZB.MOM.WW.Health" Version="0.1.0" />
<PackageReference Include="ZB.MOM.WW.Telemetry" Version="0.1.0" /> <PackageReference Include="ZB.MOM.WW.Telemetry" Version="0.1.0" />
<PackageReference Include="ZB.MOM.WW.Telemetry.Serilog" Version="0.1.0" /> <PackageReference Include="ZB.MOM.WW.Telemetry.Serilog" Version="0.1.0" />
@@ -132,7 +132,7 @@ public sealed class GatewayOptionsTests
ServiceCollection services = new(); ServiceCollection services = new();
services.AddSingleton<IConfiguration>(configuration); services.AddSingleton<IConfiguration>(configuration);
services.AddGatewayConfiguration(); services.AddGatewayConfiguration(configuration);
return services.BuildServiceProvider(validateScopes: true); return services.BuildServiceProvider(validateScopes: true);
} }
@@ -245,7 +245,7 @@ public sealed class ApiKeyAdminCliRunnerTests : IDisposable
ServiceCollection services = new(); ServiceCollection services = new();
services.AddSingleton<IConfiguration>(configuration); services.AddSingleton<IConfiguration>(configuration);
services.AddGatewayConfiguration(); services.AddGatewayConfiguration(configuration);
services.AddSqliteAuthStore(); services.AddSqliteAuthStore();
return services.BuildServiceProvider(validateScopes: true); return services.BuildServiceProvider(validateScopes: true);
@@ -188,7 +188,7 @@ public sealed class SqliteAuthStoreTests : IDisposable
ServiceCollection services = new(); ServiceCollection services = new();
services.AddSingleton<IConfiguration>(configuration); services.AddSingleton<IConfiguration>(configuration);
services.AddGatewayConfiguration(); services.AddGatewayConfiguration(configuration);
services.AddSqliteAuthStore(); services.AddSqliteAuthStore();
return services.BuildServiceProvider(validateScopes: true); return services.BuildServiceProvider(validateScopes: true);