Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 30 additions & 38 deletions src/MiniValidation/MiniValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -378,9 +378,8 @@ private static async Task<bool> TryValidateImpl(
}

// Once we get to this point we have to box the target in order to track whether we've validated it or not
if (validatedObjects.ContainsKey(target))
if (validatedObjects.TryGetValue(target, out var result))
{
var result = validatedObjects[target];
// If there's a null result it means this object is the one currently being validated
// so just skip this reference to it by returning true. If there is a result it means
// we already validated this object as part of this validation operation.
Expand Down Expand Up @@ -436,11 +435,11 @@ private static async Task<bool> TryValidateImpl(
if (recurse && currentDepth <= MaxDepth)
{
// Validate IEnumerable
if (target is IEnumerable)
if (target is IEnumerable targets)
{
RuntimeHelpers.EnsureSufficientExecutionStack();

var validateTask = TryValidateEnumerable(target, serviceProvider, recurse, allowAsync, workingErrors, validatedObjects, validationResults, prefix, currentDepth);
var validateTask = TryValidateEnumerable(targets, serviceProvider, recurse, allowAsync, workingErrors, validatedObjects, validationResults, prefix, currentDepth);

try
{
Expand Down Expand Up @@ -468,11 +467,11 @@ private static async Task<bool> TryValidateImpl(
{
RuntimeHelpers.EnsureSufficientExecutionStack();

if (propertyDetails.IsEnumerable)
if (propertyDetails.IsEnumerable && propertyValue is IEnumerable propertyValues)
{
var thePrefix = $"{prefix}{propertyDetails.Name}";

var validateTask = TryValidateEnumerable(propertyValue, serviceProvider, recurse, allowAsync, workingErrors, validatedObjects, validationResults, thePrefix, currentDepth);
var validateTask = TryValidateEnumerable(propertyValues, serviceProvider, recurse, allowAsync, workingErrors, validatedObjects, validationResults, thePrefix, currentDepth);
try
{
ThrowIfAsyncNotAllowed(validateTask.IsCompleted, allowAsync);
Expand All @@ -486,7 +485,7 @@ private static async Task<bool> TryValidateImpl(

isValid = await validateTask.ConfigureAwait(false) && isValid;
}
else
else if (!propertyDetails.IsEnumerable)
{
var thePrefix = $"{prefix}{propertyDetails.Name}."; // <-- Note trailing '.' here

Expand All @@ -509,10 +508,8 @@ private static async Task<bool> TryValidateImpl(
}
}

if (typeof(IValidatableObject).IsAssignableFrom(targetType))
if (target is IValidatableObject validatable)
{
var validatable = (IValidatableObject)target;

// Reset validation context
validationContext.MemberName = null;
validationContext.DisplayName = validationContext.ObjectType.Name;
Expand All @@ -524,15 +521,13 @@ private static async Task<bool> TryValidateImpl(
}
}

if ((isValid || allowAsync) && typeof(IAsyncValidatableObject).IsAssignableFrom(targetType))
if ((isValid || allowAsync) && target is IAsyncValidatableObject asyncValidatable)
{
var validatable = (IAsyncValidatableObject)target;

// Reset validation context
validationContext.MemberName = null;
validationContext.DisplayName = validationContext.ObjectType.Name;

var validateTask = validatable.ValidateAsync(validationContext);
var validateTask = asyncValidatable.ValidateAsync(validationContext);
ThrowIfAsyncNotAllowed(validateTask.IsCompleted, allowAsync);

var validatableResults = await validateTask.ConfigureAwait(false);
Expand Down Expand Up @@ -566,7 +561,7 @@ private static async ValueTask<bool> TryValidateEnumerable(
#else
private static async Task<bool> TryValidateEnumerable(
#endif
object target,
IEnumerable items,
IServiceProvider? serviceProvider,
bool recurse,
bool allowAsync,
Expand All @@ -577,34 +572,31 @@ private static async Task<bool> TryValidateEnumerable(
int currentDepth = 0)
{
var isValid = true;
if (target is IEnumerable items)
// Validate each instance in the collection
var index = 0;
foreach (var item in items)
{
// Validate each instance in the collection
var index = 0;
foreach (var item in items)
if (item is null)
{
if (item is null)
{
continue;
}

var itemPrefix = $"{prefix}[{index}].";
continue;
}

var validateTask = TryValidateImpl(item, serviceProvider, recurse, allowAsync, workingErrors, validatedObjects, validationResults, itemPrefix, currentDepth + 1);
try
{
ThrowIfAsyncNotAllowed(validateTask.IsCompleted, allowAsync);
}
catch (Exception)
{
// Always observe the ValueTask
_ = await validateTask.ConfigureAwait(false);
throw;
}
var itemPrefix = $"{prefix}[{index}].";

isValid = await validateTask.ConfigureAwait(false) && isValid;
index++;
var validateTask = TryValidateImpl(item, serviceProvider, recurse, allowAsync, workingErrors, validatedObjects, validationResults, itemPrefix, currentDepth + 1);
try
{
ThrowIfAsyncNotAllowed(validateTask.IsCompleted, allowAsync);
}
catch (Exception)
{
// Always observe the ValueTask
_ = await validateTask.ConfigureAwait(false);
throw;
}

isValid = await validateTask.ConfigureAwait(false) && isValid;
index++;
}
return isValid;
}
Expand Down
Loading