Docker
Run the app and its database as containers — one profile per DatabaseProvider, no local .NET SDK or database install required.
Quick Start
docker-compose.yml (repo root) defines a db-<provider> / app-<provider> service pair for each supported database, selected with a Compose profile:
cp .env.example .env # set real passwords/secrets first
docker compose --profile sqlserver up --build # or: postgres / mysql / sqlite
The app is then at http://localhost:8080. Program.cs runs its usual startup sequence inside the container exactly as it does locally — migrations apply and seed data loads automatically (see Database Setup) — so there’s no separate migration step to run.
Every app-* service publishes the same host port (APP_PORT, default 8080). Stop one profile (docker compose --profile <name> down) before starting another.
Profiles
| Profile | Containers started | Notes |
|---|---|---|
sqlserver | db-sqlserver + app-sqlserver | mcr.microsoft.com/mssql/server:2022-latest. Matches the project default. |
postgres | db-postgres + app-postgres | postgres:16-alpine. |
mysql | db-mysql + app-mysql | mysql:8.4. On a first-ever boot the official MySQL image runs a temporary initialization server before the real one; the healthcheck pings over TCP (-h 127.0.0.1) so it only reports healthy once the real server is accepting connections, and the app starts cleanly on its first attempt. |
sqlite | app-sqlite only | No database container — the .sqlite3 file lives in the sqlite_data named volume at /app/data. |
Each database container has a real healthcheck (sqlcmd/pg_isready/mysqladmin ping), and the app service waits for it (depends_on: condition: service_healthy) before its first migration attempt.
On a brand-new PostgreSQL database, the first startup logs one fail: Microsoft.EntityFrameworkCore.Database.Command entry for a SELECT ... FROM "__EFMigrationsHistory" query. That is EF Core checking for its migrations table before creating it; the migration is applied immediately afterwards and the message does not appear on later startups.
Persisted Data
Named volumes keep data across container recreation:
sqlserver_data/postgres_data/mysql_data/sqlite_data— whichever provider’s data directory / database file.uploads_data— mounted at /app/wwwroot/content/images, shared by everyapp-*service. This is where the image-upload actions (SharedController) write product/category/slider pictures and user avatars at runtime, so they survive rebuilding or recreating the app container. Only image files (.jpg,.jpeg,.png,.gif,.webp) are accepted, from signed-in users only (Administrators for slider images).
Configuration
Copy .env.example to .env and set real values before running anything beyond a quick local try — .env is gitignored.
| Variable | Used by | Purpose |
|---|---|---|
APP_PORT | all app-* | Host port the app is published on (container always listens on 8080). |
ASPNETCORE_ENVIRONMENT | all app-* | Standard ASP.NET Core environment (Development shows detailed error pages). |
APP_ENVIRONMENT | all app-* | Maps to the app’s own Environment config key (LIVE/other) — see Go-Live Checklist. Separate from ASPNETCORE_ENVIRONMENT. |
JWT_KEY | all app-* | Signing key for the API area’s JWTs (Jwt:Key). Generate a real secret for anything beyond local testing. |
SA_PASSWORD, SQLSERVER_PORT | sqlserver profile | SQL Server sa password and published port. |
POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_PORT | postgres profile | Standard Postgres image variables. |
MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, MYSQL_ROOT_PASSWORD, MYSQL_PORT | mysql profile | Standard MySQL image variables. |
Reference: Files
| File | Purpose |
|---|---|
docker-compose.yml | Repo root. All eight services (four db-* + four app-*) and their profiles, volumes, and env vars. |
eCommerceMVCCore/Dockerfile | Multi-stage build (SDK → publish → aspnet runtime). One image (ecommercemvc-web:latest) is shared by all four app-* services — only the runtime env vars differ per provider. |
eCommerceMVCCore/docker-entrypoint.sh | The image’s entrypoint. With docker-compose it simply starts the app. Optional: on a host that can’t mount a volume onto wwwroot/content/images but keeps some other folder (e.g. Azure App Service’s /home), set PERSISTENT_IMAGES_PATH to that folder and uploaded pictures are kept there across restarts. |
eCommerceMVCCore/.dockerignore | Excludes bin/, obj/, .vs/, etc. from the build context. |
.env.example | Repo root. Template for .env — every variable above, with placeholder values. |