MicroElements.Swashbuckle.FluentValidation 7.2.2

Swagger ISchemaFilter that uses FluentValidation validators instead System.ComponentModel based attributes.

No packages depend on MicroElements.Swashbuckle.FluentValidation.

$# Changes in 7.2.2

  • Fixed: MicroElements.AspNetCore.OpenApi.FluentValidation did not apply FluentValidation rules to a [FromForm] DTO bound by an MVC controller action (Issue #232, follow-up to the Swashbuckle-only #170 fix)
    • Root cause: MVC ApiExplorer flattens a controller's [FromForm] complex parameter into one form field per property, so Microsoft.AspNetCore.OpenApi builds the request body as an inline schema from those descriptions and never asks for the DTO's JsonTypeInfo — FluentValidationSchemaTransformer therefore never saw the type. Minimal API form bodies are not flattened and were never affected
    • Fix: FluentValidationOperationTransformer now applies the DTO's rules to the inline form schema for both multipart/form-data and application/x-www-form-urlencoded. The flattening is detected via ModelMetadata.ContainerType on the form-bound parameter descriptions, so a minimal API body — which the schema transformer already owns — is never touched twice
    • Property keys are taken verbatim from the schema, because a flattened form field is named after the model binder (Name, not name); the validator-side match stays name-insensitive
    • An action binding more than one form parameter composes its body as an allOf of one property bag per parameter; every bag is now constrained, and each bag is paired with the parameter that owns its fields — including the parameters the action binds directly (a loose scalar, array or IFormFile), which get a bag of their own but no rules. Without that pairing a DTO could be pulled into a foreign bag by a single coinciding field name and lose the constraints on its own bag
    • encoding.contentType (Issue #216) is now also emitted when the file part sits inside such an allOf bag
    • Dotted keys (Inner.City, ApiExplorer's binding path for a nested complex property) are skipped: the name matcher ignores separators, so such a key would otherwise inherit the rules of an unrelated root property named InnerCity. Nested form fields remain unsupported, matching the Swashbuckle form path
    • Issue #216 encoding.contentType is unchanged for the shapes it already covered, and now also consults every validator in multi-validator mode (IsOneValidatorForType = false) instead of only the first
    • Known limitations on this path (unchanged by this fix): a renamed form field ([FromForm(Name = "...")], or a property renamed by the INameResolver) gets no constraints, and on net10 a form part rendered as a $ref (IFormFile, enums) cannot receive property-level constraints
    • Thanks to @bux for the report

Changes in 7.2.1

  • Fixed: the document-filter pipeline (UseDocumentFilter = true) did not apply FluentValidation constraints to aliased operation parameters such as [FromHeader(Name = "X-Correlation-Id")] (Issue #230). The constraint copy now uses the resolved schema property key (kebab-case/camelCase/PascalCase aliases) and falls back to the INameResolver for renames beyond separators (e.g. [JsonPropertyName]) — full parity with the operation filter
  • Fixed: a dot in a header name ([FromHeader(Name = "X.Trace.Id")] — legal in HTTP) was treated as a nested [FromQuery] dot-path (#209/#211) and silently dropped the header's validation rules. Header-bound parameters are now exempt from the dot-path logic in all three parameter pipelines: FluentValidationOperationFilter, FluentValidationDocumentFilter and the ASP.NET Core FluentValidationOperationTransformer. NSwag is unaffected (it has no dot-path parameter logic)
  • Fixed: the document filter matched document parameters to ApiExplorer descriptions case-sensitively, so options like DescribeAllParametersInCamelCase made it skip required-marking and constraint copying. The lookup is now case-insensitive, matching the operation filter
  • Thanks to @jgarciadelanoceda for the report and the repro

Changes in 7.2.0

  • Added: the document-filter pipeline is promoted from experimental to a supported opt-in (RegistrationOptions.UseDocumentFilter, default false). The document filter processes the whole document at once and performs the unused-query-schema cleanup once at the end, so per-operation shared-DTO state issues (#223/#226) cannot occur in this pipeline — on all target frameworks, including net8.0/net9.0 where the 7.1.11 healing API is unavailable
    • Full functional parity with the default schema + operation filter pipeline: required-marking with the whole-dot-path check (#209), request bodies and encoding.contentType for [FromForm] (#216), multi-validator support, allOf/oneOf/anyOf traversal, $ref preservation for unmodified properties (#198, net10.0), and every operation of a multi-verb path is now processed (previously only the first)
    • The #209 and #216 logic is extracted into internal components shared by both pipelines, so they cannot drift apart
    • Robustness: the filter no longer fails the whole document generation on a throwing validator (top-level try/catch), falls back to ServiceProviderValidatorRegistry like the sibling filters, honors an injected IFluentValidationRuleProvider (new optional constructor parameter, appended last — source-compatible), and had its dead code, logging and nullability issues cleaned up. Behavior note: constructing FluentValidationDocumentFilter with neither validatorRegistry nor serviceProvider now throws ArgumentNullException (matching the sibling filters) instead of silently producing a filter that applies no rules; the DI registration path is unaffected
    • On net10.0 the cleanup also heals Swashbuckle's reserved-ids for processed container types (SchemaRepository.ReplaceSchemaId), so custom document filters running afterwards can regenerate them
    • ExperimentalUseDocumentFilter still works as an [Obsolete] alias forwarding to UseDocumentFilter
    • The default pipeline is unchanged; a future major version may switch the default
    • samples/MinimalApi now runs on the document-filter pipeline; README documents the option and its caveats

Changes in 7.1.11

  • Fixed: a DTO shared between a flattened [FromQuery]/[AsParameters] binding and a request body ([FromBody]/[FromForm]) in the same document could lose its FluentValidation rules, and the emitted document could contain a $ref to a removed component (Issue #226). net10.0 target only
    • Root cause: the Issue #180 cleanup left the container type "reserved-but-removed" in Swashbuckle's SchemaRepository (component removed, internal reserved-id kept). The 7.1.10 fix (#223) recovered the schema for reading constraint values, but a later [FromBody]/[FromForm] operation binding the same type made Swashbuckle emit a $ref to a component that no longer exists (confirmed empirically), and rules applied on the recovered throwaway instance never reached the document
    • Fix (net10.0 / Swashbuckle 10.x): the Issue #180 cleanup now heals the repository state via SchemaRepository.ReplaceSchemaId (public API since Swashbuckle 10.1.0) before removing a side-effect schema — the reservation is cleared together with the component, so the next operation binding the same type regenerates a full component and the rules reach the real document object. SwashbuckleSchemaProvider tracks Type → schemaId for every GetSchemaForType call (including the Issue #209 ancestor walk) to make the healing possible
    • net8.0/net9.0 keep the 7.1.10 behavior: they pin Swashbuckle 8.1.1 where ReplaceSchemaId does not exist, and bumping the minimum would force the Microsoft.OpenApi 2.x breaking change on consumers. The throwaway recovery from #223 remains as a safety net on all targets
    • Thanks to @jgarciadelanoceda for suggesting the ReplaceSchemaId approach

Changes in 7.1.10

  • Fixed: the same [FromQuery]/[AsParameters] DTO shared by more than one endpoint lost its FluentValidation rules on every endpoint after the first (Issue #223)
    • FluentValidationOperationFilter runs once per operation. The Issue #180 cleanup removes the temporary container schema from SchemaRepository.Schemas, but Swashbuckle keeps the type in its internal reserved-ids map, which the cleanup does not touch. For the 2nd+ endpoint, GetSchemaForType → GenerateSchema then returns a bare $ref (no Properties) and the schema is no longer in Schemas, so the "has properties" guard was skipped and no rules were applied. Only reproduces with the default RemoveUnusedQuerySchemas = true
    • Fix: in SwashbuckleSchemaProvider.GetSchemaForType, when the returned schema has no properties and the id is absent from the shared repository (the reserved-but-removed state), the concrete schema is recovered by generating it into a throwaway SchemaRepository. Fully isolated — it never mutates the shared repository or its reserved-id state — so the Issue #180 cleanup and all other OperationFilter behavior (required marking #209, nested [FromQuery] #211/#213, request bodies, #216) are preserved

Full release notes can be found at: https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation/blob/master/CHANGELOG.md

Version Downloads Last updated
7.2.2 4 2026-10-14
7.2.1 0 2026-07-13
7.2.0 0 2026-07-12
7.1.11 0 2026-07-12
7.1.10 0 2026-07-12
7.1.9 0 2026-07-09
7.1.8 0 2026-07-01
7.1.8-beta.2 0 2026-06-21
7.1.8-beta.1 0 2026-06-20
7.1.7 0 2026-06-20
7.1.7-beta.3 0 2026-06-17
7.1.7-beta.2 0 2026-06-17
7.1.7-beta.1 0 2026-06-15
7.1.6 0 2026-06-02
7.1.6-beta.1 0 2026-06-02
7.1.5-beta.2 0 2026-05-16
7.1.5-beta 0 2026-04-01
7.1.4 100 2026-05-26
7.1.4-beta 0 2026-03-24
7.1.3 57 2026-03-26
7.1.2 1 2026-03-16
7.1.1 0 2026-03-09
7.1.0 0 2026-03-09
7.1.0-beta.2 0 2026-03-06
7.1.0-beta.1 0 2026-02-23
7.0.6 0 2026-03-03
7.0.5 0 2026-02-26
7.0.4 0 2026-02-17
7.0.4-beta.3 0 2026-02-14
7.0.4-beta.2 0 2026-02-14
7.0.4-beta.1 0 2026-02-14
7.0.3 0 2025-12-23
7.0.2 0 2025-12-23
7.0.1 0 2025-12-08
7.0.0 0 2025-12-07
6.1.1 0 2025-09-02
6.1.0 0 2024-11-26
6.0.0 413 2025-04-15
6.0.0-beta.3 0 2023-02-19
6.0.0-beta.1 0 2022-07-23
5.7.0 0 2022-06-10
5.6.0 0 2022-05-03
5.5.0 0 2022-03-28
5.4.0 0 2021-09-19
5.3.0 0 2021-09-01
5.2.0 0 2021-07-31
5.1.0 0 2021-06-15
5.1.0-rc.2 0 2021-06-03
5.1.0-rc.1 0 2021-06-01
5.0.0 0 2021-05-30
5.0.0-rc.2 0 2021-05-18
5.0.0-rc.1 0 2021-05-16
4.3.0 0 2021-03-25
4.3.0-rc.1 0 2021-03-21
4.2.0 0 2021-02-18
4.1.0 0 2021-01-21
4.1.0-rc.1 0 2021-01-06
4.0.0 0 2020-08-21
4.0.0-rc.2 0 2020-07-18
4.0.0-rc.1 0 2020-06-15
3.2.0 0 2020-06-14
3.1.1 0 2020-04-28
3.1.0 0 2020-03-25
3.0.0 0 2020-03-07
3.0.0-rc.6 0 2020-02-05
3.0.0-rc.5 0 2020-01-24
3.0.0-rc.4 0 2019-12-29
3.0.0-rc.3 0 2019-11-28
3.0.0-rc.2 0 2019-10-13
3.0.0-rc.1 0 2019-09-30
3.0.0-beta.1 0 2019-04-26
3.0.0-alpha.1 0 2019-04-23
2.3.0 0 2019-11-14
2.2.1 0 2019-10-13
2.2.0 0 2019-08-28
2.1.1 0 2019-04-26
2.1.0 0 2019-04-08
2.0.1 0 2019-04-06
2.0.0 0 2019-03-13
2.0.0-beta.5 0 2019-02-13
2.0.0-beta.4 0 2019-02-11
2.0.0-beta.3 0 2019-01-28
2.0.0-beta.2 0 2019-01-10
2.0.0-beta.1 0 2018-11-12
1.2.0 0 2019-01-22
1.1.0 0 2018-11-10
1.0.0 0 2018-09-26
1.0.0-rc.1 0 2018-09-22
1.0.0-beta.3 0 2018-09-19
1.0.0-beta.2 0 2018-09-10
1.0.0-beta.1 0 2018-08-26
0.8.2 0 2018-06-29
0.8.1 0 2018-06-20
0.8.0 0 2018-06-12
0.8.0-beta.1 0 2018-05-11
0.7.0 0 2018-04-11
0.6.0 0 2018-04-04
0.5.0 0 2018-03-30
0.4.0 0 2018-03-29
0.3.0 0 2018-03-25
0.2.0 0 2018-03-25
0.1.0 0 2018-03-20