Deploying to Production¶
This page covers the steps needed to take a Domain Services Web API from a local development setup to a production environment — replacing dev shortcuts ([AppData], JSON files, anonymous auth) with proper configuration.
The Dev → Production Checklist¶
| Item | Development | Production |
|---|---|---|
| Data storage | [AppData] + JSON files |
Database provider (PostgreSQL, MCLite, ...) or shared file storage |
| Secrets | Hardcoded or .env file |
Environment variables / Key Vault |
| Auth | AllowAnonymousHandler |
JWT bearer tokens with real RSA key pair |
| Platform target | Any | x64 (required for MIKECore/MCLite native providers) |
| CORS | Localhost only | Restrict to known origins |
| HTTPS | Optional | Required (HSTS enabled) |
Step 1 — Replace [AppData] with Real Paths¶
[AppData] resolves to App_Data/ relative to the content root. In production:
- For file-based providers (ShapeFiles, DFS files): deploy the data files alongside the app or point to a shared network/blob path. Set
ContentRootPathinappsettings.jsonif the app is deployed to a non-default location:
{
"AppConfiguration": {
"ContentRootPath": "D:\\Apps\\MyService"
}
}
- For database providers: replace
[AppData]myfile.jsonconnection strings with real database connection strings using[env:...]:
{
"ConnectionStrings": {
"Postgres": "[env:POSTGRES_CONN]"
}
}
Step 2 — Switch to a Database Provider¶
In connections.json, change RepositoryType to the production provider and ConnectionString to the env-var reference:
Before (dev):
{
"scalars": {
"$type": "DHI.Services.Scalars.WebApi.ScalarServiceConnection, DHI.Services.Scalars.WebApi",
"RepositoryType": "DHI.Services.Scalars.ScalarRepository, DHI.Services.Scalars",
"ConnectionString": "[AppData]scalars.json",
"Name": "Scalars (dev)",
"Id": "scalars"
}
}
After (production):
{
"scalars": {
"$type": "DHI.Services.Scalars.WebApi.ScalarServiceConnection, DHI.Services.Scalars.WebApi",
"RepositoryType": "DHI.Services.Provider.PostgreSQL.ScalarRepository, DHI.Services.Provider.PostgreSQL",
"ConnectionString": "[env:POSTGRES_CONN]",
"Name": "Scalars (PostgreSQL)",
"Id": "scalars"
}
}
No code changes required — only connections.json and environment variables change between environments.
Step 3 — Set Environment Variables¶
Set the following in your deployment environment (Azure App Service → Configuration, Kubernetes secret, IIS Application Pool environment, etc.):
| Variable | Value |
|---|---|
PublicRSAKey |
Content of key.public.xml |
POSTGRES_CONN |
Server=...;Port=5432;Database=...;User Id=...;Password=... |
Any other [env:VAR] placeholders |
Their resolved values |
Tip: Never store the private RSA key in a Web API app. Only the Authorization Server needs it.
Step 4 — Platform Target (x64)¶
Providers that wrap native C++ libraries (MIKECore, MCLite, DFS providers) require 64-bit hosting.
In your .csproj:
<PropertyGroup>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
IIS: In IIS Manager, open the Application Pool → Advanced Settings → "Enable 32-Bit Applications" → False.
IIS Express (local): In Visual Studio → Tools → Options → Projects and Solutions → Web Projects → select the 64-bit IIS Express option.
Step 5 — Deploying to Azure App Service¶
MIKECore / MZChart registry access¶
If your app uses the MIKECore provider, the native mzchart.dll attempts to write to the Windows registry — which is blocked in Azure App Service. Add this environment variable to avoid a FileLoadException at startup:
MZCHART_NO_REGISTRY=1
Recommended Azure App Service settings¶
| Setting | Value |
|---|---|
| Platform | 64-bit |
| Always On | On (prevents cold starts) |
| HTTPS Only | On |
| App settings | PublicRSAKey, POSTGRES_CONN, MZCHART_NO_REGISTRY (if needed) |
Step 6 — Deploying to IIS¶
- Publish the project from Visual Studio (Build → Publish) targeting a folder or directly to IIS.
- Ensure the Application Pool runs under an identity with read access to any data files.
- Set "Enable 32-bit Applications" to
Falseif using native providers. - Add environment variables to the Application Pool identity or
web.config:
<aspNetCore processPath="dotnet" arguments=".\MyService.dll" stdoutLogEnabled="false">
<environmentVariables>
<environmentVariable name="PublicRSAKey" value="..." />
<environmentVariable name="POSTGRES_CONN" value="..." />
</environmentVariables>
</aspNetCore>
Step 7 — HTTPS and HSTS¶
The Base Web API template already includes HSTS. Configure the max age in appsettings.json:
{
"AppConfiguration": {
"HstsMaxAgeInDays": 365
}
}
Ensure the app is behind an HTTPS terminator (Azure App Service handles this automatically; for IIS or Docker, configure a TLS certificate separately).
Step 8 — Remove the Dev Auth Bypass¶
Before deploying, verify AllowAnonymousHandler is not registered:
// REMOVE this line before production:
// builder.Services.AddSingleton<IAuthorizationHandler, AllowAnonymousHandler>();
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
DataDirectory is not set |
[AppData] used but DataDirectory not initialised |
Set AppDomain.CurrentDomain.SetData("DataDirectory", ...) early in startup |
Could not load type … |
RepositoryType in connections.json doesn't match installed assembly |
Check assembly-qualified name and NuGet package version |
Could not load file or assembly 'DHI.Chart.Map.dll' |
MZChart registry access blocked (Azure) | Set MZCHART_NO_REGISTRY=1 |
| All endpoints return 401 | JWT not configured or AllowAnonymousHandler removed |
Check Tokens:PublicRSAKey env var and token validation config |
| 32-bit load failure with native providers | App pool running in 32-bit mode | Set "Enable 32-Bit Applications" to False in IIS |
Summary¶
- Swap
[AppData]JSON files for database providers by changing onlyconnections.json— no code changes. - Store all secrets (
PublicRSAKey, connection strings) as environment variables using[env:VAR]. - Native C++ providers (MIKECore, MCLite) require 64-bit hosting — set
PlatformTarget=x64and disable 32-bit in IIS/App Pool. - Azure App Service: set
MZCHART_NO_REGISTRY=1if using MIKECore. - Remove
AllowAnonymousHandlerbefore deploying to any shared or production environment.
Next: You've reached the end of the onboarding sequence. For a quick reference of common patterns, see the Domain Services Cheat Sheet.