Search Results for

      Show / Hide Table of Contents

      Intent.Application.Mediator.FluentValidation

      Adds FluentValidation to the commands and queries of Intent.Application.Mediator. It generates a validator for every Command and Query, and a validation step in the Mediator request pipeline that runs those validators before the handler.

      What This Module Generates

      Output What it is
      CommandValidator An AbstractValidator<TCommand> for each Command in the Services designer.
      QueryValidator An AbstractValidator<TQuery> for each Query in the Services designer.
      ValidationBehaviour<TRequest, TResponse> A Mediator pipeline behaviour (Common/Behaviours) that runs the validators registered for the request.
      IBypassValidation A marker interface (Common/Interfaces) that lets a request opt out of validation.

      It also adjusts the core's UnhandledExceptionBehaviour when that behaviour is enabled (see below).

      Installation

      Installing Intent.Application.FluentValidation into an application that already has Intent.Application.Mediator installs this module as well (the core module declares it as interoperability). It requires Intent.Application.Mediator; install the core first if you add this module by hand.

      The module has no settings of its own. The unique constraint validation default is read from the Intent.Application.FluentValidation application settings.

      Validators

      Command and query validators are built on the same shared validator base used by the MediatR and Wolverine FluentValidation modules, so the rules generated from the designer (required, length, ranges, unique constraints and so on) match those modules. Validators may inject repositories (for example for unique constraint checks), and the custom validation hook is enabled so you can add bespoke rules that survive regeneration. In the generated rules, the lambda parameter is named command for commands and query for queries.

      The custom validation AI skill (fluent-validation-custom-validation) is owned by Intent.Application.FluentValidation and is shared by every transport; this module does not generate its own copy.

      The Validation Pipeline Behaviour

      ValidationBehaviour<TRequest, TResponse> implements Mediator's IPipelineBehavior. For each request it:

      1. Returns straight to the next step if the request implements IBypassValidation.
      2. Otherwise, if any IValidator<TRequest> is registered, validates the request with each validator and collects every failure.
      3. Throws a single FluentValidation.ValidationException carrying all the failures if there were any.
      4. Otherwise continues to the next step in the pipeline.

      A request with no registered validators is passed through untouched.

      Where it sits in the pipeline

      You do not register this behaviour yourself. Intent.Application.Mediator owns the whole ordered list of pipeline behaviours and adds the validation step when it finds the Application.Common.ValidationBehaviour template role, which this module fills. The fixed order is, outermost first: Logging, UnhandledException, Performance, Authorization, MessageBusPublish, Validation, UnitOfWork. Validation therefore runs after authorization and before the unit of work is opened, so an invalid command never starts a transaction.

      Validators run one at a time

      The validators for a request run sequentially, never in parallel. Asynchronous rules, such as unique constraint checks, use the scoped DbContext, and a DbContext does not support concurrent operations. Running them with something like Task.WhenAll would make validation intermittently fail with concurrency errors in applications that use Entity Framework Core.

      Bypassing validation

      IBypassValidation is an empty marker interface. A command or query that implements it skips all validators. Use it for specialised messages where pipeline validation is redundant or deferred to a later stage. The module only generates the interface; it does not add it to any request.

      Validation Failures Are Not Logged As Unhandled Errors

      If the core's optional UnhandledExceptionBehaviour is enabled (a setting in Intent.Application.Mediator), this module inserts a catch (ValidationException) { throw; } block ahead of the behaviour's general catch (Exception). Validation failures are expected request failures, so without this block every rejected request would be logged as an unhandled exception. The exception is still rethrown, so it propagates up the pipeline to the caller unchanged. If the setting is off, the behaviour does not exist and nothing is changed.

      Dependencies

      • Intent.Application.Mediator - owns the pipeline, the command and query contracts the validators are keyed to, and the UnhandledExceptionBehaviour this module adjusts.
      • Intent.Application.FluentValidation - shared FluentValidation settings, registration and the custom validation AI skill.
      • Intent.Modelers.Services and Intent.Modelers.Services.CQRS - the Command and Query designer elements.

      Related Modules

      • Intent.Application.FluentValidation - the shared FluentValidation module.
      • Intent.Application.MediatR.FluentValidation - the equivalent module for MediatR.
      • Intent.Application.Wolverine.FluentValidation - the equivalent module for Wolverine.
      • Intent.Application.Mediator - the core module of this family (no published page yet).
      • Edit this page
      ☀
      ☾
      In this article
      Back to top Copyright © 2017-, Intent Architect Holdings Ltd