DivineTree.DCPVault.Storage 1.0.0

dotnet add package DivineTree.DCPVault.Storage --version 1.0.0
                    
NuGet\Install-Package DivineTree.DCPVault.Storage -Version 1.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="DivineTree.DCPVault.Storage" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DivineTree.DCPVault.Storage" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="DivineTree.DCPVault.Storage" />
                    
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 DivineTree.DCPVault.Storage --version 1.0.0
                    
#r "nuget: DivineTree.DCPVault.Storage, 1.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 DivineTree.DCPVault.Storage@1.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=DivineTree.DCPVault.Storage&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=DivineTree.DCPVault.Storage&version=1.0.0
                    
Install as a Cake Tool

DivineTree.DCPVault.Storage

Connection Framework for DCPVault Storage Implementations

NuGet License: MIT .NET 9


What Is This?

DivineTree.DCPVault.Storage is the connection framework for DivineTree.DCPVault storage implementations. It provides the plumbing that every storage adapter needs — connection lifecycle, retry with exponential backoff, exception translation, and disposal — so your implementation focuses on pure storage queries only.

Zero storage SDK. This NuGet ships no Neo4j, Cosmos, or any other storage dependency. It ships the abstract base classes and interfaces your storage implementation extends.


Installation

dotnet add package DivineTree.DCPVault.Storage

Requires:

dotnet add package DivineTree.DCPVault

What Ships in This Package

Component Purpose
IVaultConnectionManager Connection lifecycle contract — OpenAsync · CloseAsync · IsHealthyAsync · IsOpen
IVaultRetryPolicy Retry contract — ExecuteAsync · ExecuteAsync<T>
DefaultVaultRetryPolicy 3 attempts · exponential backoff 200ms base · retries transient only · configurable
DefaultVaultConnectionManager Abstract state machine · thread-safe · template method — implement 3 methods
BaseVaultStorageAdapter<TDomain> Wires connection + retry + error handling — implement 3 pure query methods
VaultStorageException Typed exception — StorageOperation · IsTransient · InnerException always preserved

Quick Start — Implementing a Storage Backend

Extend BaseVaultStorageAdapter<TDomain> and implement three methods:

public sealed class MyEnvelopeVault<TDomain>
    : BaseVaultStorageAdapter<TDomain>
    where TDomain : class
{
    public MyEnvelopeVault(
        IVaultConnectionManager connectionManager,
        IVaultRetryPolicy? retryPolicy = null)
        : base(connectionManager, retryPolicy) { }

    protected override async Task ExecutePersistAsync(
        VaultRecord<TDomain> record, CancellationToken ct)
    {
        // Pure storage query only
        // No null checks — framework handles guard clauses
        // No retry logic — framework handles retry
        // No connection management — framework ensures connection is open
        await _db.UpsertAsync(record.CorrelationId, record);
    }

    protected override async Task<IReadOnlyList<VaultRecord<TDomain>>> ExecuteQueryAsync(
        VaultQuery query, CancellationToken ct)
    {
        return await _db.QueryAsync(query);
    }

    protected override async Task<int> ExecuteCountAsync(CancellationToken ct)
    {
        return await _db.CountAsync();
    }
}

The framework owns everything else.


What the Framework Owns

When you call PersistAsync, QueryAsync, or CountAsync on any BaseVaultStorageAdapter:

Caller
  |
Guard clauses          — null record · empty lineage chain → throws ArgumentException
  |
EnsureConnectionAsync  — opens if closed · health check before every operation
  |
Retry                  — DefaultVaultRetryPolicy · 3 attempts · exponential backoff
  |
ExecutePersistAsync    — YOUR CODE — pure storage query
  |
Exception translation  — raw storage exceptions → VaultStorageException
  |
Dispose                — connection manager lifecycle on IAsyncDisposable

You implement only the bottom layer. The framework handles the rest.


Implementing a Connection Manager

Extend DefaultVaultConnectionManager and implement three methods:

public sealed class Neo4jConnectionManager : DefaultVaultConnectionManager
{
    private readonly string _uri;
    private readonly string _username;
    private readonly string _password;

