Skip to content

Commit 658c18d

Browse files
committed
Refactor Postgres connection string handling; update deps
- Introduced IPostgresConnectionStringProvider abstraction and implementation for modular connection string management. - Refactored AddPostgresDbContext to use the new provider, improving separation of concerns and testability. - Moved connection string logic out of ServiceCollectionExtensions. - Added project reference to EasyExtensions in Npgsql project. - Updated Sentry.AspNetCore to 6.0.0 and NUnit3TestAdapter to 6.0.1.
1 parent 84e4de4 commit 658c18d

7 files changed

Lines changed: 151 additions & 88 deletions

File tree

Sources/EasyExtensions.AspNetCore.Sentry/EasyExtensions.AspNetCore.Sentry.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
<None Include="packageIcon.png" Pack="true" PackagePath="\" />
3131
<None Include="..\..\LICENSE.md" Pack="true" PackagePath="LICENSE.md" />
3232
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
33-
<PackageReference Include="Sentry.AspNetCore" Version="5.16.2" />
33+
<PackageReference Include="Sentry.AspNetCore" Version="6.0.0" />
3434
<ProjectReference Include="..\EasyExtensions.AspNetCore\EasyExtensions.AspNetCore.csproj" />
3535
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
3636
</ItemGroup>

Sources/EasyExtensions.Crypto.Tests/EasyExtensions.Crypto.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<PrivateAssets>all</PrivateAssets>
2121
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2222
</PackageReference>
23-
<PackageReference Include="NUnit3TestAdapter" Version="6.0.0" />
23+
<PackageReference Include="NUnit3TestAdapter" Version="6.0.1" />
2424
<ProjectReference Include="..\EasyExtensions.Crypto\EasyExtensions.Crypto.csproj" />
2525
<Using Include="NUnit.Framework" />
2626
</ItemGroup>

Sources/EasyExtensions.EntityFrameworkCore.Npgsql/EasyExtensions.EntityFrameworkCore.Npgsql.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,7 @@
3333
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="10.0.1" />
3434
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
3535
</ItemGroup>
36+
<ItemGroup>
37+
<ProjectReference Include="..\EasyExtensions\EasyExtensions.csproj" />
38+
</ItemGroup>
3639
</Project>
Lines changed: 17 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
using EasyExtensions.EntityFrameworkCore.Npgsql.Builders;
1+
using EasyExtensions.Abstractions;
2+
using EasyExtensions.EntityFrameworkCore.Npgsql.Builders;
23
using EasyExtensions.EntityFrameworkCore.Npgsql.Migrations;
4+
using EasyExtensions.EntityFrameworkCore.Npgsql.Providers;
35
using Microsoft.EntityFrameworkCore;
46
using Microsoft.EntityFrameworkCore.Design;
57
using Microsoft.Extensions.Configuration;
68
using Microsoft.Extensions.DependencyInjection;
7-
using Npgsql;
89

