/// <summary>
 /// Creates a new <see cref="DefaultModelMetadata"/>.
 /// </summary>
 /// <param name="provider">The <see cref="IModelMetadataProvider"/>.</param>
 /// <param name="detailsProvider">The <see cref="ICompositeMetadataDetailsProvider"/>.</param>
 /// <param name="details">The <see cref="DefaultMetadataDetails"/>.</param>
 public DefaultModelMetadata(
     IModelMetadataProvider provider,
     ICompositeMetadataDetailsProvider detailsProvider,
     DefaultMetadataDetails details)
     : this(provider, detailsProvider, details, new DefaultModelBindingMessageProvider())
 {
 }
        public void DefaultValues()
        {
            // Arrange
            var provider        = new EmptyModelMetadataProvider();
            var detailsProvider = new DefaultCompositeMetadataDetailsProvider(
                Enumerable.Empty <IMetadataDetailsProvider>());

            var key   = ModelMetadataIdentity.ForType(typeof(string));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            // Act
            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Assert
            Assert.NotNull(metadata.AdditionalValues);
            Assert.Empty(metadata.AdditionalValues);
            Assert.Equal(typeof(string), metadata.ModelType);

            Assert.True(metadata.ConvertEmptyStringToNull);
            Assert.False(metadata.HasNonDefaultEditFormat);
            Assert.False(metadata.HideSurroundingHtml);
            Assert.True(metadata.HtmlEncode);
            Assert.True(metadata.IsBindingAllowed);
            Assert.False(metadata.IsBindingRequired);
            Assert.False(metadata.IsCollectionType);
            Assert.False(metadata.IsComplexType);
            Assert.False(metadata.IsEnumerableType);
            Assert.False(metadata.IsEnum);
            Assert.False(metadata.IsFlagsEnum);
            Assert.False(metadata.IsNullableValueType);
            Assert.False(metadata.IsReadOnly);
            Assert.False(metadata.IsRequired); // Defaults to false for reference types
            Assert.True(metadata.ShowForDisplay);
            Assert.True(metadata.ShowForEdit);
            Assert.False(metadata.ValidateChildren); // Defaults to true for complex and enumerable types.

            Assert.Null(metadata.DataTypeName);
            Assert.Null(metadata.Description);
            Assert.Null(metadata.DisplayFormatString);
            Assert.Null(metadata.DisplayName);
            Assert.Null(metadata.EditFormatString);
            Assert.Null(metadata.ElementMetadata);
            Assert.Null(metadata.EnumGroupedDisplayNamesAndValues);
            Assert.Null(metadata.EnumNamesAndValues);
            Assert.Null(metadata.NullDisplayText);
            Assert.Null(metadata.PropertyValidationFilter);
            Assert.Null(metadata.SimpleDisplayProperty);
            Assert.Null(metadata.Placeholder);
            Assert.Null(metadata.TemplateHint);

            Assert.Equal(10000, ModelMetadata.DefaultOrder);
            Assert.Equal(ModelMetadata.DefaultOrder, metadata.Order);

            Assert.Null(metadata.BinderModelName);
            Assert.Null(metadata.BinderType);
            Assert.Null(metadata.BindingSource);
            Assert.Null(metadata.PropertyFilterProvider);
        }
 /// <summary>
 /// Creates a new <see cref="DefaultModelMetadata"/>.
 /// </summary>
 /// <param name="provider">The <see cref="IModelMetadataProvider"/>.</param>
 /// <param name="detailsProvider">The <see cref="ICompositeMetadataDetailsProvider"/>.</param>
 /// <param name="details">The <see cref="DefaultMetadataDetails"/>.</param>
 /// <param name="modelBindingMessageProvider">The <see cref="Metadata.DefaultModelBindingMessageProvider"/>.</param>
 public DefaultModelMetadata(
     IModelMetadataProvider provider,
     ICompositeMetadataDetailsProvider detailsProvider,
     DefaultMetadataDetails details,
     DefaultModelBindingMessageProvider modelBindingMessageProvider)
     : base(details.Key)
 {
     _provider                    = provider ?? throw new ArgumentNullException(nameof(provider));
     _detailsProvider             = detailsProvider ?? throw new ArgumentNullException(nameof(detailsProvider));
     _details                     = details ?? throw new ArgumentNullException(nameof(details));
     _modelBindingMessageProvider = modelBindingMessageProvider ?? throw new ArgumentNullException(nameof(modelBindingMessageProvider));
 }
        public void ValidateChildren_ComplexAndEnumerableTypes(Type modelType)
        {
            // Arrange
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
            var provider        = new DefaultModelMetadataProvider(detailsProvider);

            var key   = ModelMetadataIdentity.ForType(typeof(TypeWithProperties));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var validateChildren = metadata.ValidateChildren;

            // Assert
            Assert.True(validateChildren);
        }
        public void IsRequired_ReturnsTrue_ForNonNullableTypes(Type modelType)
        {
            // Arrange
            var provider        = new EmptyModelMetadataProvider();
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var key   = ModelMetadataIdentity.ForType(modelType);
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var isRequired = metadata.IsRequired;

            // Assert
            Assert.True(isRequired);
        }
        public void CreateMetadataForProperty()
        {
            // Arrange
            var provider        = new EmptyModelMetadataProvider();
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var key   = ModelMetadataIdentity.ForProperty(typeof(string), "Message", typeof(Exception));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0], new object[0]));

            // Act
            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Assert
            Assert.Equal(typeof(string), metadata.ModelType);
            Assert.Equal("Message", metadata.PropertyName);
            Assert.Equal(typeof(Exception), metadata.ContainerType);
        }
        public void ElementMetadata_ReturnsNull_ForNonCollections(Type modelType)
        {
            // Arrange
            var provider        = new EmptyModelMetadataProvider();
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var key   = ModelMetadataIdentity.ForType(modelType);
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var elementMetadata = metadata.ElementMetadata;

            // Assert
            Assert.Null(elementMetadata);
        }
