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.Cqrsif you only need the handler and validator contracts without the concrete implementations.
Installation
dotnet add package Dosaic.Plugins.Handlers.CqrsFeatures
Five generic CRUD handlers —
Create,Update,Delete,Get, andGetListcovering the complete resource lifecycle out of the boxAutomatic GUID assignment on create — the handler assigns a fresh
Guid.NewGuid()so callers never have to supply an IDExistence check on update — throws a
DosaicExceptionif the resource does not exist before attempting the updatePaged list support —
GetListAsyncparsesPagingRequestintoQueryOptions, runs count and data queries in parallel, and returns aPagedList<TResource>Integrated validation — every handler validates its input with FluentValidation and throws
ValidationDosaicExceptionon failure, giving structuredFieldValidationErrordetails to callersAuto-discovery of custom handlers and validators — at plugin startup,
CqrsSimpleResourcePluginscans for all types implementingIHandlerorIBaseValidatorand registers them in DIHandler override — register your own
ICreateHandler<T>(or any other handler interface) implementation and that registration takes precedence over the built-inSimpleResource*handlerOpenTelemetry tracing — every handler operation starts a named
Activitywith resource-relevant tags (e.g.resource-id) for distributed trace correlationValidateOrThrowAsyncextension — reusableIValidator<T>extension that throwsValidationDosaicExceptioninstead 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:
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
ValidateOrThrowAsync in your own handlersThe 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
GuidIdentifierValidatorApplied automatically by SimpleResourceDeleteHandler and SimpleResourceGetHandler:
Id
Must not be empty (Guid.Empty)
PagingRequestValidator
PagingRequestValidatorApplied automatically by SimpleResourceGetListHandler:
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