Domain Services Overview¶
Domain Services is a self-service platform of reusable .NET components for building service-oriented applications. It follows domain-driven design and clean architecture principles.
The LEGO Mental Model¶
Domain Services is built around four composable layers — think of them as LEGO bricks you snap together:
Entity → Repository → Service → Web API
| Layer | What it does | Example |
|---|---|---|
| Entity | Your domain model, with ID, metadata, audit fields, and permissions | Job<Guid, string>, TimeSeries<string, double> |
| Repository | Reads and writes entities from a storage backend | JsonRepository, PostgreSQL.ScalarRepository |
| Service | Business logic on top of a repository: lifecycle events, guards, CRUD | JobService, TimeSeriesService |
| Web API | REST/HTTP endpoints wired to a registered service via connectionId |
DHI.Services.Jobs.WebApi |
Each layer depends only on the abstraction below it. You can swap any layer independently — change the repository from JSON to PostgreSQL, or expose a service over HTTP, without touching the layers above or below.
Architecture Overview¶
Domain Services uses an Onion Architecture (also called Clean Architecture). The domain layer is at the center with no external dependencies; infrastructure layers (providers, Web API, UI) sit on the outside and depend inward.

| Layer | Role |
|---|---|
| Domain | Entities, services, interfaces, ServiceLocator, Guard, Maybe<T> |
| Providers | Concrete repository implementations (JSON, PostgreSQL, USGS, MIKE SDK, ...) |
| Web API | ASP.NET Core controllers that route {connectionId} requests to registered services |
| Web Components | React UI components that consume the Web APIs |
| Workflow Activities | WF-based automation blocks that call domain services |
The direction of coupling is always inward. Provider packages implement interfaces defined in the domain layer; the Web API packages call service interfaces — neither provider nor Web API packages have a dependency on each other.
Three Ways to Use Domain Services¶
1. Full Stack (Web API + React UI)¶
Install a DHI.Services.{Domain}.WebApi package into an ASP.NET Core project. Register your services at startup. Instantly get REST endpoints with Swagger docs and optional React UI components.
Best for: new microservices, team APIs, projects that need a browser front-end.
dotnet add package DHI.Services.Jobs.WebApi
2. .NET Services (library only)¶
Consume DHI.Services.{Domain} directly in a console app, desktop app, or your own Web API framework. No HTTP layer required.
Best for: scripting, analysis pipelines, custom frameworks, or when you want a different security model.
var repo = new TimeSeriesService(new CsvTimeSeriesRepository("[AppData]data".Resolve()));
var values = repo.GetValues("WaterLevel");
3. Framework (build your own domain)¶
Use DHI.Services (the Core package) as a foundation to define your own entities, repositories, and services following the same patterns used by the built-in modules (Jobs, TimeSeries, GIS, ...).
Best for: adding project-specific domains that need to integrate cleanly into the DS ecosystem.
public sealed class Sensor : BaseNamedEntity<Guid> { ... }
public sealed class SensorRepository : JsonRepository<Sensor, Guid> { ... }
public sealed class SensorService : BaseUpdatableDiscreteService<Sensor, Guid> { ... }
NuGet Package Naming Convention¶
All packages follow a predictable naming scheme, making it easy to find what you need:
| Category | Pattern | Example |
|---|---|---|
| Core abstractions | DHI.Services |
DHI.Services |
| Domain services | DHI.Services.{Domain} |
DHI.Services.Jobs |
| Web APIs | DHI.Services.{Domain}.WebApi |
DHI.Services.Jobs.WebApi |
| Providers | DHI.Services.{Technology} |
DHI.Services.PostgreSQL |
Public packages are on nuget.org. Internal packages are on the DHI Azure NuGet feed (VPN required).
Key Cross-Cutting Types¶
| Type | Package | Purpose |
|---|---|---|
BaseEntity<TId> |
DHI.Services |
Base class for all domain entities |
JsonRepository<TEntity,TId> |
DHI.Services |
File-backed JSON persistence |
ServiceLocator |
DHI.Services |
In-process registry keyed by connectionId |
Services.Configure |
DHI.Services |
Declarative service creation from connections.json |
Maybe<T> |
DHI.Services |
Null-safe optional wrapper returned by repositories |
Guard.Against |
DHI.Services |
Fluent precondition guards (null, empty, range) |
Further Reading¶
- Troubleshooting — quick fixes for 401, type-load errors, and AppData path issues
- Testing — xUnit patterns with
JsonRepositoryand mock repositories - Choosing a Provider — decision guide for JSON, PostgreSQL, USGS, and others
Next: Getting Started