Skip to content

.NET Todos

A REST API for managing todos, built with C#/ASP.NET and PostgreSQL. Demonstrates deploying a database-backed .NET application on AppMecca with Entity Framework Core.

Overview

Repository git@gitlab.com:appmecca-sample-apps/dotnet-todos.git
Tech Stack .NET 9 / ASP.NET Minimal API / EF Core / Npgsql
Services api (port 8080)
Database Yes
Cache None
URL Pattern https://dotnet-todos-api.{env}.appmecca.net

What This App Demonstrates

  • Deploying a database-backed .NET application on AppMecca
  • Entity Framework Core with code-first schema management
  • Npgsql connection strings for PostgreSQL
  • REST API with full CRUD operations against PostgreSQL
  • The database: enabled: true configuration pattern

appmecca.yaml

containers:
  - name: api
    dockerfile: Dockerfile
    context: .

deploy:
  - name: api
    container: api
    port: 8080
    health_check:
      path: /health

database:
  enabled: true

The only addition compared to Hello .NET is database: enabled: true. AppMecca provisions a PostgreSQL database on first deploy and injects DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD, and DATABASE_URL into the container automatically. Read these from the environment — the database and user names are generated identifiers, not derived from the app name.

Step-by-Step Deployment

1. Register the app

mecca register git@gitlab.com:appmecca-sample-apps/dotnet-todos.git -e dev

2. Build the container

mecca build trigger -e dev -g git@gitlab.com:appmecca-sample-apps/dotnet-todos.git
Expected output
Build started: build-xxxxxxxx
Cloning repository...
Building container: api
Pushing image to the private registry: dotnet-todos/api
Build complete. Duration: 70s

3. Deploy

mecca app deploy -e dev dotnet-todos
Expected output
Deploying dotnet-todos to dev...
Deployment queued: deploy-xxxxxxxx
Waiting for agents...
Container started: dotnet-todos-api
Health check passed: /health -> 200 OK
Deployment complete.

Services:
  api: https://dotnet-todos-api.dev.appmecca.net

4. Verify

mecca queue status takes the action ID printed when you deployed. To look up the app itself — including the exact URL for your group — use mecca app show:

mecca app show dotnet-todos -e dev

Test the API:

# Health check
curl https://dotnet-todos-api.dev.appmecca.net/health
{"status": "healthy"}
# Create a todo
curl -X POST https://dotnet-todos-api.dev.appmecca.net/api/todos \
  -H "Content-Type: application/json" \
  -d '{"title": "Deploy more apps", "done": false}'

# List all todos
curl https://dotnet-todos-api.dev.appmecca.net/api/todos

# Update a todo
curl -X PUT https://dotnet-todos-api.dev.appmecca.net/api/todos/1 \
  -H "Content-Type: application/json" \
  -d '{"done": true}'

# Delete a todo
curl -X DELETE https://dotnet-todos-api.dev.appmecca.net/api/todos/1

API Endpoints

Method Path Description
GET /health Health check
GET /api/todos List all todos
POST /api/todos Create a todo
PUT /api/todos/:id Update a todo
DELETE /api/todos/:id Delete a todo

Key Concepts

Entity Framework Core (code-first schema)

Entity Framework Core (EF Core) uses a code-first approach where the database schema is derived from C# model classes. You define a Todo class with properties like Id, Title, and Done, and a DbContext that exposes DbSet<Todo>. EF Core generates and applies migrations with dotnet ef migrations add and Database.Migrate() at startup. The entrypoint calls Database.EnsureCreated() or applies pending migrations automatically.

.NET connection strings (Npgsql format)

.NET applications use Npgsql as the PostgreSQL provider for EF Core. The connection string is built from the APPMECCA-injected environment variables:

Host={DB_HOST};Port={DB_PORT};Database={DB_NAME};Username={DB_USER};Password={DB_PASSWORD}

The application reads DB_HOST, DB_PORT, DB_NAME, DB_USER, and DB_PASSWORD from the environment and constructs the connection string at startup. Alternatively, DATABASE_URL can be parsed into the Npgsql format.

Any language, same workflow

AppMecca does not care what language your application is written in. As long as your container listens on the declared port and responds to health checks, the deployment workflow is identical.

What's Next?