Memoria Web shows you a store through your own domain types. To try it before you
have either — or to see what a store with something interesting in it looks like — the repository
ships Memoria.Web.Samples.
It does two jobs on purpose:
The types the tool displays are the types the seeder exercises, so nothing reaches the tool that was never written through Memoria first.
Five steps, and about five minutes:
The connection string is ConnectionStrings:Memoria in
src/Memoria.Web.Samples/appsettings.json.
As checked in, it is a local PostgreSQL database called memoria_samples:
{
"ConnectionStrings": {
"Memoria": "Host=localhost;Port=5432;Database=memoria_samples;Username=postgres;Password=password"
}
}
Any of the four engines works. The string itself says which one — the resolution is the tool’s own
DatabaseConnection,
compiled into both, so a string that reaches one reaches the other. See
which engine it is for the keywords and for
Database:Provider.
| Engine | Example |
|---|---|
| PostgreSQL | Host=localhost;Port=5432;Database=memoria_samples;Username=postgres;Password=password |
| SQL Server | Server=(localdb)\\MSSQLLocalDB;Initial Catalog=memoria_samples;Trusted_Connection=True |
| SQLite | Data Source=memoria_samples.db |
| Cosmos DB | AccountEndpoint=https://localhost:8081/;AccountKey=<emulator key> |
For Cosmos, set the database and container as well, and start the emulator first — the run stops with “Could not reach the database” before asking anything otherwise:
{
"Database": {
"Cosmos": {
"DatabaseName": "memoria_samples",
"ContainerName": "Domain"
}
}
}
You do not have to edit the file. Every setting can be overridden on the command line, which is how to point one run at a scratch store:
dotnet run --project src/Memoria.Web.Samples -- \
"--ConnectionStrings:Memoria=Data Source=scratch.db"
Unlike the tool, the seeder creates what is missing before it writes: the database and each store’s tables on a relational engine, the database and the container on Cosmos.
dotnet run --project src/Memoria.Web.Samples
Memoria.Web.Samples
store : Npgsql
writing : memoria_samples
bound : 28 events, 4+4 aggregates, 3+5 projections (streamed+dcb)
schema : installed
It then asks two questions, answered by number on standard input:
| Answer | Action |
|---|---|
1 |
Add — writes alongside whatever is already there |
2 |
Replace — empties the store, then writes |
3 |
Delete — empties the store and writes nothing |
| (none) | Nothing chosen; the run stops without touching a row |
Then, only when the store holds both models, which data to write: 1 streamed, 2 DCB, 3
both. A Cosmos store holds the streamed model only, so it is never asked there.
End of input counts as an answer — it means nobody is there to answer — so a piped run works and an unattended one stops rather than hanging:
echo "2" | dotnet run --project src/Memoria.Web.Samples
Exit code 0 means the run finished, including a run where nothing was chosen; 1 means the store
could not be reached and nothing was written.
Streamed — customers, the orders they place, and the reviews products collect. Every order is
driven through the Order aggregate’s own methods, so the log holds only sequences the domain would
have allowed. Some reviews go through ProductReviewV1 rather than ProductReview, so the store
ends up holding snapshots of two shapes of one model side by side.
DCB — a catalogue, stock for it, orders holding some of that stock, and the purchase orders that restock it. Every append follows the read-decide-append cycle on condition that the boundary has not moved, the way an application would write it.
Snapshots are deliberately left in three states, because a store where everything is current has nothing to demonstrate:
| State | How it is reached |
|---|---|
| Up to date | Snapshotted after the last event on its stream |
| Behind | Snapshotted, then more events appended without snapshotting again |
| No snapshot | Events appended and never snapshotted |
The run ends by listing every model it wrote and where its snapshot stands, so you know which rows have an Update waiting for them in the tool:
store kind model identifier values snapshot
streamed aggregate Order OrderId o-5b0f v4, up to date
streamed aggregate CustomerAccount CustomerAccountId c-37e7 v2 of 6 — 4 behind
streamed projection OrderSummary OrderSummaryId o-a6f6 no snapshot — 2 events waiting
The tool has no reference to this project — it reads uploaded assemblies and nothing else. So build it and zip the assembly on its own:
dotnet build src/Memoria.Web.Samples --configuration Release
Compress-Archive -Path src\Memoria.Web.Samples\bin\Release\net10.0\Memoria.Web.Samples.dll `
-DestinationPath Memoria.Web.Samples.zip -Force
# bash
cd src/Memoria.Web.Samples/bin/Release/net10.0 && zip ~/Memoria.Web.Samples.zip Memoria.Web.Samples.dll
The archive holds Memoria.Web.Samples.dll and nothing else. Never put a Memoria* core assembly in
it — see what to put in a zip.
Give src/Memoria.Web/appsettings.json the same connection string the seeder used — and, on Cosmos,
the same database and container names, or the tool opens a container the seeder never filled.
dotnet run --project src/Memoria.Web
Then open http://localhost:5159.
Go to Settings → Installed → Upload, choose the zip, and upload it. The page reports what registered; Settings → Types counts it per model. Nothing restarts.
Things worth opening first:
ProductReview sit here under one name, because
some reviews were written through ProductReviewV1. The version column is what tells them apart.Cosmos holds the streamed model only. There is no Cosmos dynamic consistency boundary store, and the model would not build on that provider if there were. A Cosmos run is never offered the DCB half rather than being offered it and refused on the first write.
In-memory SQLite is refused. Data Source=:memory: lives only as long as the connection that
opened it, and both the seeder and the tool open a connection per unit of work — they would find an
empty store rather than the one that was seeded. Point them at a file.
Do not upload the samples alongside Memoria.Examples.Ecommerce.Dcb. Both claim the event types
ProductCreated, ProductDeleted and ProductDetailsChanged at version 1, and the DCB aggregate
Product at version 1. Whichever loses the name loses its bindings, and its pages then report no
events inside the boundary. Remove one archive before uploading the other.
A version bump means a rebuild. The assembly is compiled against the <Version> in
Directory.Build.props.
One built against an older version still loads, and then contributes no types at all.
| Path | What is in it |
|---|---|
Streamed/ |
The streamed model: streams, aggregates, projections, events |
Dcb/ |
The dynamic consistency boundary model: aggregates, projections, events |
Seeding/ |
The run itself — the menu, the store it writes to, and the data |
Data/ |
The two contexts a relational store is written through |