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
<PackageReference Include="DivineTree.DCPVault.Storage" Version="1.0.0" />
<PackageVersion Include="DivineTree.DCPVault.Storage" Version="1.0.0" />
<PackageReference Include="DivineTree.DCPVault.Storage" />
paket add DivineTree.DCPVault.Storage --version 1.0.0
#r "nuget: DivineTree.DCPVault.Storage, 1.0.0"
#:package DivineTree.DCPVault.Storage@1.0.0
#addin nuget:?package=DivineTree.DCPVault.Storage&version=1.0.0
#tool nuget:?package=DivineTree.DCPVault.Storage&version=1.0.0
DivineTree.DCPVault.Storage
Connection Framework for DCPVault Storage Implementations
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
- The framework owns plumbing. Your implementation owns queries.
- Connection is opened lazily — on first operation, not on construction.
- Health is checked before every operation — stale connections never reach your query code.
- Only transient failures are retried. Auth failures and constraint violations are not.
- All exceptions are translated to
VaultStorageException. Raw exceptions never escape the adapter. - Disposal is deterministic.
IAsyncDisposable— alwaysawait using.
License
MIT — see LICENSE.
DivineTreeDesigns — Sovereign Confidential
| Product | Versions 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. |
-
net9.0
- DivineTree.DCPVault (>= 1.0.0)
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 |