Documentation
operations/documentation-setup.md
Dynaplex Documentation Setup
This guide explains how to build, preview, and deploy the Dynaplex documentation site built with DocFX.
Overview
The documentation system uses:
- DocFX - Generates static website from C# XML comments and markdown
- XML Documentation - Auto-generated API reference from code comments
- Markdown Files - Conceptual documentation (architecture, guides, ADRs)
- CI/CD - Automatic builds and deployment (Azure DevOps or GitLab)
Prerequisites
Required
- .NET 9 SDK - For building the project
- DocFX - For generating documentation
Installation
# Install .NET 9 SDK (if not already installed)
# Download from: https://dotnet.microsoft.com/download
# Install DocFX
dotnet tool install -g docfx
# Verify installation
docfx --version
Project Structure
acsis-core/
├── docfx.json # DocFX configuration
├── toc.yml # Main table of contents
├── index.md # Documentation homepage
├── api/ # Generated API reference (auto-created)
│ └── index.md # API documentation index
├── docs/ # Conceptual documentation
│ ├── *.md # Architecture docs
│ └── adrs/ # Architecture Decision Records
├── engines/ # Engine source code
│ └── */resources/ # Component-specific docs
├── _site/ # Generated website (gitignored)
└── Directory.Build.props # Enables XML documentation
Building Documentation Locally
Step 1: Build the Project
XML documentation is generated during build:
# Build all projects (generates XML files)
dotnet build acsis-core.slnx
Step 2: Generate API Metadata
Extract API reference from XML comments:
# Generate API metadata
docfx metadata docfx.json
This creates YAML files in the api/ folder with API structure.
Step 3: Build Documentation Site
Build the complete documentation website:
# Build documentation
docfx build docfx.json
Output is in _site/ folder.
Step 4: Preview Locally
Serve the documentation locally:
# Serve documentation
docfx serve _site
# Or use the shorthand that builds and serves
docfx docfx.json --serve
Open browser to: http://localhost:8080
Running with Containers
Option 1: With Aspire Orchestration (Recommended for Development)
Add the documentation container to your Aspire AppHost:
// In your AppHost.cs (e.g., projects/assettrak-classic/src/Acsis.Dynaplex.Projects.AssetTrakClassic/AppHost.cs)
var foundation = builder.AddFoundation()
.WithAppConfiguration()
.WithAppInsights()
.WithContainerAppEnvironment()
.WithDefaultDatabase()
.WithCoreData<Acsis_Components_CoreData, Acsis_Components_CoreData_DbMigrator>()
.WithSystemEnvironment<Acsis_Components_SystemEnvironment, Acsis_Components_SystemEnvironment_DbMigrator>()
.WithIdentity<Acsis_Components_Identity, Acsis_Components_Identity_DbMigrator>()
.WithEvents<Acsis_Components_Events, Acsis_Components_Identity_DbMigrator>()
// ... other components ...
.WithDocumentation(); // Add this line
foundation.Build();
builder.Build().Run();
Benefits:
- Documentation runs alongside all services
- Accessible via Aspire Dashboard
- Automatic rebuilds when container configuration changes
- Only runs in non-production environments (by default)
Access:
- Via Aspire Dashboard at the
docs-httpendpoint - Direct access at the port shown in Aspire Dashboard
Skip in Production:
By default, .WithDocumentation() skips the container when publishing to Azure. To include it:
.WithDocumentation(skipInProduction: false)
Option 2: Standalone Docker Container
Run the documentation in a standalone Docker container:
# Build and run using Docker directly
docker build -f Dockerfile.docs -t dynaplex-docs .
docker run -p 8080:80 dynaplex-docs
# Or use docker-compose
docker-compose -f docker-compose.docs.yml up
# Run in background
docker-compose -f docker-compose.docs.yml up -d
# Stop the container
docker-compose -f docker-compose.docs.yml down
Access: http://localhost:8080
Container Features:
- Multi-stage build (builds docs in .NET SDK, serves with nginx)
- Health checks for container monitoring
- Gzip compression enabled
- Lightweight nginx:alpine base (~40MB)
Option 3: Docker with Custom Port
Use a different port to avoid conflicts:
# Run on port 9090
docker run -p 9090:80 dynaplex-docs
# Or edit docker-compose.docs.yml
services:
docs:
ports:
- "9090:80" # Change to your preferred port
Container Architecture
The Dockerfile.docs uses a multi-stage build:
Stage 1: Build
- Uses
mcr.microsoft.com/dotnet/sdk:9.0 - Installs DocFX
- Builds all C# projects
- Generates API metadata
- Builds documentation site
Stage 2: Serve
- Uses
nginx:alpine(lightweight) - Copies built
_site/from build stage - Configures nginx for SPA routing
- Enables gzip compression
- Includes health check endpoint
Why This Approach?
- Single image - No external dependencies
- Self-contained - All docs built into the image
- Fast serving - nginx is optimized for static content
- Small size - Final image is ~40MB
- Health monitoring - Kubernetes/Aspire can monitor health
Quick Commands
# Build and serve in one command
docfx docfx.json --serve
# Force rebuild
docfx build docfx.json --force
# Clean generated files
rm -rf _site api obj
Writing Documentation
XML Documentation Comments
Add XML comments to your C# code:
/// <summary>
/// Gets all active items from the catalog.
/// </summary>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>List of items</returns>
/// <exception cref="InvalidOperationException">Thrown when database is unavailable</exception>
public async Task<List<ItemResponse>> GetItemsAsync(CancellationToken cancellationToken = default)
{
// Implementation
}
These comments automatically appear in the API reference.
Markdown Documentation
Create markdown files in appropriate locations:
- Architecture docs →
docs/ - Component docs →
engines/{component}/resources/ - ADRs →
docs/adrs/
Reference other pages using relative links:
See [Architectural Patterns](../ARCHITECTURAL_PATTERNS_QUICK_REF.md) for details.
Adding New Sections
Update toc.yml to add new sections:
- name: New Section
items:
- name: Page Title
href: path/to/page.md
CI/CD Deployment
Azure DevOps
The pipeline is configured in azure-pipelines-docs.yml.
Setup Steps:
Create Pipeline:
- Go to Azure DevOps → Pipelines → New Pipeline
- Select repository
- Choose existing YAML file:
azure-pipelines-docs.yml
Configure Deployment (choose one):
Option A: Azure Static Web Apps
# Uncomment in azure-pipelines-docs.yml - task: AzureStaticWebApp@0 inputs: app_location: '_site' azure_static_web_apps_api_token: $(AZURE_STATIC_WEB_APPS_API_TOKEN)Option B: Azure Blob Storage
# Uncomment in azure-pipelines-docs.yml - task: AzureCLI@2 inputs: azureSubscription: 'Your-Service-Connection' scriptType: 'bash' inlineScript: | az storage blob upload-batch \ --account-name yourstorageaccount \ --source _site \ --destination '$web' \ --overwriteSet Variables:
AZURE_STATIC_WEB_APPS_API_TOKEN(for Static Web Apps)- Or configure service connection (for Blob Storage)
GitLab
The pipeline is configured in .gitlab-ci-docs.yml.
Setup Steps:
Create Pipeline:
- Rename
.gitlab-ci-docs.ymlto.gitlab-ci.yml - Or include it in your main
.gitlab-ci.yml:include: - local: '.gitlab-ci-docs.yml'
- Rename
GitLab Pages (Automatic):
- Pipeline automatically deploys to GitLab Pages
- Access at:
https://your-group.gitlab.io/acsis-core
Azure Deployment (Optional):
- Set CI/CD variables:
AZURE_CLIENT_IDAZURE_CLIENT_SECRETAZURE_TENANT_ID
- Uncomment Azure deployment job in
.gitlab-ci-docs.yml
- Set CI/CD variables:
Manual Deployment
Build locally and deploy manually:
# Build documentation
docfx build docfx.json
# Deploy to Azure Static Web Apps
az staticwebapp deploy \
--name your-app-name \
--resource-group your-rg \
--source _site
# Or deploy to Azure Blob Storage
az storage blob upload-batch \
--account-name yourstorageaccount \
--source _site \
--destination '$web' \
--overwrite
Deployment Options
Option 1: Azure Static Web Apps (Recommended)
Pros:
- Free tier available
- Custom domains
- Automatic SSL
- Built-in authentication
- Edge caching
Setup:
# Create Static Web App
az staticwebapp create \
--name dynaplex-docs \
--resource-group your-rg \
--location eastus2 \
--sku Free
Option 2: Azure Blob Storage
Pros:
- Very cheap (~$0.20/month)
- Fast CDN integration
- Simple setup
Setup:
# Create storage account
az storage account create \
--name dynaplexdocs \
--resource-group your-rg \
--sku Standard_LRS
# Enable static website
az storage blob service-properties update \
--account-name dynaplexdocs \
--static-website \
--index-document index.html \
--404-document 404.html
Option 3: GitLab Pages
Pros:
- Free
- Integrated with GitLab
- Automatic deployment
Access: https://your-group.gitlab.io/acsis-core
Option 4: GitHub Pages
If you move to GitHub:
Setup:
# Create .github/workflows/docs.yml
name: Deploy Docs
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
dotnet-version: '9.x'
- run: dotnet tool install -g docfx
- run: docfx build docfx.json
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./_site
Customization
Branding
Update docfx.json:
{
"build": {
"globalMetadata": {
"_appTitle": "Your Company - Dynaplex",
"_appFooter": "© 2024 Your Company",
"_enableSearch": true
}
}
}
Templates
Use custom templates:
# Export default template
docfx template export default
# Customize in _exported_templates/default/
# Use custom template
docfx build docfx.json -t default,_exported_templates/default
Custom CSS
Add to docfx.json:
{
"build": {
"resource": [
{
"files": ["custom.css"]
}
]
}
}
Troubleshooting
Build Fails with "Missing XML documentation"
Solution: CS1591 warnings are suppressed in Directory.Build.props. If you want to enforce documentation:
<!-- Remove this line from Directory.Build.props -->
<NoWarn>$(NoWarn);CS1591</NoWarn>
API Reference is Empty
Solution: Ensure projects are built first:
dotnet build
docfx metadata docfx.json
docfx build docfx.json
Broken Links
Solution: Use relative paths and check case sensitivity:
<!-- Correct -->
[Link](../docs/GUIDE.md)
<!-- Incorrect -->
[Link](/docs/guide.md) # Absolute path
[Link](../docs/guide.md) # Wrong case
Serve Command Not Working
Solution: Ensure port 8080 is not in use:
# Use different port
docfx serve _site -p 9090
Missing Images
Solution: Add images to resource files in docfx.json:
{
"build": {
"resource": [
{
"files": ["images/**", "docs/images/**"]
}
]
}
}
Best Practices
- Write XML comments as you code - Don't defer documentation
- Use meaningful summaries - Explain "why", not just "what"
- Include code examples - Use
<example>tags - Link related members - Use
<see cref=""/>tags - Document exceptions - Use
<exception>tags - Keep markdown up to date - Review during code reviews
- Test locally before pushing - Run
docfx serveto preview - Version documentation - Tag releases and maintain versions
Maintenance
Regular Updates
- After new features - Update relevant documentation
- Before releases - Review and update API docs
- Monthly - Check for broken links and outdated content
- Quarterly - Review architectural docs and ADRs
Monitoring
Check documentation builds in CI/CD:
- Azure DevOps: Pipeline status
- GitLab: CI/CD → Pipelines
Resources
Support
For issues or questions:
- Create issue in repository
- Check DocFX GitHub issues
- Review this documentation
Happy documenting! 📚