CQRS

Provides concrete CQRS handler implementations for the Dosaic plugin framework. This package ships five ready-to-use generic SimpleResource handlers that cover the full CRUD lifecycle for any resource type that implements IGuidIdentifier. It also auto-discovers and registers your own custom handlers and validators through the Dosaic IImplementationResolver, and integrates built-in OpenTelemetry tracing and FluentValidation support.

Use Dosaic.Plugins.Handlers.Abstractions.Cqrs if you only need the handler and validator contracts without the concrete implementations.

Installation

dotnet add package Dosaic.Plugins.Handlers.Cqrs

Features

  • Five generic CRUD handlersCreate, Update, Delete, Get, and GetList covering the complete resource lifecycle out of the box

  • Automatic GUID assignment on create — the handler assigns a fresh Guid.NewGuid() so callers never have to supply an ID

  • Existence check on update — throws a DosaicException if the resource does not exist before attempting the update

  • Paged list supportGetListAsync parses PagingRequest into QueryOptions, runs count and data queries in parallel, and returns a PagedList<TResource>

  • Integrated validation — every handler validates its input with FluentValidation and throws ValidationDosaicException on failure, giving structured FieldValidationError details to callers

  • Auto-discovery of custom handlers and validators — at plugin startup, CqrsSimpleResourcePlugin scans for all types implementing IHandler or IBaseValidator and registers them in DI

  • Handler override — register your own ICreateHandler<T> (or any other handler interface) implementation and that registration takes precedence over the built-in SimpleResource* handler

  • OpenTelemetry tracing — every handler operation starts a named Activity with resource-relevant tags (e.g. resource-id) for distributed trace correlation

  • ValidateOrThrowAsync extension — reusable IValidator<T> extension that throws ValidationDosaicException instead of returning a result, with null-request guard included

Usage

1. Define your resource model

Your resource must implement IGuidIdentifier from Dosaic.Plugins.Persistence.Abstractions:

2. Register the plugin

Add CqrsSimpleResourcePlugin to your Dosaic host. Because Dosaic uses source generation, simply referencing this package in your host project is enough — DosaicPluginTypes.All emitted by the generator will include it automatically.

When CqrsSimpleResourcePlugin.ConfigureServices runs it registers:

Service
Implementation

ICreateHandler<TResource>

SimpleResourceCreateHandler<TResource>

IUpdateHandler<TResource>

SimpleResourceUpdateHandler<TResource>

IDeleteHandler<TResource>

SimpleResourceDeleteHandler<TResource>

IGetHandler<TResource>

SimpleResourceGetHandler<TResource>

IGetListHandler<TResource>

SimpleResourceGetListHandler<TResource>

Any IHandler implementation found by the resolver

the discovered type

Any IBaseValidator implementation found by the resolver

the discovered type

All registrations use AddTransient lifetime.

3. Provide a repository

The built-in handlers depend on IRepository<TResource> and IReadRepository<TResource> from Dosaic.Plugins.Persistence.Abstractions. Register a concrete persistence plugin (e.g. Dosaic.Plugins.Persistence.EfCore) alongside this plugin, or provide your own implementation:

4. Resolve and use the handlers

Inject the handler interfaces where you need them — for example inside a Dosaic endpoint, a controller, or any other DI-resolved service:

5. Add custom validation

Implement one or more validator interfaces from Dosaic.Plugins.Handlers.Abstractions.Cqrs.Validators and make the class public. The plugin discovers it automatically at startup and registers it against each interface it implements:

SimpleResourceCreateHandler<Article> automatically receives the ICreateValidator<Article> from DI and wraps it into a GenericValidator<Article> via ValidateOnCreate. The same pattern applies for update.

6. Override a built-in handler

Create a public class that implements the relevant handler interface and register it anywhere in your assembly. The plugin scans for IHandler implementations and registers them after the built-in ones, so the last registration wins for AddTransient:

7. Use ValidateOrThrowAsync in your own handlers

The ValidationExtensions.ValidateOrThrowAsync<T> extension method is available for any IValidator<T>. It throws ValidationDosaicException with structured FieldValidationError details when validation fails, and guards against null requests:

Built-in Validation Rules

GuidIdentifierValidator

Applied automatically by SimpleResourceDeleteHandler and SimpleResourceGetHandler:

Field
Rule

Id

Must not be empty (Guid.Empty)

PagingRequestValidator

Applied automatically by SimpleResourceGetListHandler:

Field
Rule

Page

When provided: must be ≥ 0

Size

When provided: must be > 0 and ≤ 100

Sort

When provided: must not be an empty string

Filter

When provided: must not be an empty string

Last updated