Rationale
MVC can now consume generated validation OpenAPI contracts through [ProducesPortableValidationProblemFor<TValidator>], but it does not yet have feature parity with Minimal APIs for endpoint-local customization. Minimal APIs can apply the generated validator contract and then append additional builder calls through the configure callback. MVC attributes currently rely on named properties after construction, and array properties such as ErrorCodes, InlineErrorMetadataCodes, and ErrorExamples replace generated metadata instead of appending to it.
This plan adds an attribute-friendly additive customization path for MVC while keeping the source generator framework-neutral.
Acceptance Criteria
Technical Details
Add a second MVC attribute type in Light.PortableResults.Validation.OpenApi which is called ProducesPortableValidationProblemForAttribute<TValidator, TEndpointContract>. It should inherit from ProducesPortableValidationProblemAttribute and constrain both generic parameters to IPortableValidationOpenApiContract.
The constructor should accept the same status code and content type values as the existing MVC source-generation attribute. It should create one PortableValidationProblemOpenApiBuilder for this, call TValidator.ConfigurePortableValidationOpenApi(builder) first, and then call TEndpointContract.ConfigurePortableValidationOpenApi(builder) second. This mirrors Minimal API ordering where generated metadata is applied before the endpoint-local configure callback.
Endpoint-local MVC customization should be expressed as a small hand-written contract type implementing IPortableValidationOpenApiContract. That type provides a static ConfigurePortableValidationOpenApi method and can call the same builder APIs as Minimal APIs: UseFormat, WithMetadata, WithErrorCodes, WithErrorMetadata, typed validation helper extensions, WithErrorExample, and AllowUnknownErrorCodes.
Do not change ValidatorOpenApiAnalyzer, ValidatorOpenApiEmitter, or generated validator source. The existing one-generic-parameter MVC attribute remains the simple path for endpoints that only need generated validator metadata plus scalar named-property overrides.
Add unit tests for the new attribute proving that endpoint-local metadata appends to generated arrays instead of replacing them. Add MVC OpenAPI document integration tests comparing the new two-contract MVC attribute with an equivalent Minimal API endpoint using the configure callback. Update README source-generation examples to show Minimal API callback customization and MVC contract-based customization side by side.
Keep the test code coverage at least above 90%.
Rationale
MVC can now consume generated validation OpenAPI contracts through
[ProducesPortableValidationProblemFor<TValidator>], but it does not yet have feature parity with Minimal APIs for endpoint-local customization. Minimal APIs can apply the generated validator contract and then append additional builder calls through theconfigurecallback. MVC attributes currently rely on named properties after construction, and array properties such asErrorCodes,InlineErrorMetadataCodes, andErrorExamplesreplace generated metadata instead of appending to it.This plan adds an attribute-friendly additive customization path for MVC while keeping the source generator framework-neutral.
Acceptance Criteria
PortableValidationProblemOpenApiBuildercustomization surface that Minimal APIs support inProducesPortableValidationProblemFor<TValidator>(configure: ...).[ProducesPortableValidationProblemFor<TValidator>]behavior remains unchanged.IPortableValidationOpenApiContract.Light.PortableResults.AspNetCore.Mvc.Technical Details
Add a second MVC attribute type in
Light.PortableResults.Validation.OpenApiwhich is calledProducesPortableValidationProblemForAttribute<TValidator, TEndpointContract>. It should inherit fromProducesPortableValidationProblemAttributeand constrain both generic parameters toIPortableValidationOpenApiContract.The constructor should accept the same status code and content type values as the existing MVC source-generation attribute. It should create one
PortableValidationProblemOpenApiBuilderforthis, callTValidator.ConfigurePortableValidationOpenApi(builder)first, and then callTEndpointContract.ConfigurePortableValidationOpenApi(builder)second. This mirrors Minimal API ordering where generated metadata is applied before the endpoint-localconfigurecallback.Endpoint-local MVC customization should be expressed as a small hand-written contract type implementing
IPortableValidationOpenApiContract. That type provides a staticConfigurePortableValidationOpenApimethod and can call the same builder APIs as Minimal APIs:UseFormat,WithMetadata,WithErrorCodes,WithErrorMetadata, typed validation helper extensions,WithErrorExample, andAllowUnknownErrorCodes.Do not change
ValidatorOpenApiAnalyzer,ValidatorOpenApiEmitter, or generated validator source. The existing one-generic-parameter MVC attribute remains the simple path for endpoints that only need generated validator metadata plus scalar named-property overrides.Add unit tests for the new attribute proving that endpoint-local metadata appends to generated arrays instead of replacing them. Add MVC OpenAPI document integration tests comparing the new two-contract MVC attribute with an equivalent Minimal API endpoint using the
configurecallback. Update README source-generation examples to show Minimal API callback customization and MVC contract-based customization side by side.Keep the test code coverage at least above 90%.