using Example.Data; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Npgsql; var builder = WebApplication.CreateBuilder(args); var configuredProvider = builder.Configuration["Database:Provider"] ?? throw new InvalidOperationException("Database provider configuration 'Database:Provider' was not found."); var connectionString = ResolveConnectionString(builder, configuredProvider); if (builder.Environment.IsDevelopment()) { EnsureProviderMatchesEnvironment(configuredProvider, expectedProvider: "Sqlite", builder.Environment.EnvironmentName); ValidateConnectionString(connectionString, configuredProvider); builder.Services.AddDbContext(options => options.UseSqlite(connectionString)); } else { EnsureProviderMatchesEnvironment(configuredProvider, expectedProvider: "Postgres", builder.Environment.EnvironmentName); ValidateConnectionString(connectionString, configuredProvider); builder.Services.AddDbContext(options => options.UseNpgsql(connectionString)); } builder.Services.AddDatabaseDeveloperPageExceptionFilter(); var identityBuilder = builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true); if (builder.Environment.IsDevelopment()) { identityBuilder.AddEntityFrameworkStores(); } else { identityBuilder.AddEntityFrameworkStores(); } builder.Services.AddControllersWithViews(); var app = builder.Build(); using (var services = app.Services.CreateScope()) { var db = services.ServiceProvider.GetRequiredService(); db.Database.Migrate(); if (app.Environment.IsDevelopment()) { ApplicationDbInitializer.SeedDevelopmentData(db); } } if (app.Environment.IsDevelopment()) { app.UseMigrationsEndPoint(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.MapRazorPages(); app.Run(); static void EnsureProviderMatchesEnvironment(string configuredProvider, string expectedProvider, string environmentName) { if (!string.Equals(configuredProvider, expectedProvider, StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException( $"Environment '{environmentName}' must use the '{expectedProvider}' database provider, but configuration specifies '{configuredProvider}'."); } } static void ValidateConnectionString(string connectionString, string configuredProvider) { if (string.Equals(configuredProvider, "Sqlite", StringComparison.OrdinalIgnoreCase)) { if ((!connectionString.Contains("Data Source=", StringComparison.OrdinalIgnoreCase) && !connectionString.Contains("DataSource=", StringComparison.OrdinalIgnoreCase)) || connectionString.Contains("Host=", StringComparison.OrdinalIgnoreCase) || connectionString.Contains("Server=", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("The development connection string does not look like a valid SQLite connection string."); } return; } if (string.Equals(configuredProvider, "Postgres", StringComparison.OrdinalIgnoreCase)) { if (!connectionString.Contains("Host=", StringComparison.OrdinalIgnoreCase) || connectionString.Contains("Server=", StringComparison.OrdinalIgnoreCase) || connectionString.Contains("DataSource=", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("The production connection string does not look like a valid PostgreSQL connection string."); } return; } throw new InvalidOperationException($"Unsupported database provider '{configuredProvider}'."); } static string ResolveConnectionString(WebApplicationBuilder builder, string configuredProvider) { var configuredConnectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' was not found."); if (builder.Environment.IsDevelopment() || !string.Equals(configuredProvider, "Postgres", StringComparison.OrdinalIgnoreCase)) { return configuredConnectionString; } var passwordFile = builder.Configuration["POSTGRES_PASSWORD_FILE"]; if (string.IsNullOrWhiteSpace(passwordFile) || !File.Exists(passwordFile)) { return configuredConnectionString; } var password = File.ReadAllText(passwordFile).Trim(); if (string.IsNullOrWhiteSpace(password)) { throw new InvalidOperationException($"The PostgreSQL password file '{passwordFile}' is empty."); } var connectionStringBuilder = new NpgsqlConnectionStringBuilder(configuredConnectionString) { Host = builder.Configuration["POSTGRES_HOST"] ?? "db", Database = builder.Configuration["POSTGRES_DB"] ?? "db", Username = builder.Configuration["POSTGRES_USER"] ?? "user", Password = password }; if (int.TryParse(builder.Configuration["POSTGRES_PORT"], out var port)) { connectionStringBuilder.Port = port; } return connectionStringBuilder.ConnectionString; }