File: ModelBinding\Metadata\DefaultValidationMetadataProvider.cs
Web Access
Project: src\src\Mvc\Mvc.Core\src\Microsoft.AspNetCore.Mvc.Core.csproj (Microsoft.AspNetCore.Mvc.Core)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#nullable enable
 
using System.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
 
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
 
/// <summary>
/// A default implementation of <see cref="IValidationMetadataProvider"/>.
/// </summary>
internal sealed class DefaultValidationMetadataProvider : IValidationMetadataProvider
{
    /// <inheritdoc />
    public void CreateValidationMetadata(ValidationMetadataProviderContext context)
    {
        ArgumentNullException.ThrowIfNull(context);
 
        foreach (var attribute in context.Attributes)
        {
            if (attribute is IModelValidator || attribute is IClientModelValidator)
            {
                // If another provider has already added this attribute, do not repeat it.
                // This will prevent attributes like RemoteAttribute (which implement ValidationAttribute and
                // IClientModelValidator) to be added to the ValidationMetadata twice.
                // This is to ensure we do not end up with duplication validation rules on the client side.
                if (!context.ValidationMetadata.ValidatorMetadata.Contains(attribute))
                {
                    context.ValidationMetadata.ValidatorMetadata.Add(attribute);
                }
            }
        }
 
        // IPropertyValidationFilter attributes on a type affect properties in that type, not properties that have
        // that type. Thus, we ignore context.TypeAttributes for properties and not check at all for types.
        if (context.Key.MetadataKind == ModelMetadataKind.Property)
        {
            var validationFilter = context.PropertyAttributes!.OfType<IPropertyValidationFilter>().FirstOrDefault();
            if (validationFilter == null)
            {
                // No IPropertyValidationFilter attributes on the property.
                // Check if container has such an attribute.
                validationFilter = context.Key.ContainerType!
                    .GetCustomAttributes(inherit: true)
                    .OfType<IPropertyValidationFilter>()
                    .FirstOrDefault();
            }
 
            context.ValidationMetadata.PropertyValidationFilter = validationFilter;
        }
        else if (context.Key.MetadataKind == ModelMetadataKind.Parameter)
        {
            var validationFilter = context.ParameterAttributes!.OfType<IPropertyValidationFilter>().FirstOrDefault();
            context.ValidationMetadata.PropertyValidationFilter = validationFilter;
        }
    }
}