Exemple #8
0
        public void ValidateChildren_SimpleTypes(Type modelType)
        {
            // Arrange
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
            var provider        = new DefaultModelMetadataProvider(detailsProvider);

            var key   = ModelMetadataIdentity.ForType(modelType);
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0], null, null));

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var validateChildren = metadata.ValidateChildren;

            // Assert
            Assert.False(validateChildren);
        }
        public void IsReadOnly_ReturnsFalse_ForPublicSetProperty()
        {
            // Arrange
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
            var provider        = new DefaultModelMetadataProvider(detailsProvider);

            var key   = ModelMetadataIdentity.ForType(typeof(TypeWithProperties));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var isReadOnly = metadata.Properties["PublicGetPublicSetProperty"].IsReadOnly;

            // Assert
            Assert.False(isReadOnly);
        }
        public void CreateMetadataForType()
        {
            // Arrange
            var provider        = new EmptyModelMetadataProvider();
            var detailsProvider = new DefaultCompositeMetadataDetailsProvider(
                Enumerable.Empty <IMetadataDetailsProvider>());

            var key   = ModelMetadataIdentity.ForType(typeof(Exception));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            // Act
            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Assert
            Assert.Equal(typeof(Exception), metadata.ModelType);
            Assert.Null(metadata.PropertyName);
            Assert.Null(metadata.ContainerType);
        }
