Skip to content

Consider MVC-style configurable child validation suppression #87

@DamianEdwards

Description

@DamianEdwards

Context

While reviewing PR #83 for #54/#73, we investigated how ASP.NET Core MVC avoids recursion-based validation issues when property getters or framework object graphs are problematic.

MVC generally does not catch exceptions from property getters during validation. Instead, it avoids traversing many risky child graphs through validation metadata:

  • ValidationEntry stores child model access lazily, so MVC can skip entries before invoking a property getter.
  • ValidationVisitor.VisitChildren checks metadata.PropertyValidationFilter?.ShouldValidateEntry(...) before evaluating entry.Model.
  • [ValidateNever] implements IPropertyValidationFilter; MVC has tests proving skipped properties are not accessed.
  • ModelMetadata.ValidateChildren can be set to false by metadata providers.
  • MVC registers default SuppressChildValidationMetadataProviders for framework/terminal types such as Type, Delegate, MethodInfo, MemberInfo, ParameterInfo, Assembly, Uri, CancellationToken, form-file types, and Stream.
  • Newtonsoft MVC setup additionally suppresses child validation for IJsonPatchDocument and JToken.

Relevant ASP.NET Core files observed:

  • src/Mvc/Mvc.Core/src/ModelBinding/Validation/ValidationVisitor.cs
  • src/Mvc/Mvc.Core/src/ModelBinding/Validation/DefaultComplexObjectValidationStrategy.cs
  • src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationEntry.cs
  • src/Mvc/Mvc.Core/src/Infrastructure/MvcCoreMvcOptionsSetup.cs
  • src/Mvc/Mvc.Core/src/ModelBinding/SuppressChildValidationMetadataProvider.cs
  • src/Mvc/Mvc.NewtonsoftJson/src/DependencyInjection/NewtonsoftJsonMvcOptionsSetup.cs

Current MiniValidation behavior

PR #83 addresses the immediate crash reports by treating delegates, reflection types, and selected JSON/dynamic framework namespaces as terminal/non-validatable types. This is directionally similar to MVC's suppression approach and avoids broad getter-exception swallowing.

However, MiniValidation's suppression list is currently hardcoded inside TypeDetailsCache.IsNonValidatableType(...). MiniValidation has [SkipRecursion] for opt-out on model members, but it does not have an MVC-like configurable global mechanism for suppressing recursion into types owned by framework/library packages.

Follow-up idea

Consider adding an options/configuration mechanism for recursive validation suppression, similar in spirit to MVC's SuppressChildValidationMetadataProvider:

  • Allow callers to configure types or predicates that should be treated as terminal for recursion.
  • Seed the default list with MVC-aligned framework types where appropriate.
  • Consider namespace/full-name based suppression for optional dependencies without taking package references, similar to MVC's XML full-type-name provider.
  • Preserve [SkipRecursion] as the per-member opt-out.
  • Avoid broad catch-and-ignore behavior for arbitrary property getter exceptions.

Possible API shapes to explore:

MiniValidator.TryValidate(model, new MiniValidationOptions
{
    SuppressChildValidationTypes = { typeof(Delegate), typeof(Uri) },
    SuppressChildValidationTypeNames = { "Newtonsoft.Json.Linq.JToken" }
}, out var errors);

or static/global defaults if an options object would be too large a change.

Questions

  • Should MiniValidation expose a configurable suppression list, or is a small built-in terminal-type list sufficient?
  • Should MVC's default suppressed types be mirrored exactly, partially, or used only as inspiration?
  • Can this be added without making the public API too option-heavy?
  • Should this be part of a future 0.11.0 feature release or deferred beyond that?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions