refactor: rename ScadaLink → ZB.MOM.WW.ScadaBridge (code + projects + namespaces)
Solution + 23 src projects + 26 test projects renamed; folders, csproj, namespaces, and ScadaLinkDbContext/ScadaBridgeDbContext class updated. ActorSystem "scadalink" → "scadabridge", Akka seed-node URLs migrated. SQL roles/logins, LDAP domains, CLI command name, and CLI config dir (~/.scadalink → ~/.scadabridge) also renamed. Build green; 5 Host.Tests fail awaiting SQL login rename in next commit. Pre-existing StaleTagMonitor timing flakes unchanged. Rename script committed at tools/rename-to-scadabridge.sh.
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Transport;
|
||||
using ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Maintenance;
|
||||
using ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Repositories;
|
||||
using ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Services;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers the ScadaBridgeDbContext with the provided SQL Server connection string.
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection to register into.</param>
|
||||
/// <param name="connectionString">SQL Server connection string for the central configuration database.</param>
|
||||
public static IServiceCollection AddConfigurationDatabase(this IServiceCollection services, string connectionString)
|
||||
{
|
||||
// The DbContext is constructed via the (options, IDataProtectionProvider) overload so
|
||||
// secret-bearing configuration columns are encrypted at rest. AddDataProtection below
|
||||
// registers IDataProtectionProvider as a singleton; resolving it here does not recurse
|
||||
// because key-ring loading is lazy (first Protect/Unprotect), not triggered by
|
||||
// CreateProtector during model building.
|
||||
services.AddDbContext<ScadaBridgeDbContext>((serviceProvider, options) =>
|
||||
{
|
||||
options.UseSqlServer(connectionString)
|
||||
.ConfigureWarnings(w => w.Ignore(
|
||||
Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning));
|
||||
});
|
||||
|
||||
// AddDbContext registers ScadaBridgeDbContext via EF's activator, which only injects
|
||||
// DbContextOptions. Override that registration (last registration wins for resolution)
|
||||
// with a factory that also supplies the IDataProtectionProvider, so the encrypting
|
||||
// value converter for secret columns is always wired up at runtime.
|
||||
services.AddScoped(serviceProvider =>
|
||||
{
|
||||
var options = serviceProvider.GetRequiredService<DbContextOptions<ScadaBridgeDbContext>>();
|
||||
var protectionProvider = serviceProvider.GetRequiredService<IDataProtectionProvider>();
|
||||
return new ScadaBridgeDbContext(options, protectionProvider);
|
||||
});
|
||||
|
||||
services.AddScoped<ISecurityRepository, SecurityRepository>();
|
||||
services.AddScoped<ICentralUiRepository, CentralUiRepository>();
|
||||
services.AddScoped<ITemplateEngineRepository, TemplateEngineRepository>();
|
||||
services.AddScoped<IDeploymentManagerRepository, DeploymentManagerRepository>();
|
||||
services.AddScoped<ISiteRepository, SiteRepository>();
|
||||
services.AddScoped<IExternalSystemRepository, ExternalSystemRepository>();
|
||||
services.AddScoped<INotificationRepository, NotificationRepository>();
|
||||
services.AddScoped<INotificationOutboxRepository, NotificationOutboxRepository>();
|
||||
services.AddScoped<IAuditLogRepository, AuditLogRepository>();
|
||||
services.AddScoped<ISiteCallAuditRepository, SiteCallAuditRepository>();
|
||||
// CD-016: factory registration wires a lazy accessor for IApiKeyHasher so
|
||||
// the production peppered hasher is used (via DI) when GetApiKeyByValueAsync
|
||||
// is actually called, but composition roots that never call it (and may
|
||||
// not register IApiKeyHasher at all) still bring up the repository.
|
||||
services.AddScoped<IInboundApiRepository>(sp => new InboundApiRepository(
|
||||
sp.GetRequiredService<ScadaBridgeDbContext>(),
|
||||
hasherAccessor: () => sp.GetService<Commons.Types.InboundApi.IApiKeyHasher>()
|
||||
?? Commons.Types.InboundApi.ApiKeyHasher.Default,
|
||||
logger: sp.GetService<ILogger<InboundApiRepository>>()));
|
||||
services.AddScoped<IAuditCorrelationContext, AuditCorrelationContext>();
|
||||
services.AddScoped<IAuditService, AuditService>();
|
||||
services.AddScoped<IInstanceLocator, InstanceLocator>();
|
||||
|
||||
// #23 M6 Bundle D: IPartitionMaintenance drives the daily roll-forward
|
||||
// of pf_AuditLog_Month from the central AuditLogPartitionMaintenanceService
|
||||
// hosted service. Scoped because the implementation reuses the per-scope
|
||||
// ScadaBridgeDbContext for raw-SQL execution; the hosted service opens a
|
||||
// fresh scope on each tick (mirrors AuditLogPurgeActor / AuditLogIngestActor).
|
||||
services.AddScoped<IPartitionMaintenance, AuditLogPartitionMaintenance>();
|
||||
|
||||
services.AddDataProtection()
|
||||
.PersistKeysToDbContext<ScadaBridgeDbContext>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obsolete parameterless overload. This previously registered nothing, which meant a
|
||||
/// central node wired up with it failed late and opaquely — the first repository
|
||||
/// resolution threw a DI exception far from the actual misconfiguration. Use
|
||||
/// <see cref="AddConfigurationDatabase(IServiceCollection, string)"/> and pass the
|
||||
/// configured connection string.
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection (unused; this overload always throws).</param>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Always thrown. The connection string is required; there is no valid no-op registration.
|
||||
/// </exception>
|
||||
[Obsolete(
|
||||
"AddConfigurationDatabase() with no connection string registers nothing and is not a " +
|
||||
"valid configuration. Call AddConfigurationDatabase(connectionString) instead.",
|
||||
error: true)]
|
||||
public static IServiceCollection AddConfigurationDatabase(this IServiceCollection services)
|
||||
{
|
||||
// Defence-in-depth: even if a caller suppresses the compile-time obsolete error,
|
||||
// fail fast at wire-up time rather than silently registering nothing and surfacing
|
||||
// an opaque DI resolution failure much later.
|
||||
throw new InvalidOperationException(
|
||||
"AddConfigurationDatabase() requires a connection string. Call " +
|
||||
"AddConfigurationDatabase(connectionString) with the configured " +
|
||||
"'ScadaBridge:Database:ConfigurationDb' value.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user