    public IDriver? Driver { get; private set; }

    public Neo4jConnectionManager(string uri, string username, string password)
    {
        _uri      = uri;
        _username = username;
        _password = password;
    }

    protected override Task OpenConnectionAsync(CancellationToken ct)
    {
        Driver = GraphDatabase.Driver(_uri, AuthTokens.Basic(_username, _password));
        return Task.CompletedTask;
    }

    protected override async Task CloseConnectionAsync(CancellationToken ct)
    {
        if (Driver is not null)
        {
            await Driver.DisposeAsync();
            Driver = null;
        }
    }

    protected override async Task<bool> CheckHealthAsync(CancellationToken ct)
    {
        if (Driver is null) return false;
        try   { await Driver.VerifyConnectivityAsync(); return true; }
        catch { return false; }
    }
}

DefaultVaultRetryPolicy

Ships ready to use. Configurable via constructor:

// Default — 3 attempts · 200ms base · exponential backoff
var retry = new DefaultVaultRetryPolicy();

// Custom
var retry = new DefaultVaultRetryPolicy(
    maxAttempts:    5,
    baseDelayMs:    100,
    retryTransient: true);

Only retries VaultStorageException where IsTransient == true. Non-transient exceptions (auth failure, constraint violation) are not retried.


VaultStorageException

All raw storage exceptions are translated to VaultStorageException by the framework. Your execute methods should let raw exceptions propagate — the framework catches and wraps them.

public sealed class VaultStorageException : Exception
{
    public string StorageOperation { get; }   // "Persist" · "Query" · "Count" · "Open"
    public bool   IsTransient      { get; }   // retry eligible
    // InnerException always preserved
}

Connection Pool Configuration

For connection-pool-aware managers (Neo4j, SQL, etc.), pass options via constructor:

public sealed class Neo4jConnectionOptions
{
    public int      MaxConnectionPoolSize        { get; init; } = 10;
    public TimeSpan ConnectionAcquisitionTimeout { get; init; } = TimeSpan.FromSeconds(30);
    public TimeSpan MaxConnectionLifetime        { get; init; } = TimeSpan.FromHours(1);
    public TimeSpan ConnectionIdleTimeout        { get; init; } = TimeSpan.FromMinutes(10);

    public static readonly Neo4jConnectionOptions Default    = new();
    public static readonly Neo4jConnectionOptions Production = new()
    {
        MaxConnectionPoolSize        = 50,
        ConnectionAcquisitionTimeout = TimeSpan.FromSeconds(60)
    };
}

AuraDB Free safe defaults. Override for production workloads.


AuraDB URI Scheme Note

When using Neo4j AuraDB with neo4j+s:// URI — do not call WithEncryptionLevel. The +s scheme implies TLS. Setting it explicitly causes a driver conflict.

// Correct — neo4j+s implies TLS
GraphDatabase.Driver("neo4j+s://xxxxx.databases.neo4j.io", auth, builder =>
{
    builder.WithMaxConnectionPoolSize(options.MaxConnectionPoolSize);
});

DI Registration Pattern

services.AddSingleton<IVaultConnectionManager>(sp =>
    new Neo4jConnectionManager(
        uri:      configuration["Neo4j:Uri"],
        username: configuration["Neo4j:Username"],
        password: configuration["Neo4j:Password"]));

services.AddSingleton<IVaultRetryPolicy, DefaultVaultRetryPolicy>();

services.AddSingleton<IEnvelopeVault<LoanVaultDomainContext>,
    Neo4jEnvelopeVault<LoanVaultDomainContext>>();

Design Principles

  1. The framework owns plumbing. Your implementation owns queries.
  2. Connection is opened lazily — on first operation, not on construction.
  3. Health is checked before every operation — stale connections never reach your query code.
  4. Only transient failures are retried. Auth failures and constraint violations are not.
  5. All exceptions are translated to VaultStorageException. Raw exceptions never escape the adapter.
  6. Disposal is deterministic. IAsyncDisposable — always await using.

License

MIT — see LICENSE.


DivineTreeDesigns — Sovereign Confidential

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
1.0.0 122 5/17/2026