Validating Connection Strings on .NET Startup
Initial Host Configuration
using System.Data.Common;
using Microsoft.Data.SqlClient;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using WorkerServiceDatabase;
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services
// validate connection strings
.ValidateConnectionStrings()
.ValidateOnStart();
services.AddHostedService<Worker>();
})
.Build();
host.Run();
public static class ConnectionStringExtensions
{
public static OptionsBuilder<ConnectionStrings>
ValidateConnectionStrings(this IServiceCollection services)
{
return services
.AddOptions<ConnectionStrings>()
.BindConfiguration("ConnectionStrings")
.Validate(c => c.Validate(), "Could not connect to 1 or more databases.");
}
}
public class ConnectionStrings
: Dictionary<string,string>
{
public ConnectionStrings()
{
// these are the key names
DbProviderFactories.RegisterFactory("Sqlite", SqliteFactory.Instance);
DbProviderFactories.RegisterFactory("SqlServer", SqlClientFactory.Instance);
}
public bool Validate()
{
// can't inject logger :(
var logger = LoggerFactory
.Create(cfg => cfg.AddConsole().AddDebug())
.CreateLogger("ConnectionStrings");
List<Exception> errors = new();
foreach (var (key, connectionString) in this)
{
try
{
var factory = DbProviderFactories.GetFactory(key);
using var connection = factory.CreateConnection();
if (connection is null) {
throw new Exception($"\"{key}\" did not have a valid database provider registered");
}
connection.ConnectionString = connectionString;
connection.Open();
}
catch (Exception e)
{
var message = $"Could not connect to \"{key}\".";
logger.LogError(message);
errors.Add(new Exception(message, e));
}
}
return errors.IsNullOrEmpty();
}
}
ConnectionString Configuration
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
"Sqlite": "Data Source=database.db",
"SqlServer": "Data Source=localhost,11433;Initial Catalog=DBName;User Id=sa;Password=password;Encrypt=false"
}
}