From 27191114538c92ac1901bf18cb20124102a99892 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Thu, 16 Apr 2015 16:25:25 -0700 Subject: [PATCH] Add more details to ModelAttributes This change adds more information to ModelAttributes, so that metadata providers can look at the attributes on the property and type separately if so desired --- .../BindingMetadataProviderContext.cs | 17 ++- ...taMemberRequiredBindingMetadataProvider.cs | 2 +- .../Metadata/DefaultMetadataDetails.cs | 8 +- .../Metadata/DefaultModelMetadata.cs | 10 +- .../Metadata/DefaultModelMetadataProvider.cs | 7 +- .../DisplayMetadataProviderContext.cs | 21 ++- .../Metadata/ModelAttributes.cs | 99 ++++++++------ .../ValidationMetadataProviderContext.cs | 17 ++- ...Microsoft.AspNet.Mvc.FunctionalTests.xproj | 3 + .../DataAnnotationsMetadataProviderTest.cs | 34 ++--- ...mberRequiredBindingMetadataProviderTest.cs | 10 +- .../DefaultBindingMetadataProviderTest.cs | 14 +- .../DefaultModelMetadataProviderTest.cs | 4 +- .../Metadata/DefaultModelMetadataTest.cs | 36 ++--- .../Metadata/DefaultValidationMetadataTest.cs | 6 +- ...tributesTest.cs => ModelAttributesTest.cs} | 124 +++++++++++++++--- .../Metadata/ModelMetadataProviderTest.cs | 4 +- .../TestBindingSourceModelBinder.cs | 2 +- 18 files changed, 285 insertions(+), 133 deletions(-) rename test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/{ModelMetadataAttributesTest.cs => ModelAttributesTest.cs} (50%) diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/BindingMetadataProviderContext.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/BindingMetadataProviderContext.cs index 400bf90b85..a0379ad9bd 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/BindingMetadataProviderContext.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/BindingMetadataProviderContext.cs @@ -18,10 +18,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata /// The attributes for the . public BindingMetadataProviderContext( [NotNull] ModelMetadataIdentity key, - [NotNull] IReadOnlyList attributes) + [NotNull] ModelAttributes attributes) { Key = key; - Attributes = attributes; + Attributes = attributes.Attributes; + PropertyAttributes = attributes.PropertyAttributes; + TypeAttributes = attributes.TypeAttributes; + BindingMetadata = new BindingMetadata(); } @@ -35,6 +38,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata /// public ModelMetadataIdentity Key { get; } + /// + /// Gets the property attributes. + /// + public IReadOnlyList PropertyAttributes { get; } + + /// + /// Gets the type attributes. + /// + public IReadOnlyList TypeAttributes { get; } + /// /// Gets the . /// diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DataMemberRequiredBindingMetadataProvider.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DataMemberRequiredBindingMetadataProvider.cs index 81db4cf98e..f6584bcff8 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DataMemberRequiredBindingMetadataProvider.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DataMemberRequiredBindingMetadataProvider.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata } var dataMemberAttribute = context - .Attributes + .PropertyAttributes .OfType() .FirstOrDefault(); if (dataMemberAttribute == null || !dataMemberAttribute.IsRequired) diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultMetadataDetails.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultMetadataDetails.cs index 27ea450313..8e0a287152 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultMetadataDetails.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultMetadataDetails.cs @@ -2,7 +2,7 @@ // 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 Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata { @@ -19,16 +19,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata /// /// The . /// The set of model attributes. - public DefaultMetadataDetails(ModelMetadataIdentity key, IReadOnlyList attributes) + public DefaultMetadataDetails(ModelMetadataIdentity key, [NotNull] ModelAttributes attributes) { Key = key; - Attributes = attributes; + ModelAttributes = attributes; } /// /// Gets or sets the set of model attributes. /// - public IReadOnlyList Attributes { get; } + public ModelAttributes ModelAttributes { get; } /// /// Gets or sets the . diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultModelMetadata.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultModelMetadata.cs index dffe4a422f..c94dc86cd7 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultModelMetadata.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultModelMetadata.cs @@ -44,11 +44,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata /// /// Gets the set of attributes for the current instance. /// - public IReadOnlyList Attributes + public ModelAttributes Attributes { get { - return _details.Attributes; + return _details.ModelAttributes; } } @@ -64,7 +64,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata { if (_details.BindingMetadata == null) { - var context = new BindingMetadataProviderContext(Identity, _details.Attributes); + var context = new BindingMetadataProviderContext(Identity, _details.ModelAttributes); _detailsProvider.GetBindingMetadata(context); _details.BindingMetadata = context.BindingMetadata; } @@ -85,7 +85,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata { if (_details.DisplayMetadata == null) { - var context = new DisplayMetadataProviderContext(Identity, _details.Attributes); + var context = new DisplayMetadataProviderContext(Identity, _details.ModelAttributes); _detailsProvider.GetDisplayMetadata(context); _details.DisplayMetadata = context.DisplayMetadata; } @@ -106,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata { if (_details.ValidationMetadata == null) { - var context = new ValidationMetadataProviderContext(Identity, _details.Attributes); + var context = new ValidationMetadataProviderContext(Identity, _details.ModelAttributes); _detailsProvider.GetValidationMetadata(context); _details.ValidationMetadata = context.ValidationMetadata; } diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultModelMetadataProvider.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultModelMetadataProvider.cs index 491ee67bb3..a1c13a96ee 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultModelMetadataProvider.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DefaultModelMetadataProvider.cs @@ -114,9 +114,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata propertyHelper.Name, key.ModelType); - var attributes = new List(ModelAttributes.GetAttributesForProperty( + var attributes = ModelAttributes.GetAttributesForProperty( key.ModelType, - propertyHelper.Property)); + propertyHelper.Property); var propertyEntry = new DefaultMetadataDetails(propertyKey, attributes); if (propertyHelper.Property.CanRead && propertyHelper.Property.GetMethod?.IsPublic == true) @@ -151,8 +151,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata /// protected virtual DefaultMetadataDetails CreateTypeDetails([NotNull] ModelMetadataIdentity key) { - var attributes = new List(ModelAttributes.GetAttributesForType(key.ModelType)); - return new DefaultMetadataDetails(key, attributes); + return new DefaultMetadataDetails(key, ModelAttributes.GetAttributesForType(key.ModelType)); } private class TypeCache : ConcurrentDictionary diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DisplayMetadataProviderContext.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DisplayMetadataProviderContext.cs index 2eae19df70..623da3b83f 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DisplayMetadataProviderContext.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/DisplayMetadataProviderContext.cs @@ -18,10 +18,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata /// The attributes for the . public DisplayMetadataProviderContext( [NotNull] ModelMetadataIdentity key, - [NotNull] IReadOnlyList attributes) + [NotNull] ModelAttributes attributes) { Key = key; - Attributes = attributes; + Attributes = attributes.Attributes; + PropertyAttributes = attributes.PropertyAttributes; + TypeAttributes = attributes.TypeAttributes; + DisplayMetadata = new DisplayMetadata(); } @@ -30,14 +33,24 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata /// public IReadOnlyList Attributes { get; } + /// + /// Gets the . + /// + public DisplayMetadata DisplayMetadata { get; } + /// /// Gets the . /// public ModelMetadataIdentity Key { get; } /// - /// Gets the . + /// Gets the property attributes. /// - public DisplayMetadata DisplayMetadata { get; } + public IReadOnlyList PropertyAttributes { get; } + + /// + /// Gets the type attributes. + /// + public IReadOnlyList TypeAttributes { get; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/ModelAttributes.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/ModelAttributes.cs index 543c8c6dbb..7787086355 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/ModelAttributes.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/ModelAttributes.cs @@ -10,27 +10,53 @@ using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding { /// - /// Provides static methods which can be used to get a combined list of attributes associated - /// with a parameter or property. + /// Provides access to the combined list of attributes associated a or property. /// - public static class ModelAttributes + public class ModelAttributes { /// - /// Gets the attributes for the given . + /// Creates a new for a . /// - /// A for which attributes need to be resolved. - /// - /// An containing the attributes on the - /// before the attributes on the type. - public static IEnumerable GetAttributesForParameter(ParameterInfo parameter) + /// The set of attributes for the . + public ModelAttributes([NotNull] IEnumerable typeAttributes) { - // Return the parameter attributes first. - var parameterAttributes = parameter.GetCustomAttributes(); - var typeAttributes = parameter.ParameterType.GetTypeInfo().GetCustomAttributes(); - - return parameterAttributes.Concat(typeAttributes); + Attributes = typeAttributes.ToArray(); + TypeAttributes = Attributes; } + /// + /// Creates a new for a property. + /// + /// The set of attributes for the property. + /// + /// The set of attributes for the property's . See . + /// + public ModelAttributes([NotNull] IEnumerable propertyAttributes, [NotNull] IEnumerable typeAttributes) + { + PropertyAttributes = propertyAttributes.ToArray(); + TypeAttributes = typeAttributes.ToArray(); + Attributes = PropertyAttributes.Concat(TypeAttributes).ToArray(); + } + + /// + /// Gets the set of all attributes. If this instance represents the attributes for a property, the attributes + /// on the property definition are before those on the property's . + /// + public IReadOnlyList Attributes { get; } + + /// + /// Gets the set of attributes on the property, or null if this instance represents the attributes + /// for a . + /// + public IReadOnlyList PropertyAttributes { get; } + + /// + /// Gets the set of attributes on the . If this instance represents a property, + /// then contains attributes retrieved from + /// . + /// + public IReadOnlyList TypeAttributes { get; } + /// /// Gets the attributes for the given . /// @@ -38,32 +64,26 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// A for which attributes need to be resolved. /// - /// An containing the attributes on the - /// before the attributes on the type. - public static IEnumerable GetAttributesForProperty([NotNull] Type type, [NotNull] PropertyInfo property) + /// A instance with the attributes of the property. + public static ModelAttributes GetAttributesForProperty([NotNull] Type type, [NotNull] PropertyInfo property) { - // Return the property attributes first. var propertyAttributes = property.GetCustomAttributes(); var typeAttributes = property.PropertyType.GetTypeInfo().GetCustomAttributes(); - propertyAttributes = propertyAttributes.Concat(typeAttributes); - - var modelMedatadataType = type.GetTypeInfo().GetCustomAttribute(); - if (modelMedatadataType != null) + var metadataType = GetMetadataType(type); + if (metadataType != null) { - var modelMedatadataProperty = modelMedatadataType.MetadataType.GetRuntimeProperty(property.Name); - if (modelMedatadataProperty != null) + var metadataProperty = metadataType.GetRuntimeProperty(property.Name); + if (metadataProperty != null) { - var modelMedatadataAttributes = modelMedatadataProperty.GetCustomAttributes(); - propertyAttributes = propertyAttributes.Concat(modelMedatadataAttributes); + propertyAttributes = propertyAttributes.Concat(metadataProperty.GetCustomAttributes()); - var modelMetadataTypeAttributes = - modelMedatadataProperty.PropertyType.GetTypeInfo().GetCustomAttributes(); - propertyAttributes = propertyAttributes.Concat(modelMetadataTypeAttributes); + var propertyMetadataType = metadataProperty.PropertyType; + typeAttributes = typeAttributes.Concat(propertyMetadataType.GetTypeInfo().GetCustomAttributes()); } } - return propertyAttributes; + return new ModelAttributes(propertyAttributes, typeAttributes); } /// @@ -71,20 +91,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// The for which attributes need to be resolved. /// - /// An containing the attributes on the - /// . - public static IEnumerable GetAttributesForType([NotNull] Type type) + /// A instance with the attributes of the . + public static ModelAttributes GetAttributesForType([NotNull] Type type) { var attributes = type.GetTypeInfo().GetCustomAttributes(); - var modelMedatadataType = type.GetTypeInfo().GetCustomAttribute(); - if (modelMedatadataType != null) + var metadataType = GetMetadataType(type); + if (metadataType != null) { - var modelMedatadataAttributes = modelMedatadataType.MetadataType.GetTypeInfo().GetCustomAttributes(); - attributes = attributes.Concat(modelMedatadataAttributes); + attributes = attributes.Concat(metadataType.GetTypeInfo().GetCustomAttributes()); } - return attributes; + return new ModelAttributes(attributes); + } + + private static Type GetMetadataType(Type type) + { + return type.GetTypeInfo().GetCustomAttribute()?.MetadataType; } } } diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/ValidationMetadataProviderContext.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/ValidationMetadataProviderContext.cs index ca59eb76a3..85a8322065 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/ValidationMetadataProviderContext.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/ValidationMetadataProviderContext.cs @@ -18,10 +18,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata /// The attributes for the . public ValidationMetadataProviderContext( [NotNull] ModelMetadataIdentity key, - [NotNull] IReadOnlyList attributes) + [NotNull] ModelAttributes attributes) { Key = key; - Attributes = attributes; + Attributes = attributes.Attributes; + PropertyAttributes = attributes.PropertyAttributes; + TypeAttributes = attributes.TypeAttributes; + ValidationMetadata = new ValidationMetadata(); } @@ -35,6 +38,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata /// public ModelMetadataIdentity Key { get; } + /// + /// Gets the property attributes. + /// + public IReadOnlyList PropertyAttributes { get; } + + /// + /// Gets the type attributes. + /// + public IReadOnlyList TypeAttributes { get; } + /// /// Gets the . /// diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.xproj b/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.xproj index a38232da9b..a6cc812cb9 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.xproj +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.xproj @@ -13,5 +13,8 @@ 2.0 + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DataAnnotationsMetadataProviderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DataAnnotationsMetadataProviderTest.cs index 836151bf59..c6855868dc 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DataAnnotationsMetadataProviderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DataAnnotationsMetadataProviderTest.cs @@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var provider = new DataAnnotationsMetadataProvider(); var key = ModelMetadataIdentity.ForType(typeof(string)); - var context = new DisplayMetadataProviderContext(key, new object[] { attribute }); + var context = new DisplayMetadataProviderContext(key, new ModelAttributes(new object[] { attribute })); // Act provider.GetDisplayMetadata(context); @@ -78,7 +78,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attributes = new[] { dataType, }; var key = ModelMetadataIdentity.ForType(typeof(string)); - var context = new DisplayMetadataProviderContext(key, attributes); + var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes)); // Act provider.GetDisplayMetadata(context); @@ -101,7 +101,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attributes = new Attribute[] { dataType, displayFormat, }; var key = ModelMetadataIdentity.ForType(typeof(string)); - var context = new DisplayMetadataProviderContext(key, attributes); + var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes)); // Act provider.GetDisplayMetadata(context); @@ -120,7 +120,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attributes = new Attribute[] { editable }; var key = ModelMetadataIdentity.ForType(typeof(string)); - var context = new BindingMetadataProviderContext(key, attributes); + var context = new BindingMetadataProviderContext(key, new ModelAttributes(attributes)); // Act provider.GetBindingMetadata(context); @@ -139,7 +139,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attributes = new Attribute[] { editable }; var key = ModelMetadataIdentity.ForType(typeof(string)); - var context = new BindingMetadataProviderContext(key, attributes); + var context = new BindingMetadataProviderContext(key, new ModelAttributes(attributes)); // Act provider.GetBindingMetadata(context); @@ -169,7 +169,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attributes = new Attribute[] { display }; var key = ModelMetadataIdentity.ForType(typeof(string)); - var context = new DisplayMetadataProviderContext(key, attributes); + var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes)); // Act provider.GetDisplayMetadata(context); @@ -198,7 +198,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attributes = new Attribute[] { display }; var key = ModelMetadataIdentity.ForType(typeof(string)); - var context = new DisplayMetadataProviderContext(key, attributes); + var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes)); // Act provider.GetDisplayMetadata(context); @@ -232,7 +232,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var key = ModelMetadataIdentity.ForType(type); var attributes = new object[0]; - var context = new DisplayMetadataProviderContext(key, attributes); + var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes)); // Act provider.GetDisplayMetadata(context); @@ -266,7 +266,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var key = ModelMetadataIdentity.ForType(type); var attributes = new object[0]; - var context = new DisplayMetadataProviderContext(key, attributes); + var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes)); // Act provider.GetDisplayMetadata(context); @@ -398,7 +398,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var key = ModelMetadataIdentity.ForType(type); var attributes = new object[0]; - var context = new DisplayMetadataProviderContext(key, attributes); + var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes)); // Act provider.GetDisplayMetadata(context); @@ -532,7 +532,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var key = ModelMetadataIdentity.ForType(type); var attributes = new object[0]; - var context = new DisplayMetadataProviderContext(key, attributes); + var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes)); // Act provider.GetDisplayMetadata(context); @@ -551,7 +551,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attributes = new Attribute[] { required }; var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)); - var context = new ValidationMetadataProviderContext(key, attributes); + var context = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); // Act provider.GetValidationMetadata(context); @@ -571,7 +571,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attributes = new Attribute[] { }; var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)); - var context = new ValidationMetadataProviderContext(key, attributes); + var context = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); context.ValidationMetadata.IsRequired = initialValue; // Act @@ -592,7 +592,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attributes = new Attribute[] { new RequiredAttribute() }; var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)); - var context = new BindingMetadataProviderContext(key, attributes); + var context = new BindingMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); context.BindingMetadata.IsBindingRequired = initialValue; // Act @@ -613,7 +613,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attributes = new Attribute[] { }; var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)); - var context = new BindingMetadataProviderContext(key, attributes); + var context = new BindingMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); context.BindingMetadata.IsReadOnly = initialValue; // Act @@ -632,7 +632,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attribute = new TestValidationAttribute(); var attributes = new Attribute[] { attribute }; var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)); - var context = new ValidationMetadataProviderContext(key, attributes); + var context = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); // Act provider.GetValidationMetadata(context); @@ -651,7 +651,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attribute = new TestValidationAttribute(); var attributes = new Attribute[] { attribute }; var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)); - var context = new ValidationMetadataProviderContext(key, attributes); + var context = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); context.ValidationMetadata.ValidatorMetadata.Add(attribute); // Act diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DataMemberRequiredBindingMetadataProviderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DataMemberRequiredBindingMetadataProviderTest.cs index 15cdc1683e..b886ba536a 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DataMemberRequiredBindingMetadataProviderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DataMemberRequiredBindingMetadataProviderTest.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata typeof(string), nameof(ClassWithDataMemberIsRequiredTrue.StringProperty), typeof(ClassWithDataMemberIsRequiredTrue)); - var context = new BindingMetadataProviderContext(key, attributes); + var context = new BindingMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); // Act provider.GetBindingMetadata(context); @@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata typeof(string), nameof(ClassWithDataMemberIsRequiredFalse.StringProperty), typeof(ClassWithDataMemberIsRequiredFalse)); - var context = new BindingMetadataProviderContext(key, attributes); + var context = new BindingMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); context.BindingMetadata.IsBindingRequired = initialValue; @@ -74,7 +74,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata }; var key = ModelMetadataIdentity.ForType(typeof(ClassWithDataMemberIsRequiredTrue)); - var context = new BindingMetadataProviderContext(key, attributes); + var context = new BindingMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); context.BindingMetadata.IsBindingRequired = initialValue; @@ -97,7 +97,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata typeof(string), nameof(ClassWithoutAttributes.StringProperty), typeof(ClassWithoutAttributes)); - var context = new BindingMetadataProviderContext(key, attributes: new object[0]); + var context = new BindingMetadataProviderContext(key, new ModelAttributes(new object[0], new object[0])); context.BindingMetadata.IsBindingRequired = initialValue; @@ -125,7 +125,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata typeof(string), nameof(ClassWithDataMemberIsRequiredTrueWithoutDataContract.StringProperty), typeof(ClassWithDataMemberIsRequiredTrueWithoutDataContract)); - var context = new BindingMetadataProviderContext(key, attributes); + var context = new BindingMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); context.BindingMetadata.IsBindingRequired = initialValue; diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultBindingMetadataProviderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultBindingMetadataProviderTest.cs index f954b67582..56f32618ed 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultBindingMetadataProviderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultBindingMetadataProviderTest.cs @@ -18,8 +18,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata }; var context = new BindingMetadataProviderContext( - ModelMetadataIdentity.ForType(typeof(string)), - attributes); + ModelMetadataIdentity.ForType(typeof(string)), + new ModelAttributes(attributes)); var provider = new DefaultBindingMetadataProvider(); @@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var context = new BindingMetadataProviderContext( ModelMetadataIdentity.ForType(typeof(string)), - attributes); + new ModelAttributes(attributes)); var provider = new DefaultBindingMetadataProvider(); @@ -66,7 +66,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var context = new BindingMetadataProviderContext( ModelMetadataIdentity.ForType(typeof(string)), - attributes); + new ModelAttributes(attributes)); var provider = new DefaultBindingMetadataProvider(); @@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var context = new BindingMetadataProviderContext( ModelMetadataIdentity.ForType(typeof(string)), - attributes); + new ModelAttributes(attributes)); var provider = new DefaultBindingMetadataProvider(); @@ -113,7 +113,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var context = new BindingMetadataProviderContext( ModelMetadataIdentity.ForType(typeof(string)), - attributes); + new ModelAttributes(attributes)); var provider = new DefaultBindingMetadataProvider(); @@ -137,7 +137,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var context = new BindingMetadataProviderContext( ModelMetadataIdentity.ForType(typeof(string)), - attributes); + new ModelAttributes(attributes)); var provider = new DefaultBindingMetadataProvider(); diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultModelMetadataProviderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultModelMetadataProviderTest.cs index f026a16879..a3129e2356 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultModelMetadataProviderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultModelMetadataProviderTest.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata // Assert var defaultMetadata = Assert.IsType(metadata); - var attribute = Assert.IsType(Assert.Single(defaultMetadata.Attributes)); + var attribute = Assert.IsType(Assert.Single(defaultMetadata.Attributes.Attributes)); Assert.Equal("OnType", attribute.Value); } @@ -121,7 +121,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata // Assert var defaultMetadata = Assert.IsType(metadata); - var attributes = defaultMetadata.Attributes.ToArray(); + var attributes = defaultMetadata.Attributes.Attributes.ToArray(); Assert.Equal("OnProperty", Assert.IsType(attributes[0]).Value); Assert.Equal("OnPropertyType", Assert.IsType(attributes[1]).Value); } diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultModelMetadataTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultModelMetadataTest.cs index 79e43c72e7..00c7519150 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultModelMetadataTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultModelMetadataTest.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata Enumerable.Empty()); var key = ModelMetadataIdentity.ForType(typeof(string)); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); // Act var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); @@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata Enumerable.Empty()); var key = ModelMetadataIdentity.ForType(typeof(Exception)); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); // Act var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); @@ -95,7 +95,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var detailsProvider = new EmptyCompositeMetadataDetailsProvider(); var key = ModelMetadataIdentity.ForProperty(typeof(string), "Message", typeof(Exception)); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0], new object[0])); // Act var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); @@ -117,7 +117,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var detailsProvider = new EmptyCompositeMetadataDetailsProvider(); var key = ModelMetadataIdentity.ForType(modelType); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); @@ -138,7 +138,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var detailsProvider = new EmptyCompositeMetadataDetailsProvider(); var key = ModelMetadataIdentity.ForType(modelType); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); @@ -164,13 +164,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata detailsProvider, new DefaultMetadataDetails( ModelMetadataIdentity.ForProperty(typeof(int), "Prop1", typeof(string)), - attributes: null)), + attributes: new ModelAttributes(new object[0], new object[0]))), new DefaultModelMetadata( provider.Object, detailsProvider, new DefaultMetadataDetails( ModelMetadataIdentity.ForProperty(typeof(int), "Prop2", typeof(string)), - attributes: null)), + attributes: new ModelAttributes(new object[0], new object[0]))), }; provider @@ -178,7 +178,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata .Returns(expectedProperties); var key = ModelMetadataIdentity.ForType(typeof(string)); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); var metadata = new DefaultModelMetadata(provider.Object, detailsProvider, cache); @@ -240,7 +240,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata detailsProvider, new DefaultMetadataDetails( ModelMetadataIdentity.ForProperty(typeof(int), originalName, typeof(string)), - attributes: null))); + attributes: new ModelAttributes(new object[0], new object[0])))); } provider @@ -248,7 +248,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata .Returns(expectedProperties); var key = ModelMetadataIdentity.ForType(typeof(string)); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); var metadata = new DefaultModelMetadata(provider.Object, detailsProvider, cache); @@ -340,7 +340,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata { var propertyCache = new DefaultMetadataDetails( ModelMetadataIdentity.ForProperty(typeof(int), kvp.Key, typeof(string)), - attributes: null); + attributes: new ModelAttributes(new object[0], new object[0])); propertyCache.DisplayMetadata = new DisplayMetadata(); propertyCache.DisplayMetadata.Order = kvp.Value; @@ -356,7 +356,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata .Returns(expectedProperties); var key = ModelMetadataIdentity.ForType(typeof(string)); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); var metadata = new DefaultModelMetadata(provider.Object, detailsProvider, cache); @@ -377,7 +377,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var detailsProvider = new EmptyCompositeMetadataDetailsProvider(); var key = ModelMetadataIdentity.ForType(typeof(string)); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); @@ -398,7 +398,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var detailsProvider = new EmptyCompositeMetadataDetailsProvider(); var key = ModelMetadataIdentity.ForType(typeof(string)); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); @@ -419,7 +419,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var provider = new DefaultModelMetadataProvider(detailsProvider); var key = ModelMetadataIdentity.ForType(typeof(int[])); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); @@ -438,7 +438,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var provider = new DefaultModelMetadataProvider(detailsProvider); var key = ModelMetadataIdentity.ForType(typeof(TypeWithProperties)); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); @@ -457,7 +457,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var provider = new DefaultModelMetadataProvider(detailsProvider); var key = ModelMetadataIdentity.ForType(typeof(TypeWithProperties)); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); @@ -476,7 +476,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var provider = new DefaultModelMetadataProvider(detailsProvider); var key = ModelMetadataIdentity.ForType(typeof(TypeWithProperties)); - var cache = new DefaultMetadataDetails(key, new object[0]); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultValidationMetadataTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultValidationMetadataTest.cs index 7eeb2ed5bb..a7c5ee89a8 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultValidationMetadataTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/DefaultValidationMetadataTest.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attribute = new TestClientModelValidationAttribute(); var attributes = new Attribute[] { attribute }; var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)); - var context = new ValidationMetadataProviderContext(key, attributes); + var context = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); // Act provider.GetValidationMetadata(context); @@ -38,7 +38,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attribute = new TestModelValidationAttribute(); var attributes = new Attribute[] { attribute }; var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)); - var context = new ValidationMetadataProviderContext(key, attributes); + var context = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); // Act provider.GetValidationMetadata(context); @@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var attribute = new TestValidationAttribute(); var attributes = new Attribute[] { attribute }; var key = ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)); - var context = new ValidationMetadataProviderContext(key, attributes); + var context = new ValidationMetadataProviderContext(key, new ModelAttributes(attributes, new object[0])); context.ValidationMetadata.ValidatorMetadata.Add(attribute); // Act diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelMetadataAttributesTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelAttributesTest.cs similarity index 50% rename from test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelMetadataAttributesTest.cs rename to test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelAttributesTest.cs index 01859e7b27..701b6233fc 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelMetadataAttributesTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelAttributesTest.cs @@ -9,7 +9,7 @@ using Xunit; namespace Microsoft.AspNet.Mvc.ModelBinding { - public class ModelMetadataAttributesTest + public class ModelAttributesTest { [Fact] public void GetAttributesForBaseProperty_IncludesMetadataAttributes() @@ -22,8 +22,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var attributes = ModelAttributes.GetAttributesForProperty(modelType, property); // Assert - Assert.Single(attributes.OfType()); - Assert.Single(attributes.OfType()); + Assert.Single(attributes.Attributes.OfType()); + Assert.Single(attributes.Attributes.OfType()); + + Assert.Single(attributes.PropertyAttributes.OfType()); + Assert.Single(attributes.PropertyAttributes.OfType()); } [Fact] @@ -37,11 +40,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var attributes = ModelAttributes.GetAttributesForProperty(modelType, property); // Assert - var rangeAttribute = attributes.OfType().FirstOrDefault(); - Assert.NotNull(rangeAttribute); - Assert.Equal(0, (int)rangeAttribute.Minimum); - Assert.Equal(10, (int)rangeAttribute.Maximum); - Assert.Single(attributes.OfType()); + var rangeAttributes = attributes.Attributes.OfType().ToArray(); + Assert.NotNull(rangeAttributes[0]); + Assert.Equal(0, (int)rangeAttributes[0].Minimum); + Assert.Equal(10, (int)rangeAttributes[0].Maximum); + Assert.NotNull(rangeAttributes[1]); + Assert.Equal(10, (int)rangeAttributes[1].Minimum); + Assert.Equal(100, (int)rangeAttributes[1].Maximum); + Assert.Single(attributes.Attributes.OfType()); + + rangeAttributes = attributes.PropertyAttributes.OfType().ToArray(); + Assert.NotNull(rangeAttributes[0]); + Assert.Equal(0, (int)rangeAttributes[0].Minimum); + Assert.Equal(10, (int)rangeAttributes[0].Maximum); + Assert.NotNull(rangeAttributes[1]); + Assert.Equal(10, (int)rangeAttributes[1].Minimum); + Assert.Equal(100, (int)rangeAttributes[1].Maximum); + Assert.Single(attributes.PropertyAttributes.OfType()); } [Fact] @@ -55,8 +70,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var attributes = ModelAttributes.GetAttributesForProperty(modelType, property); // Assert - Assert.Single(attributes.OfType()); - Assert.Single(attributes.OfType()); + Assert.Single(attributes.Attributes.OfType()); + Assert.Single(attributes.Attributes.OfType()); + + Assert.Single(attributes.PropertyAttributes.OfType()); + Assert.Single(attributes.PropertyAttributes.OfType()); } [Fact] @@ -70,9 +88,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var attributes = ModelAttributes.GetAttributesForProperty(modelType, property); // Assert - Assert.Single(attributes.OfType()); - Assert.Single(attributes.OfType()); - Assert.DoesNotContain(typeof(RangeAttribute), attributes); + Assert.Single(attributes.Attributes.OfType()); + Assert.Single(attributes.Attributes.OfType()); + Assert.DoesNotContain(typeof(RangeAttribute), attributes.Attributes); + + Assert.Single(attributes.PropertyAttributes.OfType()); + Assert.Single(attributes.PropertyAttributes.OfType()); + Assert.DoesNotContain(typeof(RangeAttribute), attributes.PropertyAttributes); } [Fact] @@ -86,8 +108,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var attributes = ModelAttributes.GetAttributesForProperty(modelType, property); // Assert - Assert.Single(attributes.OfType()); - Assert.Single(attributes.OfType()); + Assert.Single(attributes.Attributes.OfType()); + Assert.Single(attributes.Attributes.OfType()); + + Assert.Single(attributes.PropertyAttributes.OfType()); + Assert.Single(attributes.PropertyAttributes.OfType()); } [Fact] @@ -101,8 +126,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var attributes = ModelAttributes.GetAttributesForProperty(modelType, property); // Assert - Assert.Single(attributes.OfType()); - Assert.Single(attributes.OfType()); + Assert.Single(attributes.Attributes.OfType()); + Assert.Single(attributes.Attributes.OfType()); + + Assert.Single(attributes.PropertyAttributes.OfType()); + Assert.Single(attributes.PropertyAttributes.OfType()); } [Fact] @@ -112,10 +140,45 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var attributes = ModelAttributes.GetAttributesForType(typeof(BaseViewModel)); // Assert - Assert.Single(attributes.OfType()); + Assert.Single(attributes.Attributes.OfType()); + + Assert.Single(attributes.TypeAttributes.OfType()); } - // Helper classes + [Fact] + public void GetAttributesForType_PropertyAttributes_IsNull() + { + // Arrange & Act + var attributes = ModelAttributes.GetAttributesForType(typeof(BaseViewModel)); + + // Assert + Assert.Null(attributes.PropertyAttributes); + } + + [Fact] + public void GetAttributesForProperty_MergedAttributes() + { + // Arrange + var property = typeof(MergedAttributes).GetRuntimeProperty(nameof(MergedAttributes.Property)); + + // Act + var attributes = ModelAttributes.GetAttributesForProperty(typeof(MergedAttributes), property); + + // Assert + Assert.Equal(4, attributes.Attributes.Count); + Assert.IsType(attributes.Attributes[0]); + Assert.IsType(attributes.Attributes[1]); + Assert.IsType(attributes.Attributes[2]); + Assert.IsType(attributes.Attributes[3]); + + Assert.Equal(2, attributes.PropertyAttributes.Count); + Assert.IsType(attributes.PropertyAttributes[0]); + Assert.IsType(attributes.PropertyAttributes[1]); + + Assert.Equal(2, attributes.TypeAttributes.Count); + Assert.IsType(attributes.TypeAttributes[0]); + Assert.IsType(attributes.TypeAttributes[1]); + } [ClassValidator] private class BaseModel @@ -182,5 +245,28 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return true; } } + + [ModelMetadataType(typeof(MergedAttributesMetadata))] + private class MergedAttributes + { + [Required] + public PropertyType Property { get; set; } + } + + private class MergedAttributesMetadata + { + [Range(0, 10)] + public MetadataPropertyType Property { get; set; } + } + + [ClassValidator] + private class PropertyType + { + } + + [Bind] + private class MetadataPropertyType + { + } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelMetadataProviderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelMetadataProviderTest.cs index 2c10466e94..22b99c4b99 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelMetadataProviderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Metadata/ModelMetadataProviderTest.cs @@ -886,7 +886,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata protected override DefaultMetadataDetails CreateTypeDetails([NotNull]ModelMetadataIdentity key) { var entry = base.CreateTypeDetails(key); - return new DefaultMetadataDetails(key, _attributes.Concat(entry.Attributes).ToArray()); + return new DefaultMetadataDetails( + key, + new ModelAttributes(_attributes.Concat(entry.ModelAttributes.TypeAttributes).ToArray())); } } } diff --git a/test/WebSites/ModelBindingWebSite/TestBindingSourceModelBinder.cs b/test/WebSites/ModelBindingWebSite/TestBindingSourceModelBinder.cs index 71327521cb..a6d870fb65 100644 --- a/test/WebSites/ModelBindingWebSite/TestBindingSourceModelBinder.cs +++ b/test/WebSites/ModelBindingWebSite/TestBindingSourceModelBinder.cs @@ -20,7 +20,7 @@ namespace ModelBindingWebSite protected override Task BindModelCoreAsync(ModelBindingContext bindingContext) { var attributes = ((DefaultModelMetadata)bindingContext.ModelMetadata).Attributes; - var metadata = attributes.OfType().First(); + var metadata = attributes.Attributes.OfType().First(); var model = metadata.Value; if (!IsSimpleType(bindingContext.ModelType)) {