Skip to main content

handle-validation-and-errors

Validates DTOs/inputs and throws/localizes business errors in an ABP app. USE FOR: data annotations, IValidationEnabled, FluentValidation, BusinessException/UserFriendlyException, error codes, localizing error messages, mapping exceptions to HTTP status codes. DO NOT USE FOR: writing the application service itself or CrudAppService plumbing (use application-services); permission/authorization checks and AbpAuthorizationException policy (use permissions-and-authorization / authorize-resources).

Zur Installation springen

Quellinformationen

Repository
abpframework/abp-skills
Letzte Quellaktivität
20. Juli 2026 um 03:24
Erkannte Sprache von SKILL.md
Englisch
Sterne
18
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
handle-validation-and-errors
description
Validates DTOs/inputs and throws/localizes business errors in an ABP app. USE FOR: data annotations, IValidationEnabled, FluentValidation, BusinessException/UserFriendlyException, error codes, localizing error messages, mapping exceptions to HTTP status codes. DO NOT USE FOR: writing the application service itself or CrudAppService plumbing (use application-services); permission/authorization checks and AbpAuthorizationException policy (use permissions-and-authorization / authorize-resources).
license
MIT
# Validation & Error Handling in ABP ABP builds on ASP.NET Core model validation and adds automatic validation, localization, and a standard exception-handling pipeline. Everything from the [ASP.NET Core validation docs](https://learn.microsoft.com/aspnet/core/mvc/models/validation) still applies. ## When to Use - Validating DTOs/inputs with data annotations or `IValidatableObject`. - Getting automatic method-argument validation via `IValidationEnabled`. - Integrating FluentValidation into ABP's validation pipeline. - Throwing business errors with `BusinessException` / `UserFriendlyException`. - Localizing error messages by error code. - Mapping exception types to HTTP status codes. ## When Not to Use - **Writing the application service or CRUD plumbing itself** — use the application-services skill; this skill only covers the validation/error concerns inside it. - **Authorization checks and `AbpAuthorizationException` policy** — use permissions-and-authorization / authorize-resources; here it appears only in the status-code mapping table. ## DTO Validation Use standard data annotation attributes on DTOs. When a DTO is a parameter to an application service or controller action, ABP validates it automatically and throws an `AbpValidationException` on failure. (The attribute messages are localized only when the DTO's assembly is registered for data-annotations localization — see below — otherwise the raw attribute message is used.) ```csharp public class CreateBookDto { [Required] [StringLength(100)] public string Name { get; set; } [Range(0, 999.99)] public decimal Price { get; set; } } ``` For custom cross-field logic, implement `IValidatableObject`: ```csharp public class CreateBookDto : IValidatableObject { [Required] public string Name { get; set; } [Required] public string Description { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { if (Name == Description) { yield return new ValidationResult( "Name and Description can not be the same!", new[] { "Name", "Description" }); } } } ``` Keep DTOs simple — don't put domain logic in `Validate`. Data annotation error messages are localized only when the DTO's assembly is registered for it (via `AddDataAnnotationsLocalization` / `AbpMvcDataAnnotationsLocalizationOptions.AssemblyResources`); otherwise the raw attribute message is used. ### IValidationEnabled `IValidationEnabled` is an empty marker interface. Any DI-registered class that implements it gets automatic method-argument validation. All application services implement it already. ABP uses dynamic proxying/interception, so the method must be **virtual** or the service must be called through an **interface**. ```csharp public class MyService : ITransientDependency, IValidationEnabled { public virtual async Task DoItAsync(MyInput input) { /* input is validated */ } } ``` Disable with `[DisableValidation]` on a method, class, or property. ### AbpValidationException ABP throws `AbpValidationException` when validation fails. Its `ValidationErrors` holds the error list, its log level is `Warning`, and ABP converts it to an HTTP 400 response automatically. You can throw it yourself but rarely need to. ## FluentValidation Integration Add the `Volo.Abp.FluentValidation` package (`abp add-package Volo.Abp.FluentValidation`) and depend on `AbpFluentValidationModule`. Then write standard FluentValidation validators — ABP discovers them and runs them as part of the same validation pipeline. ```csharp public class CreateUpdateBookDtoValidator : AbstractValidator<CreateUpdateBookDto> { public CreateUpdateBookDtoValidator() { RuleFor(x => x.Name).Length(3, 10); RuleFor(x => x.Price).ExclusiveBetween(0.0f, 999.0f); } } ``` ## Business Exceptions Most of your own errors are business exceptions. `BusinessException` implements `IBusinessException`, `IHasErrorCode`, `IHasErrorDetails`, and `IHasLogLevel` (default log level `Warning`). All its constructor arguments are optional; usually you set an error `Code` or a `Message`. ```csharp throw new BusinessException(QaErrorCodes.CanNotVoteYourOwnAnswer); ``` The `Code` follows the format `<code-namespace>:<error-code>` (e.g. `Volo.Qa:010002`). The code-namespace is unique to your module/application and is the key used for localization. Attach message parameters via the `Data` dictionary; there is a `WithData` shortcut that is chainable: ```csharp throw new BusinessException("App:010046").WithData("UserName", "john"); ``` ## Localizing Error Messages Two models: **User-friendly exceptions.** `UserFriendlyException` implements `IUserFriendlyException` (which derives from `IBusinessException`). ABP sends its `Message` and `Details` to the client unchanged — no localization needed, or localize it yourself with the string localizer at throw time. ```csharp throw new UserFriendlyException(_stringLocalizer["UserNameShouldBeUniqueMessage", "john"]); ``` **Error codes (recommended for advanced cases).** Instead of localizing at throw time, map a code-namespace to a localization resource once, then localize by the error code key. This avoids needing the localizer everywhere (e.g. in static contexts or entity methods). ```csharp services.Configure<AbpExceptionLocalizationOptions>(options => { options.MapCodeNamespace("Volo.Qa", typeof(QaResource)); }); ``` Add the error code as a key in the resource's `en.json`: ```json { "culture": "en", "texts": { "Volo.Qa:010002": "You can not vote your own answer!", "App:010046": "Username should be unique. '{UserName}' is already taken!" } } ``` If no localized string is defined for a code, ABP sends a default error message to the client — it does **not** fall back to the exception's `Message` property. Use `UserFriendlyException` when you want the raw message shown. ## HTTP Status Code Mapping ABP picks a status code automatically for common exception types: - `AbpAuthorizationException` → `401` if not logged in, `403` if logged in - `AbpValidationException` → `400` - `EntityNotFoundException` → `404` - `AbpDbConcurrencyException` → `409` - `IBusinessException` / `IUserFriendlyException` → `403` - `NotImplementedException` → `501` - anything else → `500` (treated as an infrastructure error) Override per error code with `AbpExceptionHttpStatusCodeOptions`: ```csharp services.Configure<AbpExceptionHttpStatusCodeOptions>(options => { options.Map("Volo.Qa:010002", HttpStatusCode.Conflict); }); ``` ## Validation - Pass an invalid DTO into an app service / auto API controller and confirm an `AbpValidationException` → HTTP 400 response, with `validationErrors` populated in the JSON. - Throw a `BusinessException` with a mapped error code and confirm the localized text from `en.json` reaches the client (not the raw `Message`). - Confirm the response body is a `RemoteServiceErrorResponse` with a single `error` object holding `code` / `message`. - Verify a code mapped via `AbpExceptionHttpStatusCodeOptions.Map(...)` returns the overridden status code. ## Common Pitfalls - Data annotation messages are **not** localized unless the DTO's assembly is registered for data-annotations localization (`AddDataAnnotationsLocalization` / `AbpMvcDataAnnotationsLocalizationOptions.AssemblyResources`); otherwise the raw attribute message shows. - `IValidationEnabled` needs the method to be **virtual** or the service to be called through an **interface** — ABP relies on dynamic proxying/interception, so direct concrete calls to non-virtual methods bypass validation. - An error code with no localized string falls back to ABP's default message, **not** to the exception's `Message`. Use `UserFriendlyException` when you want the raw message shown. - The error JSON is a `RemoteServiceErrorResponse` with a single `error` object (a `RemoteServiceErrorInfo`) holding `code`, `message`, `details`, `data`, and `validationErrors` — i.e. `{ "error": { "code": ..., "message": ... } }` — filled based on which interfaces the exception implements. - Control what reaches clients with `AbpExceptionHandlingOptions` (`SendExceptionsDetailsToClients`, `SendStackTraceToClients`). - Set an exception's log level by implementing `IHasLogLevel`; add extra logging with `IExceptionWithSelfLogging`. - To react when ABP handles an exception, derive from `ExceptionSubscriber` and override `HandleAsync`.
Auf GitHub ansehen