Skip to content

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 ContentRootPath in appsettings.json if the app is deployed to a non-default location:
{
  "AppConfiguration": {
    "ContentRootPath": "D:\\Apps\\MyService"
  }
}
  • For database providers: replace [AppData]myfile.json connection 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
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

  1. Publish the project from Visual Studio (Build → Publish) targeting a folder or directly to IIS.
  2. Ensure the Application Pool runs under an identity with read access to any data files.
  3. Set "Enable 32-bit Applications" to False if using native providers.
  4. 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 only connections.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=x64 and disable 32-bit in IIS/App Pool.
  • Azure App Service: set MZCHART_NO_REGISTRY=1 if using MIKECore.
  • Remove AllowAnonymousHandler before 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.