910
namespace EasyExtensions.EntityFrameworkCore.Npgsql.Extensions
1011
{
@@ -28,17 +29,24 @@ public static class ServiceCollectionExtensions
2829
/// builder.Services.AddPostgresDbContext&lt;MyDbContext&gt;(f =&gt; { f.ConfigurationSection = "Db"; });
2930
/// </code>
3031
/// </example>
31-
public static IServiceCollection AddPostgresDbContext<TContext>(this IServiceCollection services,
32-
Action<PostgresOptionsBuilder>? setup = null, Action<DbContextOptionsBuilder>? setupContextOptions = null) where TContext : DbContext
32+
public static IServiceCollection AddPostgresDbContext<TContext>(
33+
this IServiceCollection services,
34+
Action<PostgresOptionsBuilder>? setup = null,
35+
Action<DbContextOptionsBuilder>? setupContextOptions = null)
36+
where TContext : DbContext
3337
{
3438
PostgresOptionsBuilder contextFactory = new();
3539
setup?.Invoke(contextFactory);
3640

37-
services.AddDbContext<TContext>((sp, builder) =>
41+
services.AddScoped<IPostgresConnectionStringProvider>(sp =>
3842
{
3943
var configuration = sp.GetRequiredService<IConfiguration>();
40-
string connectionString = BuildConnectionString(configuration, contextFactory);
41-
builder.UseNpgsql(connectionString);
44+
return new PostgresConnectionStringProvider(configuration, contextFactory);
45+
});
46+
services.AddDbContext<TContext>((sp, builder) =>
47+
{
48+
var conStringProvider = sp.GetRequiredService<IPostgresConnectionStringProvider>();
49+
builder.UseNpgsql(conStringProvider.GetConnectionString());
4250
setupContextOptions?.Invoke(builder);
4351
if (contextFactory.UseLazyLoadingProxies)
4452
{
@@ -81,9 +89,8 @@ public static IServiceCollection AddPostgresDbContext<TContext, TImplementation>
8189

8290
services.AddDbContext<TContext, TImplementation>((sp, builder) =>
8391
{
84-
var configuration = sp.GetRequiredService<IConfiguration>();
85-
string connectionString = BuildConnectionString(configuration, contextFactory);
86-
builder.UseNpgsql(connectionString);
92+
var conStringProvider = sp.GetRequiredService<IPostgresConnectionStringProvider>();
93+
builder.UseNpgsql(conStringProvider.GetConnectionString());
8794
setupContextOptions?.Invoke(builder);
8895
if (contextFactory.UseLazyLoadingProxies)
8996
{
@@ -97,80 +104,5 @@ public static IServiceCollection AddPostgresDbContext<TContext, TImplementation>
97104
}
98105
return services;
99106
}
100-
101-
private static string BuildConnectionString(IConfiguration configuration, PostgresOptionsBuilder contextFactory)
102-
{
103-
bool isDevelopment = GetIsDevelopment(configuration);
104-
var settings = configuration.GetSection(contextFactory.ConfigurationSection);
105-
string host = GetSetting(settings, "Host", configuration, contextFactory);
106-
string portStr = GetSetting(settings, "Port", configuration, contextFactory);
107-
string username = GetSetting(settings, "Username", configuration, contextFactory);
108-
string password = GetSetting(settings, "Password", configuration, contextFactory);
109-
string database = GetSetting(settings, "Database", configuration, contextFactory);
110-
if (isDevelopment)
111-
{
112-
database = TryGetSetting(settings, "DatabaseDev", configuration, contextFactory) ?? database;
113-
}
114-
NpgsqlConnectionStringBuilder builder = new()
115-
{
116-
Host = host,
117-
Username = username,
118-
Password = password,
119-
Database = database,
120-
Port = ushort.Parse(portStr),
121-
Timezone = contextFactory.Timezone,
122-
Encoding = contextFactory.Encoding,
123-
Timeout = contextFactory.TimeoutSeconds,
124-
MaxPoolSize = contextFactory.MaxPoolSize,
125-
CommandTimeout = contextFactory.TimeoutSeconds,
126-
IncludeErrorDetail = contextFactory.IncludeErrorDetail,
127-
};
128-
contextFactory.SetupConnectionString?.Invoke(builder);
129-
return builder.ConnectionString;
130-
}
131-
132-
private static string? TryGetSetting(IConfigurationSection settings, string key, IConfiguration configuration, PostgresOptionsBuilder contextFactory)
133-
{
134-
if (configuration[contextFactory.ConfigurationPrefix + key] is string value)
135-
{
136-
return value;
137-
}
138-
if (!settings.Exists())
139-
{
140-
return null;
141-
}
142-
return settings[key];
143-
}
144-
145-
private static string GetSetting(IConfigurationSection settings,
146-
string key,
147-
IConfiguration configuration,
148-
PostgresOptionsBuilder contextFactory,
149-
string? defaultValue = null)
150-
{
151-
if (configuration[contextFactory.ConfigurationPrefix + key] is string value)
152-
{
153-
return value;
154-
}
155-
if (!settings.Exists())
156-
{
157-
if (defaultValue is not null)
158-
{
159-
return defaultValue;
160-
}
161-
throw new KeyNotFoundException($"{contextFactory.ConfigurationSection} section or {contextFactory.ConfigurationPrefix}{key} is not set");
162-
}
163-
return settings[key] ?? throw new KeyNotFoundException($"{settings.Path}:{key} is not set");
164-
}
165-
166-
private static bool GetIsDevelopment(IConfiguration configuration)
167-
{
168-
bool result = (Environment.GetEnvironmentVariable("ENVIRONMENT") ?? string.Empty) == "Development";
169-
if (!result)
170-
{
171-
result = (configuration["ASPNETCORE_ENVIRONMENT"] ?? string.Empty) == "Development";
172-
}
173-
return result;
174-
}
175107
}
176108
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
using EasyExtensions.Abstractions;
2+
using EasyExtensions.EntityFrameworkCore.Npgsql.Builders;
3+
using Microsoft.Extensions.Configuration;
4+
using Npgsql;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Text;
8+
9+
namespace EasyExtensions.EntityFrameworkCore.Npgsql.Providers
10+
{
11+
/// <summary>
12+
/// Provides a mechanism for retrieving PostgreSQL database connection strings based on application configuration
13+
/// and specified options.
14+
/// </summary>
15+
/// <remarks>This provider combines values from the supplied configuration and options to build a
16+
/// connection string suitable for use with Npgsql. It supports environment-specific overrides (such as development
17+
/// databases) and allows customization through the provided options. The resulting connection string reflects the
18+
/// current application environment and configuration state.</remarks>
19+
/// <param name="cfg">The configuration source used to retrieve connection string settings and environment information.</param>
20+
/// <param name="options">The options that define how the PostgreSQL connection string is constructed, including section names, prefixes,
21+
/// and additional connection parameters.</param>
22+
public class PostgresConnectionStringProvider(IConfiguration cfg,
23+
PostgresOptionsBuilder options) : IPostgresConnectionStringProvider
24+
{
25+
/// <summary>
26+
/// Retrieves the database connection string based on the current configuration and options.
27+
/// </summary>
28+
/// <returns>A string containing the database connection string. The format and contents depend on the current
29+
/// configuration settings.</returns>
30+
public string GetConnectionString()
31+
{
32+
return BuildConnectionString(cfg, options);
33+
}
34+
35+
private static string BuildConnectionString(IConfiguration configuration, PostgresOptionsBuilder contextFactory)
36+
{
37+
bool isDevelopment = GetIsDevelopment(configuration);
38+
var settings = configuration.GetSection(contextFactory.ConfigurationSection);
39+
string host = GetSetting(settings, "Host", configuration, contextFactory);
40+
string portStr = GetSetting(settings, "Port", configuration, contextFactory);
41+
string username = GetSetting(settings, "Username", configuration, contextFactory);
42+
string password = GetSetting(settings, "Password", configuration, contextFactory);
43+
string database = GetSetting(settings, "Database", configuration, contextFactory);
44+
if (isDevelopment)
45+
{
46+
database = TryGetSetting(settings, "DatabaseDev", configuration, contextFactory) ?? database;
47+
}
48+
NpgsqlConnectionStringBuilder builder = new()
49+
{
50+
Host = host,
51+
Username = username,
52+
Password = password,
53+
Database = database,
54+
Port = ushort.Parse(portStr),
55+
Timezone = contextFactory.Timezone,
56+
Encoding = contextFactory.Encoding,
57+
Timeout = contextFactory.TimeoutSeconds,
58+
MaxPoolSize = contextFactory.MaxPoolSize,
59+
CommandTimeout = contextFactory.TimeoutSeconds,
60+
IncludeErrorDetail = contextFactory.IncludeErrorDetail,
61+
};
62+
contextFactory.SetupConnectionString?.Invoke(builder);
63+
return builder.ConnectionString;
64+
}
65+
66+
private static string? TryGetSetting(IConfigurationSection settings, string key, IConfiguration configuration, PostgresOptionsBuilder contextFactory)
67+
{
68+
if (configuration[contextFactory.ConfigurationPrefix + key] is string value)
69+
{
70+
return value;
71+
}
72+
if (!settings.Exists())
73+
{
74+
return null;
75+
}
76+
return settings[key];
77+
}
78+
79+
private static string GetSetting(IConfigurationSection settings,
80+
string key,
81+
IConfiguration configuration,
82+
PostgresOptionsBuilder contextFactory,
83+
string? defaultValue = null)
84+
{
85+
if (configuration[contextFactory.ConfigurationPrefix + key] is string value)
86+
{
87+
return value;
88+
}
89+
if (!settings.Exists())
90+
{
91+
if (defaultValue is not null)
92+
{
93+
return defaultValue;
94+
}
95+
throw new KeyNotFoundException($"{contextFactory.ConfigurationSection} section or {contextFactory.ConfigurationPrefix}{key} is not set");
96+
}
97+
return settings[key] ?? throw new KeyNotFoundException($"{settings.Path}:{key} is not set");
98+
}
99+
100+
private static bool GetIsDevelopment(IConfiguration configuration)
101+
{
102+
bool result = (Environment.GetEnvironmentVariable("ENVIRONMENT") ?? string.Empty) == "Development";
103+
if (!result)
104+
{
105+
result = (configuration["ASPNETCORE_ENVIRONMENT"] ?? string.Empty) == "Development";
106+
}
107+
return result;
108+
}
109+
}
110+
}

Sources/EasyExtensions.Tests/EasyExtensions.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<PrivateAssets>all</PrivateAssets>
1818
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1919
</PackageReference>
20-
<PackageReference Include="NUnit3TestAdapter" Version="6.0.0" />
20+
<PackageReference Include="NUnit3TestAdapter" Version="6.0.1" />
2121
<ProjectReference Include="..\EasyExtensions.Clients\EasyExtensions.Clients.csproj" />
2222
<ProjectReference Include="..\EasyExtensions.Drawing\EasyExtensions.Drawing.csproj" />
2323
<ProjectReference Include="..\EasyExtensions.Fonts\EasyExtensions.Fonts.csproj" />
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace EasyExtensions.Abstractions
2+
{
3+
/// <summary>
4+
/// Defines a mechanism for retrieving a PostgreSQL database connection string.
5+
/// </summary>
6+
/// <remarks>Implementations of this interface can provide connection strings from various sources, such
7+
/// as configuration files, environment variables, or secure vaults. This abstraction enables flexible management of
8+
/// database connection details across different environments.</remarks>
9+
public interface IPostgresConnectionStringProvider
10+
{
11+
/// <summary>
12+
/// Retrieves the connection string used to establish a connection to the data source.
13+
/// </summary>
14+
/// <returns>A string containing the connection details required to connect to the data source. The format and contents
15+
/// of the string depend on the specific data provider.</returns>
16+
string GetConnectionString();
17+
}
18+
}

0 commit comments

Comments
 (0)