Table of Contents

Class NpgsqlDbContextFactory

Namespace
FishMMO.Database.Npgsql
Assembly
FishMMO-DB.dll

Factory for creating NpgsqlDbContext instances. Thread-safe and intended for singleton registration. Implements IDesignTimeDbContextFactory<TContext> for EF Core tooling.

public class NpgsqlDbContextFactory : INpgsqlDbContextFactory, IDbContextFactory, IDisposable, IAsyncDisposable, IDbContextFactoryMonitoring, IDesignTimeDbContextFactory<NpgsqlDbContext>
Inheritance
NpgsqlDbContextFactory
Implements
Inherited Members
Extension Methods

Constructors

NpgsqlDbContextFactory()

Initializes a new instance of NpgsqlDbContextFactory for EF Core design-time usage. Loads configuration from the current AppDomain base directory.

public NpgsqlDbContextFactory()

NpgsqlDbContextFactory(NpgsqlDbConfiguration)

Initializes a new instance of NpgsqlDbContextFactory with a pre-built configuration.

public NpgsqlDbContextFactory(NpgsqlDbConfiguration configuration)

Parameters

configuration NpgsqlDbConfiguration

The database configuration.

Exceptions

ArgumentNullException

Thrown when configuration is null.

NpgsqlDbContextFactory(IConfiguration)

Initializes a new instance of NpgsqlDbContextFactory from a pre-built IConfiguration.

public NpgsqlDbContextFactory(IConfiguration configuration)

Parameters

configuration IConfiguration

Configuration root containing an Npgsql section.

Exceptions

ArgumentNullException

Thrown when configuration is null.

NpgsqlDbContextFactory(IConfiguration, bool)

Initializes a new instance of NpgsqlDbContextFactory from a pre-built IConfiguration.

public NpgsqlDbContextFactory(IConfiguration configuration, bool enableLogging)

Parameters

configuration IConfiguration

Configuration root containing an Npgsql section.

enableLogging bool

Enable sensitive data logging for development.

Exceptions

ArgumentNullException

Thrown when configuration is null.

NpgsqlDbContextFactory(IConfiguration, bool, int)

Initializes a new instance of NpgsqlDbContextFactory from a pre-built IConfiguration.

public NpgsqlDbContextFactory(IConfiguration configuration, bool enableLogging, int commandTimeout)

Parameters

configuration IConfiguration

Configuration root containing an Npgsql section.

enableLogging bool

Enable sensitive data logging for development.

commandTimeout int

Command timeout in seconds (overrides config file value).

Exceptions

ArgumentNullException

Thrown when configuration is null.

Properties

ActiveContextCount

Gets the current number of active (not yet disposed) DbContext instances.

public int ActiveContextCount { get; }

Property Value

int

MaxPoolSize

Gets the configured maximum pool size.

public int MaxPoolSize { get; }

Property Value

int

PerformanceTracker

Gets the query performance tracker for operation-level monitoring.

public QueryPerformanceTracker PerformanceTracker { get; }

Property Value

QueryPerformanceTracker

PoolMetrics

Gets the connection pool metrics for monitoring and diagnostics.

public ConnectionPoolMetrics PoolMetrics { get; }

Property Value

ConnectionPoolMetrics

RetryPolicy

Gets the retry policy configuration for transient failure handling.

public RetryPolicyConfiguration RetryPolicy { get; }

Property Value

RetryPolicyConfiguration

Methods

CanConnectAsync(CancellationToken)

Tests whether the database is reachable. Useful for startup validation or health checks.

public Task<bool> CanConnectAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

Cancellation token.

Returns

Task<bool>

True if a connection can be established; false otherwise.

CreateDbContext()

Creates a new DbContext instance. Thread-safe. Each call creates a fresh context with new options - safe for concurrent use. The factory tracks active contexts for graceful shutdown support.

public NpgsqlDbContext CreateDbContext()

Returns

NpgsqlDbContext

A new NpgsqlDbContext instance.

CreateDbContext(string[])

IDesignTimeDbContextFactory implementation for EF Core migrations. Used by dotnet ef commands for database migrations.

public NpgsqlDbContext CreateDbContext(string[] args)

Parameters

args string[]

Command line arguments from migration tools.

Returns

NpgsqlDbContext

A new NpgsqlDbContext instance.

