// 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.Generic; using System.Reflection; using Microsoft.AspNetCore.Mvc.DataAnnotations; using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal; using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; using Xunit; namespace Microsoft.AspNetCore.Mvc.ModelBinding { public class TestModelMetadataProvider : DefaultModelMetadataProvider { // Creates a provider with all the defaults - includes data annotations public static ModelMetadataProvider CreateDefaultProvider(IStringLocalizerFactory stringLocalizerFactory = null) { var detailsProviders = new IMetadataDetailsProvider[] { new DefaultBindingMetadataProvider(), new DefaultValidationMetadataProvider(), new DataAnnotationsMetadataProvider( Options.Create(new MvcDataAnnotationsLocalizationOptions()), stringLocalizerFactory), new DataMemberRequiredBindingMetadataProvider(), }; var compositeDetailsProvider = new DefaultCompositeMetadataDetailsProvider(detailsProviders); return new DefaultModelMetadataProvider(compositeDetailsProvider, Options.Create(new MvcOptions())); } public static IModelMetadataProvider CreateDefaultProvider(IList providers) { var detailsProviders = new List() { new DefaultBindingMetadataProvider(), new DefaultValidationMetadataProvider(), new DataAnnotationsMetadataProvider( Options.Create(new MvcDataAnnotationsLocalizationOptions()), stringLocalizerFactory: null), new DataMemberRequiredBindingMetadataProvider(), }; detailsProviders.AddRange(providers); var compositeDetailsProvider = new DefaultCompositeMetadataDetailsProvider(detailsProviders); return new DefaultModelMetadataProvider(compositeDetailsProvider, Options.Create(new MvcOptions())); } public static IModelMetadataProvider CreateProvider(IList providers) { var detailsProviders = new List(); if (providers != null) { detailsProviders.AddRange(providers); } var compositeDetailsProvider = new DefaultCompositeMetadataDetailsProvider(detailsProviders); return new DefaultModelMetadataProvider(compositeDetailsProvider, Options.Create(new MvcOptions())); } private readonly TestModelMetadataDetailsProvider _detailsProvider; public TestModelMetadataProvider() : this(new TestModelMetadataDetailsProvider()) { } private TestModelMetadataProvider(TestModelMetadataDetailsProvider detailsProvider) : base( new DefaultCompositeMetadataDetailsProvider(new IMetadataDetailsProvider[] { new DefaultBindingMetadataProvider(), new DefaultValidationMetadataProvider(), new DataAnnotationsMetadataProvider( Options.Create(new MvcDataAnnotationsLocalizationOptions()), stringLocalizerFactory: null), detailsProvider }), Options.Create(new MvcOptions())) { _detailsProvider = detailsProvider; } public IMetadataBuilder ForType(Type type) { var key = ModelMetadataIdentity.ForType(type); var builder = new MetadataBuilder(key); _detailsProvider.Builders.Add(builder); return builder; } public IMetadataBuilder ForType() { return ForType(typeof(TModel)); } public IMetadataBuilder ForProperty(Type containerType, string propertyName) { var property = containerType.GetRuntimeProperty(propertyName); Assert.NotNull(property); var key = ModelMetadataIdentity.ForProperty(property.PropertyType, propertyName, containerType); var builder = new MetadataBuilder(key); _detailsProvider.Builders.Add(builder); return builder; } public IMetadataBuilder ForProperty(string propertyName) { return ForProperty(typeof(TContainer), propertyName); } private class TestModelMetadataDetailsProvider : IBindingMetadataProvider, IDisplayMetadataProvider, IValidationMetadataProvider { public List Builders { get; } = new List(); public void CreateBindingMetadata(BindingMetadataProviderContext context) { foreach (var builder in Builders) { builder.Apply(context); } } public void CreateDisplayMetadata(DisplayMetadataProviderContext context) { foreach (var builder in Builders) { builder.Apply(context); } } public void CreateValidationMetadata(ValidationMetadataProviderContext context) { foreach (var builder in Builders) { builder.Apply(context); } } } public interface IMetadataBuilder { IMetadataBuilder BindingDetails(Action action); IMetadataBuilder DisplayDetails(Action action); IMetadataBuilder ValidationDetails(Action action); } private class MetadataBuilder : IMetadataBuilder { private List> _bindingActions = new List>(); private List> _displayActions = new List>(); private List> _valiationActions = new List>(); private readonly ModelMetadataIdentity _key; public MetadataBuilder(ModelMetadataIdentity key) { _key = key; } public void Apply(BindingMetadataProviderContext context) { if (_key.Equals(context.Key)) { foreach (var action in _bindingActions) { action(context.BindingMetadata); } } } public void Apply(DisplayMetadataProviderContext context) { if (_key.Equals(context.Key)) { foreach (var action in _displayActions) { action(context.DisplayMetadata); } } } public void Apply(ValidationMetadataProviderContext context) { if (_key.Equals(context.Key)) { foreach (var action in _valiationActions) { action(context.ValidationMetadata); } } } public IMetadataBuilder BindingDetails(Action action) { _bindingActions.Add(action); return this; } public IMetadataBuilder DisplayDetails(Action action) { _displayActions.Add(action); return this; } public IMetadataBuilder ValidationDetails(Action action) { _valiationActions.Add(action); return this; } } } }