Releases: micro-elements/MicroElements.Swashbuckle.FluentValidation
Release list
7.1.8
🔒 Security fix — Issue #220
Closes the transitive high-severity advisory GHSA-v5pm-xwqc-g5wc / CVE-2026-49451 (CVSS 7.5, CWE-674 Uncontrolled Recursion — a circular $ref schema could stack-overflow the OpenAPI reader; availability / process-termination only).
- Bumped
Swashbuckle.AspNetCore.SwaggerGen10.0.0→10.2.1on the net10.0 target, which resolves the transitiveMicrosoft.OpenApifrom the vulnerable2.3.0to the patched2.7.5. - The net8.0 / net9.0 targets use Swashbuckle
8.1.1→Microsoft.OpenApiv1 and were never in the advisory range — left unchanged. - No public API or OpenAPI output changes — dependency + version bump only.
📎 IFormFile media type & file size validation — Issue #216
Stable rollup of the work previously shipped as 7.1.8-beta.1 / 7.1.8-beta.2:
- New File-level FluentValidation rules in
MicroElements.OpenApi.FluentValidation.FileUpload:.FileContentType(params string[]),.MaxFileSize(long),.MinFileSize(long),.FileSizeBetween(long, long)onIRuleBuilder<T, IFormFile>. - Swashbuckle, NSwag, and Microsoft.AspNetCore.OpenApi emit
multipart/form-dataencoding.contentTypefor file parts and append the allowed types / size limits to the file propertydescription. - Purely additive / opt-in — output only changes when the new rules are used.
Full changelog: https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation/blob/master/CHANGELOG.md
7.1.8-beta.2
Pre-release for #216 — tracks PR #218.
Adds to 7.1.8-beta.1: Microsoft.AspNetCore.OpenApi now emits encoding.contentType for the file part (the backend Scalar uses), so the allowed media types are machine-readable in the document, not only in the description:
multipart/form-data:
schema: { $ref: "#/components/schemas/UploadProductImageRequest" } # net10
encoding:
File:
contentType: "image/jpeg, image/png"Works on net9 (inline form schema) and net10 (resolves the whole-body $ref component to find the part name). Backend matrix is now content-type+size on all three backends, both as description and encoding.contentType.
Pre-release built from branch
feature/issue-216-media-types(not yet merged to master).
7.1.8-beta.1
Pre-release for #216 — media type (content type) & file size validation for IFormFile uploads. Tracks PR #218.
New File-level FluentValidation rules (MicroElements.OpenApi.FluentValidation.FileUpload):
RuleFor(x => x.File)
.NotNull()
.FileContentType("image/jpeg", "image/png")
.MaxFileSize(2 * 1024 * 1024);Also: .MinFileSize(long), .FileSizeBetween(long, long). They enforce at runtime and drive OpenAPI.
| Backend | content type + size in description |
encoding.contentType |
|---|---|---|
| Swashbuckle | ✅ | ✅ (net8/9 = OAS 3.0; net10 = OAS 3.1) |
| NSwag | ✅ | ✅ via FluentValidationOperationProcessor (encodingType — NSwag limitation) |
| Microsoft.AspNetCore.OpenApi | ✅ | ❌ not emitted |
Additive / opt-in — no existing document output changes. See CHANGELOG and PR #218.
Pre-release built from branch
feature/issue-216-media-types(not yet merged to master).
7.1.7
Stable release 7.1.7 — promotes 7.1.7-beta.3 to stable.
Fixed
- Nested
[FromQuery]fixes (#209 + #211) now also apply to the nativeMicrosoft.AspNetCore.OpenApitransformer and the experimental Swashbuckle DocumentFilter (Issue #213)FluentValidationOperationTransformernow follows the same reachability + ancestor-required rules as the SwashbuckleOperationFilter- The experimental
FluentValidationDocumentFilterno longer copies value constraints onto a flattened nested parameter whose nested validation is not wired from the root validator GetMethodInfonow resolves the action method fromControllerActionDescriptor(MVC controllers), not only minimal-API endpoint metadata- NSwag is unaffected (it has no
[FromQuery]parameter flattening)
- A validator for a nested type bound via
[FromQuery]was reflected in the OpenAPI document even when it was not wired into the root validator viaSetValidator/ChildRules(Issue #211)- Nested rules are now applied only when the
SetValidator/ChildRuleschain from the action's root[FromQuery]validator actually reaches the leaf container - Behavioral change: when no validator is registered for the root
[FromQuery]type, a flattened nested parameter is left unconstrained — matching runtime
- Nested rules are now applied only when the
- A required leaf property inside an optional nested type bound via
[FromQuery]was wrongly marked as a required parameter (Issue #209)- A flattened nested parameter is now marked
requiredonly when every ancestor segment of the dot-path is required - Value constraints (e.g.
minLength) still apply to an optional nested parameter when it is provided
- A flattened nested parameter is now marked
Full changelog: CHANGELOG.md
7.1.7-beta.3
- Fixed: The nested
[FromQuery]fixes (#209 + #211) now also apply to the nativeMicrosoft.AspNetCore.OpenApitransformer and the experimental Swashbuckle DocumentFilter (Issue #213)FluentValidationOperationTransformer(packageMicroElements.AspNetCore.OpenApi.FluentValidation) previously set a nested parameterrequiredfrom the leaf validator alone — ignoring both whether theSetValidator/ChildRuleschain reaches the leaf (#211) and whether every ancestor of the dot-path is required (#209). It now follows the same reachability + ancestor-required rules as the SwashbuckleOperationFilter- The experimental
FluentValidationDocumentFilterno longer copies value constraints onto a flattened nested parameter whose nested validation is not wired from the root validator (#211) GetMethodInfonow resolves the action method fromControllerActionDescriptor(MVC controllers), not only minimal-API endpoint metadata, so the dot-path root type can be resolved for controller actions- NSwag is unaffected (it has no
[FromQuery]parameter flattening)
- Fixed: A validator for a nested type bound via
[FromQuery]was reflected in the OpenAPI document even when it was not wired into the root validator viaSetValidator/ChildRules(Issue #211)FluentValidationOperationFilterresolved the leaf container's validator directly from the registry (byModelMetadata.ContainerType), so a nestedNotEmpty()marked the flattened parameter (e.g.RequiredSubType.SubProperty) asrequiredeven though FluentValidation never validates an unwired child object — the OpenAPI doc claimedrequired, but the API accepted requests without it- Fix: for a flattened nested parameter, nested rules are now applied only when the
SetValidator/ChildRuleschain from the action's root[FromQuery]validator actually reaches the leaf container; otherwise the parameter is left unconstrained, matching runtime behavior - When the root container type cannot be resolved, prior behavior is preserved (no regression for existing nested-parameter scenarios)
- Behavioral change: when no validator is registered for the root
[FromQuery]type (only a leaf/child validator is registered), a flattened nested parameter is now left unconstrained — matching runtime, where no validation runs without a root validator
- Fixed: A required leaf property inside an optional nested type bound via
[FromQuery]was wrongly marked as a required parameter (Issue #209)- The 7.1.1 fix (Issue #162) made nested
[FromQuery]validation match the leaf property name, butFluentValidationOperationFilterthen setrequiredbased solely on the leaf type, ignoring whether the ancestor segment of the dot-path was optional - Because two nested properties of the same leaf type share one schema/validator (e.g.
OptionalSubType.SubPropertyandRequiredSubType.SubProperty), aNotEmpty()on the leaf marked both flattened parameters as required - Fix: a flattened nested parameter is now marked
requiredonly when every ancestor segment of the dot-path is required — resolved from the action's root[FromQuery]type, combining the native schemarequired(e.g. the C#requiredmodifier) with FluentValidationNotNull/NotEmptyrules - Value constraints (e.g.
minLength) still apply to an optional nested parameter when it is provided - When the root container type cannot be resolved, prior behavior is preserved (no regression for existing nested-parameter scenarios)
- The 7.1.1 fix (Issue #162) made nested
7.1.7-beta.2
- Fixed: A validator for a nested type bound via
[FromQuery]was reflected in the OpenAPI document even when it was not wired into the root validator viaSetValidator/ChildRules(Issue #211)FluentValidationOperationFilterresolved the leaf container's validator directly from the registry (byModelMetadata.ContainerType), so a nestedNotEmpty()marked the flattened parameter (e.g.RequiredSubType.SubProperty) asrequiredeven though FluentValidation never validates an unwired child object — the OpenAPI doc claimedrequired, but the API accepted requests without it- Fix: for a flattened nested parameter, nested rules are now applied only when the
SetValidator/ChildRuleschain from the action's root[FromQuery]validator actually reaches the leaf container; otherwise the parameter is left unconstrained, matching runtime behavior - When the root container type cannot be resolved, prior behavior is preserved (no regression for existing nested-parameter scenarios)
- Behavioral change: when no validator is registered for the root
[FromQuery]type (only a leaf/child validator is registered), a flattened nested parameter is now left unconstrained — matching runtime, where no validation runs without a root validator
- Fixed: A required leaf property inside an optional nested type bound via
[FromQuery]was wrongly marked as a required parameter (Issue #209)- The 7.1.1 fix (Issue #162) made nested
[FromQuery]validation match the leaf property name, butFluentValidationOperationFilterthen setrequiredbased solely on the leaf type, ignoring whether the ancestor segment of the dot-path was optional - Because two nested properties of the same leaf type share one schema/validator (e.g.
OptionalSubType.SubPropertyandRequiredSubType.SubProperty), aNotEmpty()on the leaf marked both flattened parameters as required - Fix: a flattened nested parameter is now marked
requiredonly when every ancestor segment of the dot-path is required — resolved from the action's root[FromQuery]type, combining the native schemarequired(e.g. the C#requiredmodifier) with FluentValidationNotNull/NotEmptyrules - Value constraints (e.g.
minLength) still apply to an optional nested parameter when it is provided - When the root container type cannot be resolved, prior behavior is preserved (no regression for existing nested-parameter scenarios)
- The 7.1.1 fix (Issue #162) made nested
7.1.6
Stable 7.1.6 (supersedes the unreleased 7.1.5 betas).
Changes
- Fixed:
$refreplaced with an inline copy (and the child component left orphaned) when a nested object's constraints come fromChildRulesor an inline child validator (#198, #206).- The 7.1.3 fix restored unmodified
$refs, but when the nested type had no standalone validator its component schema gained itsrequiredonly after the parent's inline snapshot — the stalerequireddiverged and defeated the restore check. TheRequiredcomparison inHasValidationConstraintChangesis now directional. SetValidator(with a standalone child validator) was already correct;BigInteger/enum per-model constraints (#146/#176) continue to work.
- The 7.1.3 fix restored unmodified
- Added:
ConditionalRulesModeoption to control how.When()/.Unless()conditional rules are handled (Exclude(default) /Include/IncludeWithWarning) (#203). - Fixed: Multiple
.Matches()rules on one property rendered incorrectly (only the first pattern shown). They are now combined into a singlepatternvia lookahead assertions, across Swashbuckle,MicroElements.AspNetCore.OpenApi.FluentValidation, and NSwag (#204, #205).- Changed: default of
SchemaGenerationOptions.UseAllOfForMultipleRulestrue→false; set it totrueto keep the legacyallOfrepresentation.
- Changed: default of
NuGet: https://www.nuget.org/packages/MicroElements.Swashbuckle.FluentValidation/7.1.6
7.1.6-beta.1
Pre-release for the upcoming 7.1.6.
Changes since 7.1.5-beta.2
- Fixed:
$refstill replaced with an inline copy (and the child component left orphaned) when nested object constraints come fromChildRulesor an inline child validator (#198, #206).- The 7.1.3 fix restored unmodified
$refs, but when the nested type has no standalone validator its component schema gains itsrequiredonly after the parent's inline snapshot is taken, so the stalerequireddiverged and defeated the restore check — leaving an inline copy and an orphaned component. - Fix: the
Requiredcomparison inHasValidationConstraintChangesis now directional — restoration is only blocked when the inline copy carries a required entry the component lacks. SetValidator(with a standalone child validator) was already correct;BigInteger/enum per-model constraints (#146/#176) continue to work.
- The 7.1.3 fix restored unmodified
NuGet: https://www.nuget.org/packages/MicroElements.Swashbuckle.FluentValidation/7.1.6-beta.1
7.1.5-beta.2
Pre-release for the upcoming 7.1.5.
Changes since 7.1.5-beta
- Fixed: Multiple
.Matches()rules on one property displayed incorrectly — only the first pattern shown, property duplicated (#204, #205).- Multiple patterns were placed into separate
allOfsubschemas, which Swagger UI/Redoc/Scalar collapse, keeping only the firstpattern. - Now multiple
.Matches()rules are combined into a singlepatternvia lookahead assertions, preserving.Matches()semantics and rendering correctly. - Applied to all providers: Swashbuckle,
MicroElements.AspNetCore.OpenApi.FluentValidation, and NSwag. - Behavior change:
SchemaGenerationOptions.UseAllOfForMultipleRulesdefaulttrue→false; set it totrueto keep the legacyallOfrepresentation.
- Multiple patterns were placed into separate
Already in 7.1.5-beta
- Added:
ConditionalRulesModeoption to control how.When()/.Unless()conditional rules are handled during schema generation (#203).
See CHANGELOG.md for full details.
v7.1.5-beta
What's New
ConditionalRulesMode option (Issue #203)
Controls how conditional validation rules (.When(), .Unless()) are handled during OpenAPI schema generation.
Modes:
Exclude(default) — conditional rules are excluded from schema (backward-compatible)Include— conditional rules are included in schemaIncludeWithWarning— same as Include, but logs a warning for each conditional rule
Usage:
services.AddFluentValidationRulesToSwagger(options =>
{
options.ConditionalRules = ConditionalRulesMode.Include;
});Why: When users write .When(x => x.Prop is not null) as a null-guard, validation constraints (minLength, maxLength, etc.) were silently dropped from the schema. This option lets users opt-in to including those constraints.