-
Notifications
You must be signed in to change notification settings - Fork 0
DI and Configuration
AddDynamoDbLite registers IAmazonDynamoDB as a singleton built from a validated SQLite connection string. This page covers the registration surface, the builder, the options record, and the exception type — everything that sits between your composition root and a working DynamoDbClient.
The DI surface lives in the DynamoDbLite namespace inside the main package — there is no separate DynamoDbLite.DependencyInjection package.
-
AddDynamoDbLite— the only registration extension. -
DynamoDbLiteOptionsBuilder— fluent builder with up-front validation. -
DynamoDbLiteOptions— the configuration record. -
DynamoDbLiteConfigurationException— thrown on misconfiguration.
public static IServiceCollection AddDynamoDbLite(
this IServiceCollection services,
Action<DynamoDbLiteOptionsBuilder> configure)One overload. configure receives a fresh builder; the extension calls Build immediately and registers the resulting DynamoDbClient as a singleton IAmazonDynamoDB via TryAddSingleton. Existing registrations are preserved.
Validation is eager. If configure does not call WithConnectionString, or the supplied connection string is invalid, Build throws DynamoDbLiteConfigurationException synchronously — at AddDynamoDbLite time, not at first resolution. This surfaces misconfiguration during host startup rather than during the first request.
using DynamoDbLite;
builder.Services.AddDynamoDbLite(o =>
o.WithConnectionString("Data Source=myapp.db"));public DynamoDbLiteOptionsBuilder WithConnectionString(string connectionString)Validates connectionString and stores it on the builder. Throws DynamoDbLiteConfigurationException when the input is null, empty, whitespace, or fails to parse as a SQLite connection string.
public DynamoDbLiteOptionsBuilder WithWriteAheadLog()Enables SQLite Write-Ahead Logging on file-backed stores. Off by default — call this to opt in. WAL lets readers proceed while a writer holds the write lock, which materially improves reader-writer concurrency on file-backed stores.
Has no effect on in-memory stores. SQLite does not support WAL for :memory: databases and silently falls back to the memory journal mode.
WAL is persistent on the database file once enabled. Disabling later requires an explicit PRAGMA journal_mode=DELETE outside this library.
public DynamoDbLiteOptionsBuilder WithMaxBatchWriteItems(int maxBatchWriteItems)Sets the maximum number of put/delete requests a single BatchWriteItemAsync call accepts. Defaults to 25 — the limit the real DynamoDB client enforces. Raise it to seed more rows per call than DynamoDB allows in production; lower it to tighten the cap. Throws DynamoDbLiteConfigurationException when the value is less than 1.
builder.Services.AddDynamoDbLite(o => o
.WithConnectionString("Data Source=myapp.db")
.WithMaxBatchWriteItems(100));The cap governs only request-size validation — it does not change how writes map to SQLite or how the call batches them. See BatchWriteItemAsync for the operation itself.
public DynamoDbLiteOptionsBuilder WithPragma(string name, string value)Adds a SQLite pragma applied to every connection the client opens for an operation, after the library's own pragmas (synchronous=NORMAL, temp_store=MEMORY). Repeatable — each call adds one PRAGMA name=value;. Entries run in call order, so a later call for the same pragma wins.
The client's classic use is write-lock contention on file-backed stores:
builder.Services.AddDynamoDbLite(o => o
.WithConnectionString("Data Source=myapp.db")
.WithWriteAheadLog()
.WithPragma("busy_timeout", "5000"));busy_timeout is how long, in milliseconds, a connection waits on a write lock held by another connection before failing with SQLITE_BUSY. It matters for file-backed stores under writer contention; it is inert for in-memory stores, where shared-cache conflicts (SQLITE_LOCKED_SHAREDCACHE) bypass the busy handler and the command-timeout retry serializes writers instead. Pragmas apply uniformly to both store types — the library does not filter by pragma or store type. Picking pragmas that suit your store is your call; consult the SQLite PRAGMA reference. See Concurrency for how the wait is governed per store type.
Values are validated for injection safety, because pragma values cannot be parameterized. A name must be a SQLite identifier ([A-Za-z_][A-Za-z0-9_]*) and a value must be a signed integer (5000, -16000) or a bare keyword (NORMAL, WAL, ON). Anything else — string-valued pragmas, custom functions — throws DynamoDbLiteConfigurationException; use WithConnectionInitializer for those.
public DynamoDbLiteOptionsBuilder WithConnectionInitializer(Action<SqliteConnection> configure)Sets a callback invoked on every connection the client opens for an operation, after any WithPragma pragmas. The connection is open; run any setup the SQLite provider supports — pragmas that WithPragma won't take, custom functions, collations. This is the unrestricted escape hatch.
builder.Services.AddDynamoDbLite(o => o
.WithConnectionString("Data Source=myapp.db")
.WithConnectionInitializer(conn =>
{
using var cmd = conn.CreateCommand();
cmd.CommandText = "PRAGMA busy_timeout=5000;";
cmd.ExecuteNonQuery();
}));SQLite executes synchronously under Microsoft.Data.Sqlite, so synchronous command execution in the callback is fine. The callback runs only on per-operation connections, not on the transient connections used for schema creation, the one-time WAL enable, or the in-memory keep-alive. Because it runs on each pooled open, keep it cheap. Calling this more than once replaces the previous callback; throws ArgumentNullException on a null callback.
Per-connection application order is: library defaults → WithPragma pragmas → this callback. The callback runs last, so it has the final say.
Build is internal — AddDynamoDbLite is the only caller. If WithConnectionString was not called before Build, it throws DynamoDbLiteConfigurationException with the message:
Connection string was not configured. Call WithConnectionString before Build.
public sealed record DynamoDbLiteOptions(string ConnectionString, bool UseWriteAheadLog = false)
{
public int MaxBatchWriteItems { get; init; } = 25;
public IReadOnlyList<KeyValuePair<string, string>> Pragmas { get; init; } = [];
public Action<SqliteConnection>? ConnectionInitializer { get; init; }
}A positional record with one required parameter, one optional flag, and three optional init-only members. The positional constructor is unchanged, so existing new DynamoDbLiteOptions(...) calls keep working.
-
ConnectionString— required. No default; consumers opt in to either an in-memory or file-based store. See Getting Started for the connection string forms and the in-memory naming foot-gun. -
UseWriteAheadLog— optional, defaults tofalse. Enables SQLite Write-Ahead Logging on file-backed stores; no effect on in-memory stores. The builder equivalent is WithWriteAheadLog — same contract, including the note that WAL is persistent on the file once enabled. -
MaxBatchWriteItems— optional, defaults to25. Caps the put/delete requests a singleBatchWriteItemAsyncaccepts, matching DynamoDB's limit; raise it to exceed that limit in tests, or lower it to tighten the cap. The builder equivalent is WithMaxBatchWriteItems, which additionally rejects values below1. Direct construction with a non-positive value is not re-validated — a value of0or less rejects every batch. -
Pragmas— optional, defaults to empty. Per-connection pragmas applied after the library's own and beforeConnectionInitializer; same injection-safe validation as the builder. The builder equivalent is WithPragma. -
ConnectionInitializer— optional, defaults tonull. Callback run on each operational connection afterPragmas. The builder equivalent is WithConnectionInitializer.
Setting Pragmas or ConnectionInitializer directly via the record is equivalent to the builder calls; the builder simply accumulates them. Direct construction skips the builder's eager validation, but Pragmas are re-validated when the client is constructed, so a malformed pragma still throws DynamoDbLiteConfigurationException at that point.
The connection string follows Microsoft.Data.Sqlite connection string format. The library applies ForeignKeys=true when you leave it unset and otherwise uses the string as written — Mode and Pooling are preserved. Honoring Mode is what lets Mode=Memory select an in-memory store instead of being rewritten to a file.
public sealed class DynamoDbLiteConfigurationException : ExceptionThrown by WithConnectionString and Build on the conditions documented above. Carries the standard Exception shape — message, inner exception when wrapping a SqliteConnectionStringBuilder parse failure, no extra state.
Catch this type at composition-root level to surface configuration problems with a clear message; do not catch it at request time, since misconfiguration has already crashed startup.
DynamoDbClient accepts the same DynamoDbLiteOptions record without DI:
using var client = new DynamoDbClient(new DynamoDbLiteOptions(
"Data Source=myapp.db"));See Getting Started for the full direct-instantiation walkthrough including in-memory naming.
IConfiguration-based registration is not implemented today. Bind your config to a string and pass it through WithConnectionString:
builder.Services.AddDynamoDbLite(o =>
o.WithConnectionString(builder.Configuration["DynamoDbLite:ConnectionString"]
?? throw new InvalidOperationException("DynamoDbLite:ConnectionString missing")));- Getting Started — installation and the full setup walkthrough
-
Performance — when to use
WithWriteAheadLogandWithPragma, and which knobs move write throughput - FAQ — connection string and configuration gotchas
-
API Parity — what
IAmazonDynamoDBsurface is supported
Repo · NuGet · API Parity
Getting started
Reference
- Table Operations
- Item Operations
- Query and Scan
- Batch Operations
- Transactions
- Secondary Indexes
- TTL
- Tags and Admin
- DI and Configuration
- Concurrency
- Performance
- API Parity
- FAQ
Recipes
- DynamoDBContext for tests
- xUnit per-test isolation
- ASP.NET Core integration test fixture
- Migrating tests off DynamoDB Local
Internals