pvNugsCsProviderNc9PgSql 9.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package pvNugsCsProviderNc9PgSql --version 9.0.0
                    
NuGet\Install-Package pvNugsCsProviderNc9PgSql -Version 9.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="pvNugsCsProviderNc9PgSql" Version="9.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="pvNugsCsProviderNc9PgSql" Version="9.0.0" />
                    
Directory.Packages.props
<PackageReference Include="pvNugsCsProviderNc9PgSql" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add pvNugsCsProviderNc9PgSql --version 9.0.0
                    
#r "nuget: pvNugsCsProviderNc9PgSql, 9.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package pvNugsCsProviderNc9PgSql@9.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=pvNugsCsProviderNc9PgSql&version=9.0.0
                    
Install as a Cake Addin
#tool nuget:?package=pvNugsCsProviderNc9PgSql&version=9.0.0
                    
Install as a Cake Tool

pvNugsCsProviderPgSql

NuGet Version NuGet Downloads License

A comprehensive PostgreSQL connection string provider for .NET 9.0 applications with support for multiple authentication modes, role-based access control, and automatic credential management.

🚀 Features

  • Multiple Authentication Modes: Config-based, Static Secret Manager, and Dynamic Secret Manager
  • Role-Based Access Control: Support for Owner, Application, and Reader roles with separate credentials
  • Automatic Credential Management: Dynamic credential refresh with expiration handling
  • Thread-Safe Operations: Concurrent access with internal locking and caching mechanisms
  • Flexible Configuration: Comprehensive configuration options with validation
  • Secret Manager Integration: Compatible with Azure Key Vault, AWS Secrets Manager, and other secret stores
  • Production Ready: Designed for high-security environments with zero-trust architectures

📦 Installation

bash
dotnet add package pvNugsCsProviderPgSql

🛠 Dependencies

Required Dependencies

  • IConsoleLoggerService: Mandatory logging service for error and diagnostic logging
    dotnet add package pvNugsLoggerNc9Abstractions
    

Optional Dependencies (Mode-Specific)

  • IPvNugsStaticSecretManager: For StaticSecret mode
    dotnet add package pvNugsSecretManagerNc9Abstractions
    
  • IPvNugsDynamicSecretManager: For DynamicSecret mode
    dotnet add package pvNugsSecretManagerNc9Abstractions
    

🔧 Quick Start

1. Basic Setup (Config Mode)

appSettings.json:

json
{
  "PvNugsCsProviderPgSqlConfig": {
    "Mode": "Config",
    "Server": "localhost",
    "Database": "myapp_db",
    "Schema": "public",
    "Username": "myapp_user",
    "Password": "your_password"
  }
}

Program.cs:

csharp
using pvNugsCsProviderNc9PgSql;

var builder = WebApplication.CreateBuilder(args);

// Register required logger
builder.Services.AddSingleton<IConsoleLoggerService, ConsoleLoggerServiceImpl>();

// Register PostgreSQL connection string provider
builder.Services.TryAddPvNugsCsProviderPgSql(builder.Configuration);

var app = builder.Build();

2. Using the Provider

csharp
public class DataService
{
    private readonly IPvNugsCsProvider _csProvider;

    public DataService(IPvNugsCsProvider csProvider)
    {
        _csProvider = csProvider;
    }

    public async Task<List<User>> GetUsersAsync()
    {
        // Get connection string for Reader role (least privilege)
        var connectionString = await _csProvider.GetConnectionStringAsync(SqlRoleEnu.Reader);
        
        await using var connection = new NpgsqlConnection(connectionString);
        await connection.OpenAsync();
        
        // Your database operations...
        return users;
    }
}

🔐 Authentication Modes

Config Mode

Credentials are stored directly in configuration files. Suitable for development environments.

json
{
  "PvNugsCsProviderPgSqlConfig": {
    "Mode": "Config",
    "Server": "localhost",
    "Database": "myapp",
    "Schema": "public",
    "Username": "app_user",
    "Password": "secret123"
  }
}

StaticSecret Mode

Passwords are retrieved from a secret manager while usernames come from configuration.

json
{
  "PvNugsCsProviderPgSqlConfig": {
    "Mode": "StaticSecret",
    "Server": "mydb.postgres.database.azure.com",
    "Database": "production_db",
    "Schema": "app_schema",
    "Username": "app_user",
    "SecretName": "myapp-postgres"
  }
}
csharp
// Register secret manager
builder.Services.AddSingleton<IPvNugsStaticSecretManager, AzureKeyVaultSecretManager>();
builder.Services.TryAddPvNugsCsProviderPgSql(builder.Configuration);

DynamicSecret Mode

Both username and password are dynamically generated with automatic expiration and renewal.

json
{
  "PvNugsCsProviderPgSqlConfig": {
    "Mode": "DynamicSecret",
    "Server": "secure-db.example.com",
    "Database": "production_db",
    "Schema": "app_schema",
    "SecretName": "myapp-postgres-dynamic"
  }
}
csharp
// Register dynamic secret manager
builder.Services.AddSingleton<IPvNugsDynamicSecretManager, VaultDynamicSecretManager>();
builder.Services.TryAddPvNugsCsProviderPgSql(builder.Configuration);

🎯 Role-Based Access Control