Exemple #11
0
        public void ElementMetadata_ReturnsExpectedMetadata(Type modelType, Type elementType)
        {
            // Arrange
            var provider        = new EmptyModelMetadataProvider();
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var key   = ModelMetadataIdentity.ForType(modelType);
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0], null, null));

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var elementMetadata = metadata.ElementMetadata;

            // Assert
            Assert.NotNull(elementMetadata);
            Assert.Equal(elementType, elementMetadata.ModelType);
        }
        public void PropertiesSetOnce()
        {
            // Arrange
            var provider        = new EmptyModelMetadataProvider();
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var key   = ModelMetadataIdentity.ForType(typeof(string));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var firstPropertiesEvaluation  = metadata.Properties;
            var secondPropertiesEvaluation = metadata.Properties;

            // Assert
            // Same IEnumerable<ModelMetadata> object.
            Assert.Same(firstPropertiesEvaluation, secondPropertiesEvaluation);
        }
        public void PropertiesProperty_OrdersPropertyNamesUsingOrder_ThenAsProvided(
            IEnumerable <KeyValuePair <string, int> > originalNamesAndOrders,
            IEnumerable <string> expectedNames)
        {
            // Arrange
            var provider        = new Mock <IModelMetadataProvider>(MockBehavior.Strict);
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var expectedProperties = new List <DefaultModelMetadata>();

            foreach (var kvp in originalNamesAndOrders)
            {
                var propertyCache = new DefaultMetadataDetails(
                    ModelMetadataIdentity.ForProperty(typeof(int), kvp.Key, typeof(string)),
                    attributes: new ModelAttributes(new object[0], new object[0], null))
                {
                    DisplayMetadata = new DisplayMetadata(),
                };

                propertyCache.DisplayMetadata.Order = kvp.Value;

                expectedProperties.Add(new DefaultModelMetadata(
                                           provider.Object,
                                           detailsProvider,
                                           propertyCache));
            }

            provider
            .Setup(p => p.GetMetadataForProperties(typeof(string)))
            .Returns(expectedProperties);

            var key   = ModelMetadataIdentity.ForType(typeof(string));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0], null, null));

            var metadata = new DefaultModelMetadata(provider.Object, detailsProvider, cache);

            // Act
            var properties = metadata.Properties;

            // Assert
            Assert.Equal(expectedNames.Count(), properties.Count);
            Assert.Equal(expectedNames.ToArray(), properties.Select(p => p.PropertyName).ToArray());
        }
        public void PropertiesEnumerationEvaluatedOnce()
        {
            // Arrange
            var provider        = new EmptyModelMetadataProvider();
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var key   = ModelMetadataIdentity.ForType(typeof(string));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var firstPropertiesEvaluation  = metadata.Properties.ToList();
            var secondPropertiesEvaluation = metadata.Properties.ToList();

            // Assert
            // Identical ModelMetadata objects every time we run through the Properties collection.
            Assert.Equal(firstPropertiesEvaluation, secondPropertiesEvaluation);
        }
        public void GetMetadataForProperties_CallsProvider()
        {
            // Arrange
            var detailsProvider  = new Mock <ICompositeMetadataDetailsProvider>();
            var key              = ModelMetadataIdentity.ForType(typeof(string));
            var cache            = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));
            var metadataProvider = new Mock <IModelMetadataProvider>();

            metadataProvider
            .Setup(mp => mp.GetMetadataForProperties(typeof(Exception)))
            .Verifiable();
            var metadata1 = new DefaultModelMetadata(metadataProvider.Object, detailsProvider.Object, cache);

            // Act
            var metadata2 = metadata1.GetMetadataForProperties(typeof(Exception));

            // Assert
            metadataProvider.VerifyAll();
        }
        public void PropertiesProperty_CallsProvider()
        {
            // Arrange
            var provider        = new Mock <IModelMetadataProvider>(MockBehavior.Strict);
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var expectedProperties = new DefaultModelMetadata[]
            {
                new DefaultModelMetadata(
                    provider.Object,
                    detailsProvider,
                    new DefaultMetadataDetails(
                        ModelMetadataIdentity.ForProperty(typeof(int), "Prop1", typeof(string)),
                        attributes: new ModelAttributes(new object[0], new object[0]))),
                new DefaultModelMetadata(
                    provider.Object,
                    detailsProvider,
                    new DefaultMetadataDetails(
                        ModelMetadataIdentity.ForProperty(typeof(int), "Prop2", typeof(string)),
                        attributes: new ModelAttributes(new object[0], new object[0]))),
            };

            provider
            .Setup(p => p.GetMetadataForProperties(typeof(string)))
            .Returns(expectedProperties);

            var key   = ModelMetadataIdentity.ForType(typeof(string));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            var metadata = new DefaultModelMetadata(provider.Object, detailsProvider, cache);

            // Act
            var properties = metadata.Properties;

            // Assert
            Assert.Equal(expectedProperties.Length, properties.Count);

            for (var i = 0; i < expectedProperties.Length; i++)
            {
                Assert.Same(expectedProperties[i], properties[i]);
            }
        }
        private DefaultMetadataDetails CreateConstructorDetails(ModelMetadataIdentity constructorKey)
        {
            var constructor       = constructorKey.ConstructorInfo;
            var parameters        = constructor.GetParameters();
            var parameterMetadata = new ModelMetadata[parameters.Length];
            var parameterTypes    = new Type[parameters.Length];

            for (var i = 0; i < parameters.Length; i++)
            {
                var parameter        = parameters[i];
                var parameterDetails = CreateParameterDetails(ModelMetadataIdentity.ForParameter(parameter));
                parameterMetadata[i] = CreateModelMetadata(parameterDetails);

                parameterTypes[i] = parameter.ParameterType;
            }

            var constructorDetails = new DefaultMetadataDetails(constructorKey, ModelAttributes.Empty);

            constructorDetails.BoundConstructorParameters = parameterMetadata;
            constructorDetails.BoundConstructorInvoker    = CreateObjectFactory(constructor);

            return(constructorDetails);
        public void IsBindingRequired_ReturnsFalse_ForTypes(Type modelType)
        {
            // Arrange
            var provider        = new EmptyModelMetadataProvider();
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var key   = ModelMetadataIdentity.ForType(modelType);
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            cache.BindingMetadata = new BindingMetadata()
            {
                IsBindingRequired = true, // Will be ignored.
            };

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var isBindingRequired = metadata.IsBindingRequired;

            // Assert
            Assert.False(isBindingRequired);
        }
        public void ValidateChildren_OverrideFalse()
        {
            // Arrange
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
            var provider        = new DefaultModelMetadataProvider(detailsProvider);

            var key   = ModelMetadataIdentity.ForType(typeof(XmlDocument));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            cache.ValidationMetadata = new ValidationMetadata()
            {
                ValidateChildren = false,
            };

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var validateChildren = metadata.ValidateChildren;

            // Assert
            Assert.False(validateChildren);
        }
        public void PropertyValidationFilter_ReflectsFilter_FromValidationMetadata(IPropertyValidationFilter value)
        {
            // Arrange
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
            var provider        = new DefaultModelMetadataProvider(detailsProvider);

            var key   = ModelMetadataIdentity.ForType(typeof(int));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            cache.ValidationMetadata = new ValidationMetadata
            {
                PropertyValidationFilter = value,
            };

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var validationFilter = metadata.PropertyValidationFilter;

            // Assert
            Assert.Same(value, validationFilter);
        }
        public void IsReadOnly_ReturnsFalse_ForType()
        {
            // Arrange
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();
            var provider        = new DefaultModelMetadataProvider(detailsProvider);

            var key   = ModelMetadataIdentity.ForType(typeof(int[]));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            cache.BindingMetadata = new BindingMetadata()
            {
                IsReadOnly = true, // Will be ignored.
            };

            var metadata = new DefaultModelMetadata(provider, detailsProvider, cache);

            // Act
            var isReadOnly = metadata.IsReadOnly;

            // Assert
            Assert.False(isReadOnly);
        }
        /// <summary>
        /// Creates the <see cref="DefaultMetadataDetails"/> entries for the properties of a model
        /// <see cref="Type"/>.
        /// </summary>
        /// <param name="key">
        /// The <see cref="ModelMetadataIdentity"/> identifying the model <see cref="Type"/>.
        /// </param>
        /// <returns>A details object for each property of the model <see cref="Type"/>.</returns>
        /// <remarks>
        /// The results of this method will be cached and used to satisfy calls to
        /// <see cref="GetMetadataForProperties(Type)"/>. Override this method to provide a different
        /// set of property data.
        /// </remarks>
        protected virtual DefaultMetadataDetails[] CreatePropertyDetails(ModelMetadataIdentity key)
        {
            var propertyHelpers = PropertyHelper.GetVisibleProperties(key.ModelType);

            var propertyEntries = new List <DefaultMetadataDetails>(propertyHelpers.Length);

            for (var i = 0; i < propertyHelpers.Length; i++)
            {
                var propertyHelper = propertyHelpers[i];
                var propertyKey    = ModelMetadataIdentity.ForProperty(
                    propertyHelper.Property.PropertyType,
                    propertyHelper.Name,
                    key.ModelType);

                var attributes = ModelAttributes.GetAttributesForProperty(
                    key.ModelType,
                    propertyHelper.Property);

                var propertyEntry = new DefaultMetadataDetails(propertyKey, attributes);
                if (propertyHelper.Property.CanRead && propertyHelper.Property.GetMethod?.IsPublic == true)
                {
                    var getter = PropertyHelper.MakeNullSafeFastPropertyGetter(propertyHelper.Property);
                    propertyEntry.PropertyGetter = getter;
                }

                if (propertyHelper.Property.CanWrite &&
                    propertyHelper.Property.SetMethod?.IsPublic == true &&
                    !key.ModelType.GetTypeInfo().IsValueType)
                {
                    propertyEntry.PropertySetter = propertyHelper.ValueSetter;
                }

                propertyEntries.Add(propertyEntry);
            }

            return(propertyEntries.ToArray());
        }
        public void PropertiesProperty_WithDefaultOrder_OrdersPropertyNamesAsProvided(
            IEnumerable <string> originalNames,
            IEnumerable <string> expectedNames)
        {
            // Arrange
            var provider        = new Mock <IModelMetadataProvider>(MockBehavior.Strict);
            var detailsProvider = new EmptyCompositeMetadataDetailsProvider();

            var expectedProperties = new List <DefaultModelMetadata>();

            foreach (var originalName in originalNames)
            {
                expectedProperties.Add(new DefaultModelMetadata(
                                           provider.Object,
                                           detailsProvider,
                                           new DefaultMetadataDetails(
                                               ModelMetadataIdentity.ForProperty(typeof(int), originalName, typeof(string)),
                                               attributes: new ModelAttributes(new object[0], new object[0]))));
            }

            provider
            .Setup(p => p.GetMetadataForProperties(typeof(string)))
            .Returns(expectedProperties);

            var key   = ModelMetadataIdentity.ForType(typeof(string));
            var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0]));

            var metadata = new DefaultModelMetadata(provider.Object, detailsProvider, cache);

            // Act
            var properties = metadata.Properties;

            // Assert
            Assert.Equal(expectedNames.Count(), properties.Count);
            Assert.Equal(expectedNames.ToArray(), properties.Select(p => p.PropertyName).ToArray());
        }
 public ModelMetadataCacheEntry(ModelMetadata metadata, DefaultMetadataDetails details)
 {
     Metadata = metadata;
     Details  = details;
 }
 /// <summary>
 /// Creates a new <see cref="ModelMetadata"/> from a <see cref="DefaultMetadataDetails"/>.
 /// </summary>
 /// <param name="entry">The <see cref="DefaultMetadataDetails"/> entry with cached data.</param>
 /// <returns>A new <see cref="ModelMetadata"/> instance.</returns>
 /// <remarks>
 /// <see cref="DefaultModelMetadataProvider"/> will always create instances of
 /// <see cref="DefaultModelMetadata"/> .Override this method to create a <see cref="ModelMetadata"/>
 /// of a different concrete type.
 /// </remarks>
 protected virtual ModelMetadata CreateModelMetadata(DefaultMetadataDetails entry)
 {
     return(new DefaultModelMetadata(this, DetailsProvider, entry, ModelBindingMessageProvider));
 }