Table of Contents

Exception handling

When you send a command or query through IRequestDispatcher, CodeBlock DevKit answers with Result or Result<T>. Treat Result.IsSuccess and Result.Errors as the stable contract for Blazor, Razor, API controllers, and application services: you branch once, whether the failure came from validation, domain rules, application rules, or an unexpected bug.

Managed failures (DomainException, ApplicationException, ValidationException) are turned into human-readable strings (including localized text when you use resource-based constructors) and pushed through INotificationService. Unmanaged exceptions are logged in full for operators while callers still receive a safe message in Result.Errors—not raw stack traces. MediatRDispatcher then folds those notifications into Result.Failure(...) so every path looks the same to your UI.

API hosts still include global HTTP middleware as a last resort for anything that escapes the normal MediatR pipeline entirely.

You do not register custom exception middleware for the dispatcher story; it is part of the DevKit web stack you build on.

Request flow: from caller to Result

flowchart TD
    U[User or HTTP client] --> API[Web API host]
    API --> ASVC[Application service]
    ASVC --> MODEL[Create use case request model command or query]
    MODEL --> DISP["IRequestDispatcher Send*"]

    DISP --> VAL{Request passes annotation and FluentValidation?}
    VAL -->|No| VEX[ValidationException — handler not run]
    VAL -->|Yes| HAND[Use case handler runs]

    HAND --> DOM[Domain aggregate entity or domain service]
    DOM -->|Expected failure| DEX[DomainException]
    DOM -->|Unexpected| OEX[Other exception]
    HAND -->|Expected failure| AEX[ApplicationException]
    HAND -->|Unexpected| OEX

    VEX --> EH[DevKit pipeline exception handlers — managed vs unmanaged]
    DEX --> EH
    AEX --> EH
    OEX --> EH

    EH --> FAIL["Result.Failure — MediatRDispatcher fills Errors from INotificationService; unmanaged exceptions are logged in full"]

    HAND -->|Completes without throwing| OK["Result.Success"]

    FAIL --> OUT[Application service receives Result]
    OK --> OUT
    OUT --> RESP[API maps Result to HTTP response]
    RESP --> U

Reading the chart: validation runs before the handler. DomainException / ApplicationException are expected failures you throw from your code; anything else is unmanaged. In every failure case the caller still receives a Result and should use IsSuccess / Errors.

Where to go next

  • Services — The main exception types and namespaces you import in your projects.
  • Tutorials — Domain factories, entities, validation with annotations and FluentValidation, and template-aligned examples.