using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using ZB.MOM.WW.OtOpcUa.Configuration.Services; namespace ZB.MOM.WW.OtOpcUa.Configuration; public static class ServiceCollectionExtensions { public const string ConnectionStringName = "ConfigDb"; /// /// Registers for /// using the connection string named ConfigDb from . /// /// The service collection to configure. /// The application configuration. /// The service collection for chaining. public static IServiceCollection AddOtOpcUaConfigDb(this IServiceCollection services, IConfiguration configuration) { var connectionString = configuration.GetConnectionString(ConnectionStringName) ?? throw new InvalidOperationException( $"Connection string '{ConnectionStringName}' is required. Add it to appsettings.json or the OTOPCUA_CONFIG_CONNECTION env var."); services.AddDbContextFactory(opt => opt.UseSqlServer(connectionString)); // AddDbContextFactory registers only the IDbContextFactory<> — it does NOT also register // a scoped OtOpcUaConfigDbContext. Config services that take the context directly (e.g. // LdapGroupRoleMappingService) need a scoped instance, so bridge one off the factory. services.AddScoped(sp => sp.GetRequiredService>().CreateDbContext()); // Config-DB services consumed by both the AdminUI (RoleGrants page) and the auth/login // host (AuthEndpoints.LoginAsync). Scoped to match the request/render scope of both callers. services.AddScoped(); return services; } }