CreateDbContextAsync(CancellationToken)

Asynchronously creates a new DbContext instance. DbContext creation is CPU-bound, not I/O-bound, so this returns a completed task. The cancellation token is checked before context creation.

public Task<NpgsqlDbContext> CreateDbContextAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

Cancellation token.

Returns

Task<NpgsqlDbContext>

A new NpgsqlDbContext instance.

Exceptions

OperationCanceledException

Thrown if cancellation is requested.

Dispose()

Disposes the factory and releases all resources. Calls Shutdown() to reject new context creation, waits briefly for active contexts to complete, then disposes monitoring resources.

public void Dispose()

Remarks

This method will wait up to 5 seconds for active contexts to be disposed before proceeding. For longer waits, use ShutdownGracefullyAsync(TimeSpan, CancellationToken) before calling Dispose.

DisposeAsync()

Asynchronously disposes the factory and releases all resources. Calls Shutdown() to reject new context creation, waits briefly for active contexts to complete, then disposes monitoring resources.

public ValueTask DisposeAsync()

Returns

ValueTask

A ValueTask representing the asynchronous dispose operation.

Shutdown()

Shuts down the factory and rejects new DbContext creation. Unity-friendly synchronous shutdown (safe to call from main thread).

public void Shutdown()

ShutdownAsync(CancellationToken)

Initiates shutdown and returns immediately without waiting for active DbContext instances to complete.

This method sets the shutdown flag (which causes CreateDbContext() to throw ObjectDisposedException for future calls) and returns CompletedTask without waiting for active contexts to drain. This is a non-graceful shutdown — active queries or transactions on existing contexts will continue until those contexts are disposed by their owners, but no new contexts can be created.

Callers that require a graceful shutdown (waiting for all active contexts to complete) should use ShutdownGracefullyAsync(TimeSpan, CancellationToken) with an appropriate timeout instead.

public Task ShutdownAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

A cancellation token to observe while initiating shutdown.

Returns

Task

A task that completes immediately after the shutdown flag is set.

ShutdownGracefullyAsync(TimeSpan, CancellationToken)

Initiates shutdown and waits for all active contexts to be disposed.

public Task<bool> ShutdownGracefullyAsync(TimeSpan timeout, CancellationToken cancellationToken = default)

Parameters

timeout TimeSpan

Maximum time to wait for active contexts to complete.

cancellationToken CancellationToken

Cancellation token.

Returns

Task<bool>

True if all contexts completed within the timeout; false if timed out.

TryConnectAsync(CancellationToken)

Tests whether the database is reachable, reporting why when it is not.

public Task<(bool Connected, string? FailureReason)> TryConnectAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

Cancellation token.

Returns

Task<(bool Connected, string FailureReason)>

Whether the connection succeeded, and the failure reason when it did not.

Remarks

CanConnectAsync(CancellationToken) collapses every cause into false: a wrong password (SQLSTATE 28000), an unreachable host, an exhausted pool, and a factory that has already shut down are indistinguishable to its caller. That turns a five-second fix into an outage spent checking the network, so the reason is preserved here for callers that report to an operator. Never throws.

ValidateSchemaAsync(CancellationToken)

Reports whether this database has applied every migration the entity model expects.

public Task<SchemaValidationResult> ValidateSchemaAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

Cancellation token.

Returns

Task<SchemaValidationResult>

What was found. Never throws.

Remarks

Migrations are generated per developer and applied locally rather than shared through source control, so pulling a change to an entity does not bring a migration with it and nothing applies one on your behalf. The database simply stays where it was, and the first symptom is a query failing at runtime for a column that does not exist — which surfaces far from the cause, as missing data rather than as a schema problem.

This catches one of the two ways that happens: pending migrations, where the migration exists and this database has not run it. Fix with dotnet ef database update.

It does not catch model drift — an entity changed with no migration generated for it, which leaves nothing pending and a schema that is quietly wrong. A drift check lived here and never worked once: it compared the migration snapshot's model against the live one, but EF builds ModelSnapshot.Model with an empty convention set, so GetRelationalModel() threw on every startup. EF Core 5 has no supported way to rebuild that model at runtime, so the check was removed rather than left reporting a failure forever. See issue #162; drift belongs in CI, where a scaffolded migration can be asserted empty.