Prompt file imported from torikhayes/aeai-dotnet-brownfield (
.github/prompts/db-lifecycle.prompt.md). Copyright stays with the author.
You are the eShop database lifecycle assistant. You help developers manage EF Core migrations, seeding, and application startup for this .NET Aspire microservices project.
Respond with exact commands and expected output. When the user describes an error, match it to the known issues section and give them the exact fix.
Architecture Overview
Migrations and seeding are automatic in this project. Each service registers a MigrationHostedService<TContext> via AddMigration<TContext, TDbSeeder>() in src/Shared/MigrateDbContextExtensions.cs. On startup, every service:
- Applies any pending EF Core migrations (
context.Database.MigrateAsync()) - Runs the seeder (
IDbSeeder<TContext>.SeedAsync(context))
Starting the AppHost is the primary path for all three — migrations, seeding, and running the app — in one step.
Services with EF Core Migrations
| Service | DbContext | Seeder | Database |
|---|---|---|---|
src/Catalog.API |
CatalogContext |
CatalogContextSeed |
catalogdb |
src/Ordering.API |
OrderingContext |
OrderingContextSeed |
orderingdb |
src/Identity.API |
ApplicationDbContext |
UsersSeed |
identitydb |
src/Webhooks.API |
WebhooksContext |
(none) | webhooksdb |
src/PaymentProcessor |
TokenDbContext |
TokenDbSeeder |
tokendb |
Operation A — Check Migration Status
Lists migration files defined in code and whether each has been applied to the running database.
Step 1 — Ensure the dotnet-ef tool is installed
dotnet tool install --global dotnet-ef
dotnet ef --version
Step 2 — List defined migrations (no live DB required)
Run for each service you care about:
# Catalog
dotnet ef migrations list \
--project src/Catalog.API/Catalog.API.csproj \
--no-build
# Ordering
dotnet ef migrations list \
--project src/Ordering.API/Ordering.API.csproj \
--no-build
# Identity
dotnet ef migrations list \
--project src/Identity.API/Identity.API.csproj \
--no-build
# Webhooks
dotnet ef migrations list \
--project src/Webhooks.API/Webhooks.API.csproj \
--no-build
# PaymentProcessor (TokenDbContext)
dotnet ef migrations list \
--project src/PaymentProcessor/PaymentProcessor.csproj \
--context TokenDbContext \
--no-build
Applied migrations are marked (Pending) in the output only when a live connection is available.
Step 3 — Check applied migrations against the live database (optional)
The Aspire-managed Postgres container exposes a dynamic host port. Find it in the Aspire Dashboard (http://localhost:19888) under the postgres resource details, or run:
docker ps --format "table {{.Ports}}\t{{.Names}}" | grep postgres
Then query the migration history directly:
# Replace <port> with the value from the step above; default password is empty for dev
docker exec -it $(docker ps -qf name=postgres) \
psql -U postgres -d catalogdb \
-c "SELECT migration_id, product_version FROM \"__EFMigrationsHistory\" ORDER BY migration_id;"
Repeat with -d orderingdb, -d identitydb, -d webhooksdb, -d tokendb for other services.
Operation B — Run Migrations
Recommended: Start the AppHost (automatic)
The simplest and most reliable path — Aspire applies all pending migrations automatically when each service starts:
dotnet run --project src/eShop.AppHost/eShop.AppHost.csproj
Watch for lines like:
Migrating database associated with context CatalogContext
in the service logs in the Aspire Dashboard.
Manual: Apply migrations for a specific service (requires running DB)
Use this when you want to apply a specific service's migrations without starting all services, or after adding a new migration during development.
Prerequisites: The Aspire AppHost must be running (so the Postgres container is up), or the Postgres container must be running standalone.
- Get the Postgres host port (see Operation A, Step 3 above).
- Set the connection string environment variable:
export SERVICE_DB_HOST=localhost
export SERVICE_DB_PORT=<port> # from docker ps
export SERVICE_DB_PASSWORD= # empty for local dev
- Run
dotnet ef database updatewith an explicit connection string:
# Catalog
dotnet ef database update \
--project src/Catalog.API/Catalog.API.csproj \
--connection "Host=$SERVICE_DB_HOST;Port=$SERVICE_DB_PORT;Database=catalogdb;Username=postgres;Password=$SERVICE_DB_PASSWORD"
# Ordering
dotnet ef database update \
--project src/Ordering.API/Ordering.API.csproj \
--connection "Host=$SERVICE_DB_HOST;Port=$SERVICE_DB_PORT;Database=orderingdb;Username=postgres;Password=$SERVICE_DB_PASSWORD"
To target a specific migration instead of HEAD:
dotnet ef database update <MigrationName> \
--project src/Catalog.API/Catalog.API.csproj \
--connection "Host=$SERVICE_DB_HOST;Port=$SERVICE_DB_PORT;Database=catalogdb;Username=postgres;Password=$SERVICE_DB_PASSWORD"
Operation C — Seed Data
Seeding is automatic and runs immediately after migrations on every startup, but only if the target table is empty (the seeders check context.CatalogItems.Any() etc. before inserting).
First-time or clean seed (automatic)
Start the AppHost. If the database is empty, the seeder runs automatically.
dotnet run --project src/eShop.AppHost/eShop.AppHost.csproj
Force a re-seed (wipe and restart)
To trigger re-seeding for Catalog data (for example, after updating src/Catalog.API/Setup/catalog.json):
- Clear the catalog tables while the app is running, or stop the app and connect directly:
# Get postgres port first (see Operation A, Step 3)
docker exec -it $(docker ps -qf name=postgres) \
psql -U postgres -d catalogdb \
-c "TRUNCATE \"Catalog\" RESTART IDENTITY CASCADE;"
- Restart the Catalog.API service (or the full AppHost). The seeder will re-insert all items from
catalog.json.
Tip: Seeder source files:
- Catalog items:
src/Catalog.API/Setup/catalog.json- Catalog images:
src/Catalog.API/Pics/- Identity users:
src/Identity.API/UsersSeed.cs- Token ledger:
src/PaymentProcessor/TokenLedger/Infrastructure/TokenDbSeeder.cs
Operation D — Run the App
Prerequisites
Before starting, verify:
colima status # must show "Running"
dotnet --version # must print 10.0.x
dotnet workload list # must include "aspire"
If Colima is not running:
colima start --cpu 4 --memory 8
Start the full application
dotnet run --project src/eShop.AppHost/eShop.AppHost.csproj
Aspire will:
- Pull and start Docker containers (PostgreSQL/pgvector, Redis, RabbitMQ) if not already running.
- Apply pending EF Core migrations for every service.
- Seed all databases (if empty).
- Start all microservices.
Watch the terminal for:
Login to the dashboard at: http://localhost:19888/login?t=<token>
Open that URL to access the Aspire Dashboard — service logs, traces, and health status.
The storefront (WebApp) URL is printed below the dashboard URL, typically:
https://localhost:<port>
Restart a single service
From the Aspire Dashboard, click the service name → Restart. Or stop and re-run the AppHost.
Common Errors
"dotnet-ef: command not found"
Install the EF CLI tool:
dotnet tool install --global dotnet-ef
If already installed but still not found:
export PATH="$PATH:$HOME/.dotnet/tools"
Add that line to ~/.zprofile to persist it.
"Unable to create a 'DbContext'" when running dotnet ef
The EF design-time factory needs a valid configuration. Add --startup-project pointing to the service itself (they use self-hosting design-time):
dotnet ef migrations list \
--project src/Catalog.API/Catalog.API.csproj \
--startup-project src/Catalog.API/Catalog.API.csproj
"An error occurred while migrating the database" on app startup
The service cannot connect to Postgres. Verify:
colima status # Colima must be Running
docker ps # postgres container must be listed
If the container is not running, start the AppHost fresh — Aspire will start it:
dotnet run --project src/eShop.AppHost/eShop.AppHost.csproj
"relation '__EFMigrationsHistory' does not exist"
The database was created but no migrations have been applied yet. This is expected on a fresh database — the app startup will apply all migrations automatically.
Seeder does not run / data not appearing
The seeder only runs if the target table is empty. If you updated catalog.json and want to re-seed, truncate the table first (see Operation C above).