Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
## v1.6.0 (July 2, 2025)

### Added:
- Db Credentials file feature.
- This feature allows a database connection to be created in cases where database credentials need to be read from a file. Currently only active on PostgreSQL.
- It can be activated with the new config value `UseDbCredentialsFile`.
- This feature requires a new config section called `DbCredentialsFileSettings` with the following options:
- `FileName`: File name containing database credentials (should be full path)
- `Host`: Host information of the database
- `Database`: Db name of the database
- `ApplicationName`: App name information on database connection
- `Port`: Port of the database
- `AdditionalParameters`: Additional parameters to be added on Connection. Flags such as `Pooling`, `TrustServerCertificate` can be added.


## v1.5.0 (March 6, 2025)

### Added:
Expand Down
9 changes: 9 additions & 0 deletions example/Postgres/config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,14 @@
"Threshold": 3,
"DurationSc": 60,
"HalfOpenMaxAttempts": 1
},
"UseDbCredentialsFile": true,
"DbCredentialsFileSettings": {
"FileName": "config/postgresql-test-cluster.json",
"Host": "10.85.240.242",
"Database": "test",
"ApplicationName": "PollingOutboxPublisher",
"Port": 5432,
"AdditionalParameters": "Pooling=true;TrustServerCertificate=true;"
}
}
14 changes: 14 additions & 0 deletions src/ConfigOptions/DbCredentialsFileSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Diagnostics.CodeAnalysis;

namespace PollingOutboxPublisher.ConfigOptions;

[ExcludeFromCodeCoverage]
public class DbCredentialsFileSettings
{
public string FileName { get; set; }
public string Host { get; set; }
public string Database { get; set; }
public int Port { get; set; }
public string ApplicationName { get; set; }
public string AdditionalParameters { get; set; }
}
77 changes: 72 additions & 5 deletions src/Database/Providers/PostgresConnectionProvider.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Npgsql;
using PollingOutboxPublisher.ConfigOptions;
using PollingOutboxPublisher.Database.Providers.Interfaces;
using PollingOutboxPublisher.Exceptions;

Expand All @@ -12,15 +15,25 @@ public class PostgresConnectionProvider : IPostgresConnectionProvider
{
private readonly string _connectionString;

public PostgresConnectionProvider(IConfiguration configuration)
public PostgresConnectionProvider(IConfiguration configuration, IOptions<DbCredentialsFileSettings> databaseTbpAuthenticationCredentials)
{
var connectionString = configuration.GetValue<string>("ConnectionString");
if (string.IsNullOrWhiteSpace(connectionString))
if (configuration.GetValue<bool>("UseDbCredentialsFile") is true)
{
throw new MissingConfigurationException("ConnectionString");
ValidateTbpAuthenticationCredentials(databaseTbpAuthenticationCredentials.Value);
var dbCredentials = databaseTbpAuthenticationCredentials.Value;
var postgresqlUsernamePassword = GetPostgresqlUsernameAndPassword(dbCredentials.FileName);
_connectionString = GenerateConnectionString(postgresqlUsernamePassword.userName, postgresqlUsernamePassword.password, dbCredentials.Host, dbCredentials.Database, dbCredentials.Port, dbCredentials.ApplicationName,dbCredentials.AdditionalParameters);
}
else
{
var connectionString = configuration.GetValue<string>("ConnectionString");
if (string.IsNullOrWhiteSpace(connectionString))
{
throw new MissingConfigurationException("ConnectionString");
}

_connectionString = connectionString;
_connectionString = connectionString;
}
}

public IDbConnection CreateConnection()
Expand All @@ -29,4 +42,58 @@ public IDbConnection CreateConnection()
public IDbConnection CreateConnectionForReadOnly()
=> new NpgsqlConnection(_connectionString);


private static (string userName, string password) GetPostgresqlUsernameAndPassword(string fileName)
{
if (!File.Exists(fileName))
{
throw new FileNotFoundException($"Postgresql credentials file not found: {fileName}");
}

var postgresqlCredentials= new ConfigurationBuilder()
.AddJsonFile(fileName)
.Build();

var username = postgresqlCredentials["username"];
var password = postgresqlCredentials["password"];
return (username, password);
}

private static void ValidateTbpAuthenticationCredentials(DbCredentialsFileSettings credentialses)
{
if (string.IsNullOrWhiteSpace(credentialses.FileName))
{
throw new MissingConfigurationException("DatabaseTbpAuthenticationCredentials:FileName");
}

if (string.IsNullOrWhiteSpace(credentialses.Host))
{
throw new MissingConfigurationException("DatabaseTbpAuthenticationCredentials:Host");
}

if (string.IsNullOrWhiteSpace(credentialses.Database))
{
throw new MissingConfigurationException("DatabaseTbpAuthenticationCredentials:Database");
}

if (string.IsNullOrWhiteSpace(credentialses.ApplicationName))
{
throw new MissingConfigurationException("DatabaseTbpAuthenticationCredentials:ApplicationName");
}

if (credentialses.Port == 0)
{
throw new MissingConfigurationException("DatabaseTbpAuthenticationCredentials:Port");
}
}

private static string GenerateConnectionString(string userName, string password, string host, string database, int port, string appName, string additionalParameters)
{
var connectionString = $"User ID={userName};Password={password};Server={host};Port={port};Database={database};ApplicationName={appName};";

if (!string.IsNullOrEmpty(additionalParameters))
connectionString = string.Concat(connectionString, additionalParameters);;

return connectionString;
}
}
2 changes: 1 addition & 1 deletion src/PollingOutboxPublisher.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<Version>1.5.0</Version>
<Version>1.6.0</Version>
<RootNamespace>PollingOutboxPublisher</RootNamespace>
</PropertyGroup>

Expand Down
2 changes: 2 additions & 0 deletions src/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ private static void RegisterConfigs(IServiceCollection services, HostBuilderCont
hostContext.Configuration.GetSection(nameof(ConfigOptions.Redis)));
services.Configure<CircuitBreakerSettings>(
hostContext.Configuration.GetSection(nameof(CircuitBreakerSettings)));
services.Configure<DbCredentialsFileSettings>(
hostContext.Configuration.GetSection(nameof(DbCredentialsFileSettings)));
}

private static void RegisterSerilog(IServiceCollection services)
Expand Down