mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-14 17:54:42 +00:00
Update database handling code (#247)
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Database.Connection;
|
||||
|
||||
public static class ConfigurationHelpers
|
||||
{
|
||||
public static string GetKeyOrThrow(IConfiguration configuration, string key) =>
|
||||
configuration[key]
|
||||
?? throw new InvalidOperationException($"The {key} environment variable is not set.");
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Database.Connection</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="2.1.79" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.0.2" />
|
||||
<PackageReference Include="Microsoft.SqlServer.Types" Version="160.1000.6" />
|
||||
<PackageReference
|
||||
Include="Microsoft.Extensions.Configuration.Abstractions"
|
||||
Version="9.0.0"
|
||||
/>
|
||||
<PackageReference
|
||||
Include="Microsoft.Extensions.DependencyInjection.Abstractions"
|
||||
Version="10.0.0"
|
||||
/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.Data.Common;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Database.Connection;
|
||||
|
||||
/// <summary>
|
||||
/// Default <see cref="DefaultSqlConnectionFactory" /> implementation that creates SQL Server connections,
|
||||
/// resolving the connection string from environment variables or application configuration.
|
||||
/// </summary>
|
||||
public class DefaultSqlConnectionFactory(IConfiguration configuration) : ISqlConnectionFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// The resolved SQL Server connection string, preferring (in order): the <c>DB_CONNECTION_STRING</c>
|
||||
/// configuration value, and a connection string built from individual <c>DB_*</c> configuration values.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">Thrown when no connection string can be resolved from any source.</exception>
|
||||
public string ConnectionString
|
||||
{
|
||||
get
|
||||
{
|
||||
string? fullConnectionString = configuration["DB_CONNECTION_STRING"];
|
||||
if (!string.IsNullOrEmpty(fullConnectionString))
|
||||
return fullConnectionString;
|
||||
|
||||
// Try to build from individual configuration values (preferred method for Docker)
|
||||
if (
|
||||
SqlConnectionStringHelper.TryGetStandardDbConnectionString(
|
||||
configuration,
|
||||
out var connectionString
|
||||
)
|
||||
)
|
||||
return connectionString;
|
||||
|
||||
throw new InvalidOperationException(
|
||||
"Database connection string not configured. Set DB_CONNECTION_STRING or DB_SERVER, DB_NAME, DB_USER, DB_PASSWORD env vars."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public SqlConnection CreateConnection()
|
||||
{
|
||||
return new SqlConnection(ConnectionString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Database.Connection.DependencyInjection;
|
||||
|
||||
/// <summary>Extension methods for registering database connection services with dependency injection.</summary>
|
||||
public static class DatabaseConnectionServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>Registers <see cref="DefaultSqlConnectionFactory" /> as a singleton <see cref="ISqlConnectionFactory" />.</summary>
|
||||
/// <returns>The same <paramref name="services" /> instance, for chaining.</returns>
|
||||
public static IServiceCollection AddDatabaseConnection(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ISqlConnectionFactory, DefaultSqlConnectionFactory>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Microsoft.Data.SqlClient;
|
||||
|
||||
namespace Database.Connection;
|
||||
|
||||
public interface ISqlConnectionFactory
|
||||
{
|
||||
public string ConnectionString { get; }
|
||||
|
||||
public SqlConnection CreateConnection();
|
||||
}
|
||||
21
web/backend/Database/Database.Connection/Repository.cs
Normal file
21
web/backend/Database/Database.Connection/Repository.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Data.Common;
|
||||
|
||||
namespace Database.Connection;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for Dapper-based repositories, providing shared connection creation for derived
|
||||
/// repository implementations.
|
||||
/// </summary>
|
||||
public abstract class DapperRepository(ISqlConnectionFactory connectionFactory)
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates and opens a new database connection using the configured <see cref="ISqlConnectionFactory" />.
|
||||
/// </summary>
|
||||
/// <exception cref="DbException">Thrown when the connection cannot be opened.</exception>
|
||||
protected async Task<DbConnection> CreateConnection()
|
||||
{
|
||||
DbConnection connection = connectionFactory.CreateConnection();
|
||||
await connection.OpenAsync();
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Database.Connection;
|
||||
|
||||
/// <summary>
|
||||
/// Helper for building SQL Server connection strings from configuration
|
||||
/// (backed by the <c>DB_*</c> environment variables).
|
||||
/// </summary>
|
||||
public static class SqlConnectionStringHelper
|
||||
{
|
||||
private static SqlConnectionStringBuilder MakeConfiguredConnectionBuilder(
|
||||
IConfiguration configuration
|
||||
) =>
|
||||
new()
|
||||
{
|
||||
DataSource = ConfigurationHelpers.GetKeyOrThrow(configuration, "DB_SERVER"),
|
||||
UserID = ConfigurationHelpers.GetKeyOrThrow(configuration, "DB_USER"),
|
||||
Password = ConfigurationHelpers.GetKeyOrThrow(configuration, "DB_PASSWORD"),
|
||||
TrustServerCertificate = ResolveTrustServerCertificate(configuration),
|
||||
Encrypt = true,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Builds a SQL Server connection string from configuration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Returns <c>false</c> if DB_SERVER, DB_NAME, DB_USER, or DB_PASSWORD is unset.
|
||||
/// </remarks>
|
||||
/// <param name="configuration">The configuration to read the <c>DB_*</c> values from.</param>
|
||||
/// <param name="connectionString">The resolved connection string, if successful.</param>
|
||||
public static bool TryGetStandardDbConnectionString(
|
||||
IConfiguration configuration,
|
||||
out string connectionString
|
||||
)
|
||||
{
|
||||
connectionString = string.Empty;
|
||||
try
|
||||
{
|
||||
SqlConnectionStringBuilder builder = MakeConfiguredConnectionBuilder(configuration);
|
||||
builder.InitialCatalog = ConfigurationHelpers.GetKeyOrThrow(configuration, "DB_NAME");
|
||||
connectionString = builder.ConnectionString;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetMasterConnectionString(
|
||||
IConfiguration configuration,
|
||||
out string connectionString
|
||||
)
|
||||
{
|
||||
connectionString = string.Empty;
|
||||
try
|
||||
{
|
||||
var builder = MakeConfiguredConnectionBuilder(configuration);
|
||||
builder.InitialCatalog = "master";
|
||||
|
||||
connectionString = builder.ConnectionString;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetDatabaseNameFromConnectionString(
|
||||
string connectionString,
|
||||
out string databaseName
|
||||
)
|
||||
{
|
||||
databaseName = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
var builder = new SqlConnectionStringBuilder(connectionString);
|
||||
databaseName = builder.InitialCatalog;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the <c>DB_TRUST_SERVER_CERTIFICATE</c> configuration value, defaulting to
|
||||
/// <c>true</c> when it is unset or not a valid boolean.
|
||||
/// </summary>
|
||||
private static bool ResolveTrustServerCertificate(IConfiguration configuration)
|
||||
{
|
||||
return !bool.TryParse(
|
||||
configuration["DB_TRUST_SERVER_CERTIFICATE"],
|
||||
out bool trustServerCertificate
|
||||
) || trustServerCertificate;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user