Skip to content

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.

Architecture overview

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 JsonRepository and mock repositories
  • Choosing a Provider — decision guide for JSON, PostgreSQL, USGS, and others

Next: Getting Started