123 lines
4.0 KiB
C#
123 lines
4.0 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
|
|
|
namespace Microsoft.AspNetCore.Mvc.Internal
|
|
{
|
|
/// <summary>
|
|
/// The default implementation of <see cref="IValidationStrategy"/> for a complex object.
|
|
/// </summary>
|
|
public class DefaultComplexObjectValidationStrategy : IValidationStrategy
|
|
{
|
|
private static readonly bool IsMono = Type.GetType("Mono.Runtime") != null;
|
|
|
|
/// <summary>
|
|
/// Gets an instance of <see cref="DefaultComplexObjectValidationStrategy"/>.
|
|
/// </summary>
|
|
public static readonly IValidationStrategy Instance = new DefaultComplexObjectValidationStrategy();
|
|
|
|
private DefaultComplexObjectValidationStrategy()
|
|
{
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IEnumerator<ValidationEntry> GetChildren(
|
|
ModelMetadata metadata,
|
|
string key,
|
|
object model)
|
|
{
|
|
return new Enumerator(metadata.Properties, key, model);
|
|
}
|
|
|
|
private class Enumerator : IEnumerator<ValidationEntry>
|
|
{
|
|
private readonly string _key;
|
|
private readonly object _model;
|
|
private readonly ModelPropertyCollection _properties;
|
|
|
|
private ValidationEntry _entry;
|
|
private int _index;
|
|
|
|
public Enumerator(
|
|
ModelPropertyCollection properties,
|
|
string key,
|
|
object model)
|
|
{
|
|
_properties = properties;
|
|
_key = key;
|
|
_model = model;
|
|
|
|
_index = -1;
|
|
}
|
|
|
|
public ValidationEntry Current => _entry;
|
|
|
|
object IEnumerator.Current => Current;
|
|
|
|
public bool MoveNext()
|
|
{
|
|
_index++;
|
|
if (_index >= _properties.Count)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var property = _properties[_index];
|
|
var propertyName = property.BinderModelName ?? property.PropertyName;
|
|
var key = ModelNames.CreatePropertyModelName(_key, propertyName);
|
|
|
|
if (_model == null)
|
|
{
|
|
// Performance: Never create a delegate when container is null.
|
|
_entry = new ValidationEntry(property, key, model: null);
|
|
}
|
|
else if (IsMono)
|
|
{
|
|
_entry = new ValidationEntry(property, key, () => GetModelOnMono(_model, property.PropertyName));
|
|
}
|
|
else
|
|
{
|
|
_entry = new ValidationEntry(property, key, () => GetModel(_model, property));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
private static object GetModel(object container, ModelMetadata property)
|
|
{
|
|
return property.PropertyGetter(container);
|
|
}
|
|
|
|
// Our property accessors don't work on Mono 4.0.4 - see https://github.com/aspnet/External/issues/44
|
|
// This is a workaround for what the PropertyGetter does in the background.
|
|
private static object GetModelOnMono(object container, string propertyName)
|
|
{
|
|
var propertyInfo = container.GetType().GetRuntimeProperty(propertyName);
|
|
try
|
|
{
|
|
return propertyInfo.GetValue(container);
|
|
}
|
|
catch (TargetInvocationException ex)
|
|
{
|
|
throw ex.InnerException;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|