Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Commit

Permalink
Provide an alternative (suitable for patch) approach for issue #7952
Browse files Browse the repository at this point in the history
- #7968
- see 335500a and pull #7974
- see also pull #8000 (a straightforward port of the release/2.2 fix)
  • Loading branch information
dougbu committed Jul 6, 2018
1 parent 82f7f2a commit a679297
Showing 1 changed file with 23 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Internal;
Expand All @@ -15,6 +16,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
/// </summary>
public class ValidationVisitor
{
private bool _isTopLevel;

/// <summary>
/// Creates a new <see cref="ValidationVisitor"/>.
/// </summary>
Expand Down Expand Up @@ -107,6 +110,8 @@ public virtual bool Validate(ModelMetadata metadata, string key, object model, b
return true;
}

_isTopLevel = true;

return Visit(metadata, key, model);
}

Expand Down Expand Up @@ -204,6 +209,7 @@ protected virtual bool Visit(ModelMetadata metadata, string key, object model)
{
if (Metadata.IsEnumerableType)
{
_isTopLevel = false;
return VisitComplexType(DefaultCollectionValidationStrategy.Instance);
}

Expand All @@ -212,6 +218,9 @@ protected virtual bool Visit(ModelMetadata metadata, string key, object model)
return VisitComplexType(DefaultComplexObjectValidationStrategy.Instance);
}

// It's possible that a derived simple type i.e. something with a TypeConverter to string implements
// IValidatableObject. But, this is not currently supported -- base class must do the implementation.
_isTopLevel = false;
return VisitSimpleType();
}
}
Expand All @@ -221,6 +230,15 @@ protected virtual bool VisitComplexType(IValidationStrategy defaultStrategy)
{
var isValid = true;

var savedMetadata = Metadata;
if (_isTopLevel && Model != null && Model.GetType() != Metadata.ModelType)
{
// Handle the polymorphic binder case.
Metadata = MetadataProvider.GetMetadataForType(Model.GetType());
}

_isTopLevel = false;

if (Model != null && Metadata.ValidateChildren)
{
var strategy = Strategy ?? defaultStrategy;
Expand All @@ -234,6 +252,11 @@ protected virtual bool VisitComplexType(IValidationStrategy defaultStrategy)
SuppressValidation(Key);
}

// Done validating children. Restore Metadata because ValidationAttributes on a parameter or property are
// far more likely than a derived type implementing IValidatableObject. (But, could handle that case too,
// delaying this restoration and complicating ValidateNode().)
Metadata = savedMetadata;

// Double-checking HasReachedMaxErrors just in case this model has no properties.
// If validation has failed for any children, only validate the parent if ValidateComplexTypesIfChildValidationFails is true.
if ((isValid || ValidateComplexTypesIfChildValidationFails) && !ModelState.HasReachedMaxErrors)
Expand Down

0 comments on commit a679297

Please sign in to comment.