A comprehensive .NET Aspire-based web application for exploring Pokémon data with an interactive UI, real-time caching, and full Azure deployment support.
Live Demo: pokepedia-dev-web.azurecontainerapps.io (when deployed (currently not deployed as it cost money lol))
- 🎨 Interactive UI: Light/dark theme toggle, interactive ability cards, evolution charts
- ⚡ High Performance: Multi-tier caching (Redis + in-memory) for API responses
- 🔄 Real-time Updates: Responsive Blazor components with streaming data
- 📊 Advanced Filtering: Filter Pokémon by type, rarity (legendary/mythical), region
- 🎯 Detailed Information: Comprehensive Pokémon stats, abilities, evolution chains
- 📈 Production Ready: Full observability via Application Insights + OpenTelemetry
- 🚀 Cloud Deployment: Single-click Azure deployment with Bicep/Terraform
- 💾 Data Caching: Automatic warmup on startup for ~1,025 Pokémon species
- .NET 10 SDK (Download)
- .NET Aspire (installed with .NET 10)
- Docker Desktop (Download)
- Git (Download)
- Azure CLI (Install)
- Bicep CLI (included with Azure CLI 2.20.0+)
- Terraform (Download) - only for Terraform deployments
- Active Azure Subscription
# Check .NET SDK
dotnet --version
# Check Docker
docker --version
# Check Aspire (optional - will auto-install when needed)
dotnet workload listgit clone https://github.com/Hana-fubuki/PokemonEncyclopedia.git
cd PokemonEncyclopedia# Restore all NuGet packages
dotnet restore# Build in debug mode
dotnet build
# Or build with optimizations
dotnet build -c ReleaseThe Aspire Dashboard provides a unified view of all services, logs, and resource monitoring.
# Start the application with dashboard
dotnet run --project PokemonEncyclopedia.AppHost
# The dashboard will automatically open at: http://localhost:18629Dashboard provides:
- Real-time service status and logs
- Resource monitoring (CPU, memory, container stats)
- Service dependencies and communication flow
- Health check status
- Direct access to service URLs
If you prefer to run services separately:
# Terminal 1: Start Docker containers (Redis, Cosmos DB Emulator)
docker-compose -f docker-compose.yml up -d
# Terminal 2: Start API Service
dotnet run --project PokemonEncyclopedia.ApiService
# Terminal 3: Start Web Service
dotnet run --project PokemonEncyclopedia.WebThen access:
- Web Application: http://localhost:5173
- API Service: http://localhost:5000
- Swagger UI: http://localhost:5000/swagger
- Scalar API Docs: http://localhost:5000/scalar
When running locally with Aspire:
| Service | URL | Description |
|---|---|---|
| Web Frontend | http://localhost:5173 | Main Blazor application |
| API Service | http://localhost:5000 | RESTful API |
| Swagger UI | http://localhost:5000/swagger | API documentation (development only) |
| Scalar Docs | http://localhost:5000/scalar | Modern API documentation |
| Hangfire Dashboard | http://localhost:5000/hangfire | Background job monitoring |
| Health Check | http://localhost:5000/health | Service health status |
| Aspire Dashboard | http://localhost:18629 | Orchestration dashboard |
┌─────────────────────────────────────────────────────────────┐
│ Docker Network (Local) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Web App │ │ API Service │ │ Redis │ │
│ │ (Blazor) │──│ (.NET 10) │──│ Cache │ │
│ │ │ │ │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Cosmos DB │ │
│ │ Emulator │ │
│ │ (Hangfire) │ │
│ └──────────────┘ │
│ │
│ External APIs: │
│ • PokéAPI (https://pokeapi.co) │
│ │
└─────────────────────────────────────────────────────────────┘
-
PokemonEncyclopedia.Web - Blazor interactive web frontend
- Razor components with interactive server rendering
- Real-time filtering and search
- Theme persistence (light/dark mode)
-
PokemonEncyclopedia.ApiService - RESTful API backend
- Pokémon data retrieval and caching
- Ability/form/move endpoints
- Hangfire background job orchestration
- Health checks and monitoring
-
PokemonEncyclopedia.Application - Business logic
- MediatR handlers for CQRS pattern
- Domain models and entities
-
PokemonEncyclopedia.Infrastructure - Data access
- Repository patterns
- Redis cache implementation
- Cosmos DB integration
-
PokemonEncyclopedia.ServiceDefaults - Shared configuration
- OpenTelemetry setup
- Service discovery
- Health checks
-
PokemonEncyclopedia.AppHost - Aspire orchestration
- Service composition
- Resource configuration (Redis, Cosmos DB)
- Environment variable management
Swagger UI (traditional):
# Navigate to http://localhost:5000/swaggerScalar (modern, recommended):
# Navigate to http://localhost:5000/scalar# From Aspire Dashboard
# Click the service card and select "Restart"
# Or restart all from command line
dotnet run --project PokemonEncyclopedia.AppHost# In Aspire Dashboard:
# - Click "Logs" tab
# - Select service from dropdown
# - View real-time logs
# Or via CLI:
docker logs <container-name># Connect to Redis
docker exec -it pokemonencyclopedia-redis redis-cli
# View cache keys
> KEYS *
# Get a value
> GET pokemon:1
# Clear cache
> FLUSHDBThe Cosmos DB emulator runs on https://localhost:8081 with the following credentials:
- Endpoint: https://localhost:8081
- Key: C2y6yDjf5/R+ob0N8UZrLJWJRY4IQstsSiP1ADAcgGQ=
To explore data:
# Cosmos DB Data Explorer opens at https://localhost:8081/_explorer/index.html# Run all tests
dotnet test
# Run specific project tests
dotnet test PokemonEncyclopedia.Tests
# Run with detailed output
dotnet test --logger "console;verbosity=detailed"
# Run with code coverage
dotnet test /p:CollectCoverage=true# Stop all services
dotnet stop # Only if using Aspire AppHost
# Stop Docker containers
docker-compose down
# Stop and remove all containers
docker-compose down -v
# Clean build artifacts
dotnet cleanOn startup, the API service automatically:
- Caches all Pokémon (~1,025 species) from PokéAPI
- Caches all Moves (~900) with names and URLs
- Caches all Abilities (~300+) for interactive cards
- Stores in Redis with appropriate TTL (24 hours)
- Falls back to in-memory cache if Redis unavailable
This warmup typically takes 15-30 seconds on first run. Subsequent starts are much faster as Redis persists data.
Warmup status: Check the Aspire Dashboard or API logs for Pokemon catalog warmup completed message.
| Variable | Value | Purpose |
|---|---|---|
ASPNETCORE_ENVIRONMENT |
Development |
Enable dev features (Swagger, detailed errors) |
DEPLOYMENT_MODE |
local |
Use local Docker containers instead of Azure |
REDIS_ENDPOINT |
localhost:6379 |
Redis cache connection |
COSMOS_CONNECTION_STRING |
Cosmos DB emulator | Hangfire job backend |
See infra/README.md for Azure-specific configuration.
# Windows: Start Docker Desktop from Applications
# macOS: Open Docker.app from Applications
# Linux: Start Docker service
sudo systemctl start docker# Find process using port
netstat -ano | findstr :5000
# Kill the process (Windows, replace PID)
taskkill /PID <PID> /F
# Or use a different port
dotnet run --project PokemonEncyclopedia.Web -- --urls "http://localhost:5174"# Check if Redis container is running
docker ps | grep redis
# Check Redis logs
docker logs pokemonencyclopedia-redis
# Restart Redis
docker restart pokemonencyclopedia-redis
# Or rebuild from scratch
docker-compose down -v && docker-compose up -d# Check if Cosmos emulator is running
docker ps | grep cosmos
# Check logs
docker logs pokemonencyclopedia-cosmos
# Increase available disk space (emulator needs ~1GB)
# Restart Docker and increase resource limits
# Access Cosmos Data Explorer (verify it's running)
# https://localhost:8081/_explorer/index.html# Verify Aspire is running
# Check if port 18629 is in use
netstat -ano | findstr :18629
# Manually open dashboard
# http://localhost:18629
# Check AppHost logs for errors
dotnet run --project PokemonEncyclopedia.AppHost --verbose- Clear cache:
docker exec -it pokemonencyclopedia-redis redis-cli FLUSHDB - Restart services: Stop and re-run AppHost
- Check Docker resources: Docker Desktop → Settings → Resources → increase allocated CPU/RAM
- Monitor with Aspire: Check "Resource" tab for CPU/memory usage
# Ensure compose file path is correct
docker-compose -f docker-compose.yml up -d
# Or create docker-compose.yml in project root if missing
# Copy from: https://github.com/Hana-fubuki/PokemonEncyclopedia/docker-compose.yml-
Create feature branch:
git checkout -b feature/my-feature
-
Update domain models in
PokemonEncyclopedia.Application -
Add business logic via MediatR handlers
-
Update API endpoints in
PokemonEncyclopedia.ApiService -
Create UI components in
PokemonEncyclopedia.Web -
Test locally:
dotnet run --project PokemonEncyclopedia.AppHost
-
Run tests:
dotnet test -
Push and create PR:
git push origin feature/my-feature
- Format code:
dotnet format - Run linters:
dotnet analyzers(via IDE) - Unit tests:
dotnet test - Integration tests: See
PokemonEncyclopedia.Tests
-
Use Release mode for benchmarking:
dotnet run -c Release --project PokemonEncyclopedia.AppHost
-
Monitor with Aspire Dashboard:
- View resource usage per service
- Identify slow endpoints
- Check error rates
-
Redis optimization:
- Monitor cache hit rate
- Adjust TTL values as needed
- Use
docker statsto monitor memory
See infra/README.md for deployment and scaling recommendations.
dotnet run --project PokemonEncyclopedia.AppHostSee infra/README.md for:
- Building container images
- Deploying with Bicep (default)
- Deploying with Terraform
- Configuring Application Insights
- Setting up CI/CD with GitHub Actions
-
Push to
mainbranch:git push origin main
-
Bicep deployment (automatic):
- Workflow:
.github/workflows/deploy-bicep.yml - Triggered on: code or
infra/bicep/changes
- Workflow:
-
Terraform deployment (manual):
- Workflow:
.github/workflows/deploy-terraform.yml - Trigger via: Actions tab → "Manual Deploy with Terraform" → Run workflow
- Workflow:
# Get all Pokémon
GET /api/pokemon
# Get Pokémon by ID
GET /api/pokemon/:id
# Get Pokémon by name
GET /api/pokemon/:name
# Filter Pokémon
GET /api/pokemon?type=fire&legendary=true# Get all abilities
GET /api/abilities
# Get ability by ID
GET /api/abilities/:id
# Get ability by name
GET /api/abilities/:name# Get all moves
GET /api/moves
# Get move by ID
GET /api/moves/:idFull API documentation available at /swagger or /scalar
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- PokéAPI: https://pokeapi.co
- .NET Aspire Docs: https://learn.microsoft.com/aspire/
- Blazor Docs: https://learn.microsoft.com/aspnet/core/blazor/
- Azure Container Apps: https://docs.microsoft.com/azure/container-apps/
- OpenTelemetry: https://opentelemetry.io/
- Developer: Josh Cohenour
- PokéAPI for comprehensive Pokémon data
- .NET team for Aspire orchestration framework
- Azure community for deployment best practices