The provider supports three SQL roles for implementing the principle of least privilege:

csharp
public class DatabaseService
{
    private readonly IPvNugsPgSqlCsProvider _csProvider;

    public DatabaseService(IPvNugsPgSqlCsProvider csProvider)
    {
        _csProvider = csProvider;
    }

    // Read operations - use Reader role
    public async Task<List<Product>> GetProductsAsync()
    {
        var cs = await _csProvider.GetConnectionStringAsync(SqlRoleEnu.Reader);
        // Use connection string...
    }

    // Application logic - use Application role
    public async Task UpdateInventoryAsync(int productId, int quantity)
    {
        var cs = await _csProvider.GetConnectionStringAsync(SqlRoleEnu.Application);
        // Use connection string...
    }

    // Administrative tasks - use Owner role
    public async Task CreateTablesAsync()
    {
        var cs = await _csProvider.GetConnectionStringAsync(SqlRoleEnu.Owner);
        // Use connection string...
    }
}

🔑 Secret Naming Convention

For StaticSecret and DynamicSecret modes, secrets are resolved using the pattern:


{SecretName}-{Role}

Example:

  • SecretName: "myapp-postgres"
  • Roles: Reader, Application, Owner
  • Secret names: "myapp-postgres-Reader", "myapp-postgres-Application", "myapp-postgres-Owner"

⚙️ Configuration Options

Property Required Description Example
Mode Always Authentication mode "DynamicSecret"
Server Always PostgreSQL server address "db.example.com"
Database Always Database name "myapp_production"
Schema Always Default schema "app_schema"
Port Optional Server port (default: 5432) 5432
Username Config/Static Database username "app_user"
Password Config only Database password "secret123"
SecretName Secret modes Base secret name "myapp-db"
Timezone Optional Connection timezone "UTC"
TimeoutInSeconds Optional Command timeout 30

🔒 Security Best Practices

  1. Never use Config mode in production - passwords in configuration files are a security risk
  2. Use DynamicSecret mode for high-security environments - provides automatic credential rotation
  3. Implement role-based access - use appropriate roles for different operations
  4. Monitor credential expiration - the provider handles this automatically for dynamic credentials
  5. Use secure secret managers - Azure Key Vault, AWS Secrets Manager, HashiCorp Vault

🚨 Error Handling

The provider throws PvNugsCsProviderException for various error conditions:

csharp
try
{
    var connectionString = await _csProvider.GetConnectionStringAsync(SqlRoleEnu.Application);
    // Use connection string...
}
catch (PvNugsCsProviderException ex)
{
    // Handle provider-specific errors
    _logger.LogError(ex, "Failed to get connection string");
}

Common error scenarios:

  • Missing or invalid configuration
  • Secret manager communication failures
  • Expired or missing credentials
  • Network timeouts during credential retrieval

🔄 Dynamic Credential Lifecycle

For DynamicSecret mode, the provider automatically:

  1. Fetches fresh credentials when cache is empty
  2. Monitors credential expiration times
  3. Refreshes credentials before they expire
  4. Handles concurrent access safely
  5. Logs credential lifecycle events

📚 Advanced Usage

Custom Secret Manager Integration

csharp
public class CustomSecretManager : IPvNugsDynamicSecretManager
{
    public async Task<IPvNugsDynamicCredential?> GetDynamicSecretAsync(
        string secretName, 
        CancellationToken cancellationToken = default)
    {
        // Your custom implementation
        return new DynamicCredential
        {
            Username = "generated_user",
            Password = "generated_password",
            ExpirationDateUtc = DateTime.UtcNow.AddHours(1)
        };
    }

    public async Task<string?> GetStaticSecretAsync(
        string secretName, 
        CancellationToken cancellationToken = default)
    {
        // Your custom implementation
        return await GetPasswordFromCustomStore(secretName);
    }
}

Monitoring and Observability

public class MonitoredDataService
{
    private readonly IPvNugsPgSqlCsProvider _csProvider;
    private readonly ILogger _logger;

    public MonitoredDataService(IPvNugsPgSqlCsProvider csProvider, ILogger logger)
    {
        _csProvider = csProvider;
        _logger = logger;
    }

    public async Task<string> GetDataAsync()
    {
        var stopwatch = Stopwatch.StartNew();
        try
        {
            var cs = await _csProvider.GetConnectionStringAsync(SqlRoleEnu.Reader);
            var username = _csProvider.GetUsername(SqlRoleEnu.Reader);
            var useDynamic = _csProvider.UseDynamicCredentials;
            
            _logger.LogInformation("Retrieved connection string for user {Username}, Dynamic: {UseDynamic}, Time: {Elapsed}ms",
                username, useDynamic, stopwatch.ElapsedMilliseconds);
                
            // Use connection string...
            return "data";
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to get connection string after {Elapsed}ms", 
                stopwatch.ElapsedMilliseconds);
            throw;
        }
    }
}

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

📞 Support

For support and questions, please open an issue on the GitHub repository.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
9.0.4 59 9/26/2025
9.0.3 111 9/12/2025
9.0.2 141 9/11/2025
9.0.1 225 9/10/2025 9.0.1 is deprecated because it has critical bugs.
9.0.0 275 8/28/2025 9.0.0 is deprecated because it has critical bugs.

Initial