Converters¶
Domain Services uses System.Text.Json. Many domain models rely on custom JSON converters for correct serialization/deserialization (polymorphism, value objects, strong-typed IDs, etc.).
Each Web API module ships its own set of converters exposed via a standard entry point named:
{Module}.WebApi.SerializerOptionsDefault.Options.Converters
Because of this, when you add a module (TimeSeries, GIS, Jobs, Places, Meshes, …) you must also register that module’s converters in Program.cs.
Base setup (from the project template)¶
The BaseWebApi template already wires up the core converters from DHI.Services:
// MVC
builder.Services
.AddResponseCompression(options => { options.EnableForHttps = true; })
.AddControllers()
.AddJsonOptions(options =>
{
// Configure JSON serialization options
options.JsonSerializerOptions.WriteIndented = true;
options.JsonSerializerOptions.DefaultIgnoreCondition
= SerializerOptionsDefault.Options.DefaultIgnoreCondition;
options.JsonSerializerOptions.PropertyNamingPolicy
= SerializerOptionsDefault.Options.PropertyNamingPolicy;
// Core DS converters (from DHI.Services / DHI.Services.WebApi)
options.JsonSerializerOptions
.AddConverters(SerializerOptionsDefault.Options.Converters);
#warning Depending on which Web API packages you install in this project,
#warning you need to register domain-specific JSON converters for these packages
});
The last warning is intentional: it reminds you to add converters for each domain-specific Web API you install.
Add converters for each Web API module¶
Example: TimeSeries Web API¶
options.JsonSerializerOptions.AddConverters(
DHI.Services.TimeSeries.WebApi.SerializerOptionsDefault.Options.Converters
);
Example: multiple modules (Places, GIS, Meshes)¶
options.JsonSerializerOptions
.AddConverters(DHI.Services.Places.WebApi.SerializerOptionsDefault.Options.Converters);
options.JsonSerializerOptions
.AddConverters(DHI.Services.GIS.WebApi.SerializerOptionsDefault.Options.Converters);
options.JsonSerializerOptions
.AddConverters(DHI.Services.Meshes.WebApi.SerializerOptionsDefault.Options.Converters);
You can add as many as needed—one line per module.
Important notes¶
- Namespace/assembly matters. Every module exposes
SerializerOptionsDefaultin its own WebApi assembly/namespace. Make sure you reference the correct one, e.g.DHI.Services.TimeSeries.WebApi.SerializerOptionsDefault, not justDHI.Services.TimeSeries.SerializerOptionsDefault. - Order is fine-grained-safe. Converters are appended; typical modules don’t conflict, but if you define your own custom converters for the same types, add yours after the module converters to override behavior.
- Swagger & clients. Once registered, Swagger will show correct request/response shapes. If you are writing clients that use
System.Text.Json, mirror the same converter registration on the client’sJsonSerializerOptionsto deserialize responses correctly. -
When you’ll notice missing converters:
NotSupportedException: Deserialization of types deriving from … is not supported- Unexpected
nullvalues or default values after model binding - Polymorphic payloads losing concrete type information
Quick checklist when adding a module¶
- Install the Web API package (e.g.,
DHI.Services.TimeSeries.WebApi). - In
Program.cs, add its converter line under.AddJsonOptions(...). - Run and hit the new endpoints in Swagger; verify JSON round-trips.
Summary¶
- Converters are per-module: each Web API package ships its own
SerializerOptionsDefault.Options.Converters. - Add one
AddConverters(...)call per module — they stack without conflict. - Always reference the WebApi assembly namespace (e.g.,
DHI.Services.TimeSeries.WebApi.SerializerOptionsDefault), not the domain assembly.
Next: Dynamic Connections