Skip to content

Commit f0e5e34

Browse files
authored
feat(db): implement options pattern for database connection strings chapter 2
1 parent 035750b commit f0e5e34

12 files changed

Lines changed: 92 additions & 21 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace EvolutionaryArchitecture.Fitnet.Contracts.Infrastructure.Database;
2+
3+
using System.ComponentModel.DataAnnotations;
4+
5+
internal sealed class ContractsPersistenceOptions
6+
{
7+
public const string SectionName = "Modules:Contracts:ConnectionStrings";
8+
9+
[Required]
10+
public string Primary { get; init; } = string.Empty;
11+
}

Chapter-2-modules-separation/Src/Contracts/Fitnet.Contracts.Infrastructure/Database/DatabaseModule.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,23 @@ namespace EvolutionaryArchitecture.Fitnet.Contracts.Infrastructure.Database;
44
using Microsoft.EntityFrameworkCore;
55
using Microsoft.Extensions.Configuration;
66
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.Options;
78
using Repositories;
89

910
internal static class DatabaseModule
1011
{
11-
private const string ConnectionStringConfigurationSection = "Modules:Contracts:ConnectionStrings:Primary";
12-
1312
internal static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration)
1413
{
15-
var connectionString = configuration.GetSection(ConnectionStringConfigurationSection).Value;
16-
services.AddDbContext<ContractsPersistence>(options => options.UseNpgsql(connectionString));
14+
services.Configure<ContractsPersistenceOptions>(configuration.GetSection(ContractsPersistenceOptions.SectionName));
15+
services.AddOptionsWithValidateOnStart<ContractsPersistenceOptions>();
16+
17+
services.AddDbContext<ContractsPersistence>((serviceProvider, options) =>
18+
{
19+
var persistenceOptions = serviceProvider.GetRequiredService<IOptions<ContractsPersistenceOptions>>();
20+
var connectionString = persistenceOptions.Value.Primary;
21+
options.UseNpgsql(connectionString);
22+
});
23+
1724
services.AddRepositories();
1825

1926
return services;

Chapter-2-modules-separation/Src/Offers/Fitnet.Offers.DataAccess/Database/DatabaseModule.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,21 @@ namespace EvolutionaryArchitecture.Fitnet.Offers.DataAccess.Database;
44
using Microsoft.EntityFrameworkCore;
55
using Microsoft.Extensions.Configuration;
66
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.Options;
78

89
internal static class DatabaseModule
910
{
10-
private const string ConnectionStringConfigurationSection = "Modules:Offers:ConnectionStrings:Primary";
11-
1211
internal static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration)
1312
{
14-
var connectionString = configuration.GetSection(ConnectionStringConfigurationSection).Value;
15-
services.AddDbContext<OffersPersistence>(options => options.UseNpgsql(connectionString));
13+
services.Configure<OffersPersistenceOptions>(configuration.GetSection(OffersPersistenceOptions.SectionName));
14+
services.AddOptionsWithValidateOnStart<OffersPersistenceOptions>();
15+
16+
services.AddDbContext<OffersPersistence>((serviceProvider, options) =>
17+
{
18+
var persistenceOptions = serviceProvider.GetRequiredService<IOptions<OffersPersistenceOptions>>();
19+
var connectionString = persistenceOptions.Value.Primary;
20+
options.UseNpgsql(connectionString);
21+
});
1622

1723
return services;
1824
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace EvolutionaryArchitecture.Fitnet.Offers.DataAccess.Database;
2+
3+
using System.ComponentModel.DataAnnotations;
4+
5+
internal sealed class OffersPersistenceOptions
6+
{
7+
public const string SectionName = "Modules:Offers:ConnectionStrings";
8+
9+
[Required]
10+
public string Primary { get; init; } = string.Empty;
11+
}

Chapter-2-modules-separation/Src/Offers/Fitnet.Offers.DataAccess/Fitnet.Offers.DataAccess.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
2+
<ItemGroup>
3+
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
4+
</ItemGroup>
25
<ItemGroup>
36
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
47
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />

Chapter-2-modules-separation/Src/Passes/Fitnet.Passes.DataAccess/Database/DatabaseModule.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,21 @@ namespace EvolutionaryArchitecture.Fitnet.Passes.DataAccess.Database;
44
using Microsoft.EntityFrameworkCore;
55
using Microsoft.Extensions.Configuration;
66
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.Options;
78

89
internal static class DatabaseModule
910
{
10-
private const string ConnectionStringConfigurationSection = "Modules:Passes:ConnectionStrings:Primary";
11-
1211
internal static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration)
1312
{
14-
var connectionString = configuration.GetRequiredSection(ConnectionStringConfigurationSection).Value;
15-
services.AddDbContext<PassesPersistence>(options => options.UseNpgsql(connectionString));
13+
services.Configure<PassesPersistenceOptions>(configuration.GetSection(PassesPersistenceOptions.SectionName));
14+
services.AddOptionsWithValidateOnStart<PassesPersistenceOptions>();
15+
16+
services.AddDbContext<PassesPersistence>((serviceProvider, options) =>
17+
{
18+
var persistenceOptions = serviceProvider.GetRequiredService<IOptions<PassesPersistenceOptions>>();
19+
var connectionString = persistenceOptions.Value.Primary;
20+
options.UseNpgsql(connectionString);
21+
});
1622

1723
return services;
1824
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace EvolutionaryArchitecture.Fitnet.Passes.DataAccess.Database;
2+
3+
using System.ComponentModel.DataAnnotations;
4+
5+
internal sealed class PassesPersistenceOptions
6+
{
7+
public const string SectionName = "Modules:Passes:ConnectionStrings";
8+
9+
[Required]
10+
public string Primary { get; init; } = string.Empty;
11+
}

Chapter-2-modules-separation/Src/Passes/Fitnet.Passes.DataAccess/Fitnet.Passes.DataAccess.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
2+
<ItemGroup>
3+
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
4+
</ItemGroup>
25
<ItemGroup>
36
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
47
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
namespace EvolutionaryArchitecture.Fitnet.Reports.DataAccess;
22

3+
using Microsoft.Extensions.Configuration;
34
using Microsoft.Extensions.DependencyInjection;
45

56
internal static class DatabaseAccessModule
67
{
7-
internal static IServiceCollection AddDataAccess(this IServiceCollection services)
8+
internal static IServiceCollection AddDataAccess(this IServiceCollection services, IConfiguration configuration)
89
{
10+
services.Configure<ReportsPersistenceOptions>(configuration.GetSection(ReportsPersistenceOptions.SectionName));
11+
services.AddOptionsWithValidateOnStart<ReportsPersistenceOptions>();
12+
913
services.AddSingleton<IDatabaseConnectionFactory, DatabaseConnectionFactory>();
1014

1115
return services;
1216
}
13-
}
17+
}

Chapter-2-modules-separation/Src/Reports/Fitnet.Reports/DataAccess/DatabaseConnectionFactory.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
namespace EvolutionaryArchitecture.Fitnet.Reports.DataAccess;
22

3-
using Microsoft.Extensions.Configuration;
3+
using Microsoft.Extensions.Options;
44
using System.Data;
55
using System.Diagnostics.CodeAnalysis;
66
using Npgsql;
77

8-
internal sealed class DatabaseConnectionFactory(IConfiguration configuration) : IDatabaseConnectionFactory
8+
internal sealed class DatabaseConnectionFactory(IOptions<ReportsPersistenceOptions> persistenceOptions) : IDatabaseConnectionFactory
99
{
10-
private const string ConnectionStringConfigurationSection = "Modules:Reports:ConnectionStrings:Primary";
1110
private NpgsqlConnection? _connection;
1211

1312
public IDbConnection Create()
@@ -17,9 +16,8 @@ public IDbConnection Create()
1716
return _connection;
1817
}
1918

20-
var connectionString = configuration.GetRequiredSection(ConnectionStringConfigurationSection).Value;
21-
_connection =
22-
new NpgsqlConnection(connectionString);
19+
var connectionString = persistenceOptions.Value.Primary;
20+
_connection = new NpgsqlConnection(connectionString);
2321
_connection.Open();
2422

2523
return _connection;

0 commit comments

Comments
 (0)