using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; namespace ScadaLink.ConfigurationDatabase; /// /// Factory for creating DbContext instances at design time (used by dotnet ef tooling). /// Resolves the connection string from the Host's appsettings files, or — for environments /// where those files are not present — from the /// SCADALINK_DESIGNTIME_CONNECTIONSTRING environment variable. /// /// /// There is deliberately no hardcoded fallback connection string. A credential literal in /// source is committed to version control, encourages copy-paste of sa / /// TrustServerCertificate=True into real environments, and can silently point /// dotnet ef tooling at an unintended database. If no connection string can be /// resolved, this factory fails loudly with an actionable message. /// public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory { private const string EnvironmentVariableName = "SCADALINK_DESIGNTIME_CONNECTIONSTRING"; private const string ConfigurationKey = "ScadaLink:Database:ConfigurationDb"; public ScadaLinkDbContext CreateDbContext(string[] args) { var configurationBuilder = new ConfigurationBuilder(); // The Host's appsettings files are an optional source — only wire them up when the // Host directory actually exists, otherwise SetBasePath throws DirectoryNotFoundException // (e.g. when this factory is exercised from a test runner with no sibling Host folder). var hostDirectory = Path.Combine(Directory.GetCurrentDirectory(), "..", "ScadaLink.Host"); if (Directory.Exists(hostDirectory)) { configurationBuilder .SetBasePath(hostDirectory) .AddJsonFile("appsettings.json", optional: true) .AddJsonFile("appsettings.Central.json", optional: true); } var configuration = configurationBuilder.Build(); var connectionString = configuration[ConfigurationKey] ?? Environment.GetEnvironmentVariable(EnvironmentVariableName); if (string.IsNullOrWhiteSpace(connectionString)) { throw new InvalidOperationException( "No design-time database connection string was found. Set the configuration " + $"key '{ConfigurationKey}' in the Host's appsettings file, or set the " + $"'{EnvironmentVariableName}' environment variable, before running dotnet ef tooling."); } var optionsBuilder = new DbContextOptionsBuilder(); optionsBuilder.UseSqlServer(connectionString); return new ScadaLinkDbContext(optionsBuilder.Options); } }