diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/ModelMetadataProviderExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/ModelMetadataProviderExtensions.cs index a254a1e2ef..8509574c65 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/ModelMetadataProviderExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/ModelMetadataProviderExtensions.cs @@ -3,7 +3,6 @@ using System; using Microsoft.AspNet.Mvc.Core; -using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding { @@ -12,25 +11,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// public static class ModelMetadataProviderExtensions { - /// - /// Gets a for the provided and - /// . - /// - /// The . - /// The declared of the model object. - /// The model object. - /// - /// A for the and . - /// - public static ModelExplorer GetModelExplorerForType( - [NotNull] this IModelMetadataProvider provider, - [NotNull] Type modelType, - object model) - { - var modelMetadata = provider.GetMetadataForType(modelType); - return new ModelExplorer(provider, modelMetadata, model); - } - /// /// Gets a for property identified by the provided /// and . @@ -40,10 +20,25 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// The property name. /// A for the property. public static ModelMetadata GetMetadataForProperty( - [NotNull] this IModelMetadataProvider provider, - [NotNull] Type containerType, - [NotNull] string propertyName) + this IModelMetadataProvider provider, + Type containerType, + string propertyName) { + if (provider == null) + { + throw new ArgumentNullException(nameof(provider)); + } + + if (containerType == null) + { + throw new ArgumentNullException(nameof(containerType)); + } + + if (propertyName == null) + { + throw new ArgumentNullException(nameof(propertyName)); + } + var containerMetadata = provider.GetMetadataForType(containerType); var propertyMetadata = containerMetadata.Properties[propertyName]; diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs index 77bac2c741..b917d18516 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs @@ -398,8 +398,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding IDictionary results) { var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; - var modelExplorer = - metadataProvider.GetModelExplorerForType(bindingContext.ModelType, bindingContext.Model); + var metadata = metadataProvider.GetMetadataForType(bindingContext.ModelType); + var validationInfo = GetPropertyValidationInfo(bindingContext); // Eliminate provided properties from RequiredProperties; leaving just *missing* required properties. @@ -408,8 +408,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding foreach (var missingRequiredProperty in validationInfo.RequiredProperties) { - var propertyExplorer = modelExplorer.GetExplorerForProperty(missingRequiredProperty); - var propertyName = propertyExplorer.Metadata.BinderModelName ?? missingRequiredProperty; + var propertyMetadata = metadata.Properties[missingRequiredProperty]; + var propertyName = propertyMetadata.BinderModelName ?? missingRequiredProperty; var modelStateKey = ModelNames.CreatePropertyModelName(bindingContext.ModelName, propertyName); bindingContext.ModelState.TryAddModelError( @@ -425,7 +425,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding { var result = entry.Value; var propertyMetadata = entry.Key; - SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + SetProperty(bindingContext, metadata, propertyMetadata, result); } } } @@ -434,15 +434,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// Updates a property in the current . /// /// The . - /// - /// The for the model containing property to set. + /// + /// The for the model containing property to set. /// /// The for the property to set. /// The for the property's new value. /// Should succeed in all cases that returns true. protected virtual void SetProperty( [NotNull] ModelBindingContext bindingContext, - [NotNull] ModelExplorer modelExplorer, + [NotNull] ModelMetadata metadata, [NotNull] ModelMetadata propertyMetadata, [NotNull] ModelBindingResult result) { @@ -464,7 +464,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding if (!property.CanWrite) { // Try to handle as a collection if property exists but is not settable. - AddToProperty(bindingContext, modelExplorer, property, result); + AddToProperty(bindingContext, metadata, property, result); return; } @@ -481,13 +481,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding private void AddToProperty( ModelBindingContext bindingContext, - ModelExplorer modelExplorer, + ModelMetadata modelMetadata, PropertyInfo property, ModelBindingResult result) { - var propertyExplorer = modelExplorer.GetExplorerForProperty(property.Name); + var propertyMetadata = modelMetadata.Properties[property.Name]; - var target = propertyExplorer.Model; + var target = propertyMetadata.PropertyGetter(bindingContext.Model); var source = result.Model; if (target == null || source == null) { @@ -504,14 +504,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding // Determine T if this is an ICollection property. No need for a T[] case because CanUpdateProperty() // ensures property is either settable or not an array. Underlying assumption is that CanUpdateProperty() // and SetProperty() are overridden together. - if (!propertyExplorer.Metadata.IsCollectionType) + if (!propertyMetadata.IsCollectionType) { // Not a collection model. return; } var propertyAddRange = CallPropertyAddRangeOpenGenericMethod.MakeGenericMethod( - propertyExplorer.Metadata.ElementMetadata.ModelType); + propertyMetadata.ElementMetadata.ModelType); try { propertyAddRange.Invoke(obj: null, parameters: new[] { target, source }); diff --git a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelExplorer.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelExplorer.cs similarity index 83% rename from src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelExplorer.cs rename to src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelExplorer.cs index 3836cbf6df..1a56ca9080 100644 --- a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelExplorer.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelExplorer.cs @@ -5,9 +5,10 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.Framework.Internal; -namespace Microsoft.AspNet.Mvc.ModelBinding +namespace Microsoft.AspNet.Mvc.ViewFeatures { /// /// Associates a model object with it's corresponding . @@ -29,10 +30,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// The . /// The model object. May be null. public ModelExplorer( - [NotNull] IModelMetadataProvider metadataProvider, - [NotNull] ModelMetadata metadata, + IModelMetadataProvider metadataProvider, + ModelMetadata metadata, object model) { + if (metadataProvider == null) + { + throw new ArgumentNullException(nameof(metadataProvider)); + } + + if (metadata == null) + { + throw new ArgumentNullException(nameof(metadata)); + } + _metadataProvider = metadataProvider; Metadata = metadata; _model = model; @@ -46,11 +57,26 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// The . /// A model accessor function. May be null. public ModelExplorer( - [NotNull] IModelMetadataProvider metadataProvider, - [NotNull] ModelExplorer container, - [NotNull] ModelMetadata metadata, + IModelMetadataProvider metadataProvider, + ModelExplorer container, + ModelMetadata metadata, Func modelAccessor) { + if (metadataProvider == null) + { + throw new ArgumentNullException(nameof(metadataProvider)); + } + + if (container == null) + { + throw new ArgumentNullException(nameof(container)); + } + + if (metadata == null) + { + throw new ArgumentNullException(nameof(metadata)); + } + _metadataProvider = metadataProvider; Container = container; Metadata = metadata; @@ -65,11 +91,21 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// The . /// The model object. May be null. public ModelExplorer( - [NotNull] IModelMetadataProvider metadataProvider, - [NotNull] ModelExplorer container, - [NotNull] ModelMetadata metadata, + IModelMetadataProvider metadataProvider, + ModelExplorer container, + ModelMetadata metadata, object model) { + if (metadataProvider == null) + { + throw new ArgumentNullException(nameof(metadataProvider)); + } + + if (metadata == null) + { + throw new ArgumentNullException(nameof(metadata)); + } + _metadataProvider = metadataProvider; Container = container; Metadata = metadata; @@ -216,8 +252,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// The property name. /// A , or null. - public ModelExplorer GetExplorerForProperty([NotNull] string name) + public ModelExplorer GetExplorerForProperty(string name) { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + return Properties.FirstOrDefault(p => string.Equals( p.Metadata.PropertyName, name, @@ -234,8 +275,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// As this creates a model explorer with a specific model accessor function, the result is not cached. /// - public ModelExplorer GetExplorerForProperty([NotNull] string name, Func modelAccessor) + public ModelExplorer GetExplorerForProperty(string name, Func modelAccessor) { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + var metadata = GetMetadataForRuntimeType(); var propertyMetadata = metadata.Properties[name]; @@ -257,8 +303,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// As this creates a model explorer with a specific model value, the result is not cached. /// - public ModelExplorer GetExplorerForProperty([NotNull] string name, object model) + public ModelExplorer GetExplorerForProperty(string name, object model) { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + var metadata = GetMetadataForRuntimeType(); var propertyMetadata = metadata.Properties[name]; @@ -286,8 +337,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// The returned will have the current instance set as its . /// /// - public ModelExplorer GetExplorerForExpression([NotNull] Type modelType, object model) + public ModelExplorer GetExplorerForExpression(Type modelType, object model) { + if (modelType == null) + { + throw new ArgumentNullException(nameof(modelType)); + } + var metadata = _metadataProvider.GetMetadataForType(modelType); return GetExplorerForExpression(metadata, model); } @@ -309,8 +365,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// The returned will have the current instance set as its . /// /// - public ModelExplorer GetExplorerForExpression([NotNull] ModelMetadata metadata, object model) + public ModelExplorer GetExplorerForExpression(ModelMetadata metadata, object model) { + if (metadata == null) + { + throw new ArgumentNullException(nameof(metadata)); + } + return new ModelExplorer(_metadataProvider, this, metadata, model); } @@ -331,8 +392,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// The returned will have the current instance set as its . /// /// - public ModelExplorer GetExplorerForExpression([NotNull] Type modelType, Func modelAccessor) + public ModelExplorer GetExplorerForExpression(Type modelType, Func modelAccessor) { + if (modelType == null) + { + throw new ArgumentNullException(nameof(modelType)); + } + var metadata = _metadataProvider.GetMetadataForType(modelType); return GetExplorerForExpression(metadata, modelAccessor); } @@ -354,8 +420,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// The returned will have the current instance set as its . /// /// - public ModelExplorer GetExplorerForExpression([NotNull] ModelMetadata metadata, Func modelAccessor) + public ModelExplorer GetExplorerForExpression(ModelMetadata metadata, Func modelAccessor) { + if (metadata == null) + { + throw new ArgumentNullException(nameof(metadata)); + } + return new ModelExplorer(_metadataProvider, this, metadata, modelAccessor); } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/ModelExplorerExtensions.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelExplorerExtensions.cs similarity index 86% rename from src/Microsoft.AspNet.Mvc.Core/ModelBinding/ModelExplorerExtensions.cs rename to src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelExplorerExtensions.cs index cb45a66360..81bfe57f25 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/ModelExplorerExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelExplorerExtensions.cs @@ -4,9 +4,9 @@ using System; using System.Linq; using System.Globalization; -using Microsoft.Framework.Internal; +using Microsoft.AspNet.Mvc.ModelBinding; -namespace Microsoft.AspNet.Mvc.ModelBinding +namespace Microsoft.AspNet.Mvc.ViewFeatures { /// /// Extension methods for . @@ -19,8 +19,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// The . /// A simple display string for the model. - public static string GetSimpleDisplayText([NotNull] this ModelExplorer modelExplorer) + public static string GetSimpleDisplayText(this ModelExplorer modelExplorer) { + if (modelExplorer == null) + { + throw new ArgumentNullException(nameof(modelExplorer)); + } + if (modelExplorer.Metadata.SimpleDisplayProperty != null) { var propertyExplorer = modelExplorer.GetExplorerForProperty( diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelExpression.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelExpression.cs index e65d8a3793..a0108d24a2 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelExpression.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelExpression.cs @@ -3,6 +3,7 @@ using System; using Microsoft.AspNet.Mvc.ModelBinding; +using Microsoft.AspNet.Mvc.ViewFeatures; namespace Microsoft.AspNet.Mvc.Rendering { diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelMetadataProviderExtensions.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelMetadataProviderExtensions.cs new file mode 100644 index 0000000000..71f206660f --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ModelMetadataProviderExtensions.cs @@ -0,0 +1,43 @@ +// 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 Microsoft.AspNet.Mvc.ModelBinding; + +namespace Microsoft.AspNet.Mvc.ViewFeatures +{ + /// + /// Extensions methods for . + /// + public static class ModelMetadataProviderExtensions + { + /// + /// Gets a for the provided and + /// . + /// + /// The . + /// The declared of the model object. + /// The model object. + /// + /// A for the and . + /// + public static ModelExplorer GetModelExplorerForType( + this IModelMetadataProvider provider, + Type modelType, + object model) + { + if (provider == null) + { + throw new ArgumentNullException(nameof(provider)); + } + + if (modelType == null) + { + throw new ArgumentNullException(nameof(modelType)); + } + + var modelMetadata = provider.GetMetadataForType(modelType); + return new ModelExplorer(provider, modelMetadata, model); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TemplateInfo.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TemplateInfo.cs index b2da019d53..e3e5bd4b79 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TemplateInfo.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TemplateInfo.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Microsoft.AspNet.Mvc.ModelBinding; namespace Microsoft.AspNet.Mvc.ViewFeatures { diff --git a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs index ff283cda7d..ecfd45bc8c 100644 --- a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs +++ b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs @@ -415,10 +415,7 @@ namespace System.Web.Http /// public void Validate(TEntity entity, string keyPrefix) { - var modelExplorer = MetadataProvider.GetModelExplorerForType(typeof(TEntity), entity); - var validatidationState = new ValidationStateDictionary(); - ObjectValidator.Validate( BindingContext.ValidatorProvider, ModelState, diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/MutableObjectModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/MutableObjectModelBinderTest.cs index 412e2e5034..1ae12bb4a3 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/MutableObjectModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/MutableObjectModelBinderTest.cs @@ -1240,14 +1240,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model); var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; - var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model); - var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.PropertyWithDefaultValue)]; + var metadata = metadataProvider.GetMetadataForType(typeof(Person)); + var propertyMetadata = metadata.Properties[nameof(model.PropertyWithDefaultValue)]; var result = ModelBindingResult.Failed("foo"); var testableBinder = new TestableMutableObjectModelBinder(); // Act - testableBinder.SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + testableBinder.SetProperty(bindingContext, metadata, propertyMetadata, result); // Assert var person = Assert.IsType(bindingContext.Model); @@ -1263,8 +1263,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model); var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; - var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model); - var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.PropertyWithInitializedValue)]; + var metadata = metadataProvider.GetMetadataForType(typeof(Person)); + var propertyMetadata = metadata.Properties[nameof(model.PropertyWithInitializedValue)]; // The null model value won't be used because IsModelBound = false. var result = ModelBindingResult.Failed("foo"); @@ -1272,7 +1272,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var testableBinder = new TestableMutableObjectModelBinder(); // Act - testableBinder.SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + testableBinder.SetProperty(bindingContext, metadata, propertyMetadata, result); // Assert var person = Assert.IsType(bindingContext.Model); @@ -1288,9 +1288,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model); var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; - var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model); - var propertyMetadata = - bindingContext.ModelMetadata.Properties[nameof(model.PropertyWithInitializedValueAndDefault)]; + var metadata = metadataProvider.GetMetadataForType(typeof(Person)); + var propertyMetadata = metadata.Properties[nameof(model.PropertyWithInitializedValueAndDefault)]; // The null model value won't be used because IsModelBound = false. var result = ModelBindingResult.Failed("foo"); @@ -1298,7 +1297,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var testableBinder = new TestableMutableObjectModelBinder(); // Act - testableBinder.SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + testableBinder.SetProperty(bindingContext, metadata, propertyMetadata, result); // Assert var person = Assert.IsType(bindingContext.Model); @@ -1314,14 +1313,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model); var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; - var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model); - var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.NonUpdateableProperty)]; + var metadata = metadataProvider.GetMetadataForType(typeof(Person)); + var propertyMetadata = metadata.Properties[nameof(model.NonUpdateableProperty)]; var result = ModelBindingResult.Failed("foo"); var testableBinder = new TestableMutableObjectModelBinder(); // Act - testableBinder.SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + testableBinder.SetProperty(bindingContext, metadata, propertyMetadata, result); // Assert // If didn't throw, success! @@ -1351,7 +1350,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding [MemberData(nameof(MyCanUpdateButCannotSetPropertyData))] public void SetProperty_ValueProvidedAndCanUpdatePropertyTrue_DoesNothing( string propertyName, - Func propertAccessor) + Func propertyAccessor) { // Arrange var model = new MyModelTestingCanUpdateProperty(); @@ -1359,7 +1358,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var bindingContext = CreateContext(GetMetadataForType(type), model); var modelState = bindingContext.ModelState; var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; - var modelExplorer = metadataProvider.GetModelExplorerForType(type, model); + var metadata = metadataProvider.GetMetadataForType(type); var propertyMetadata = bindingContext.ModelMetadata.Properties[propertyName]; var result = ModelBindingResult.Success( @@ -1369,10 +1368,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var testableBinder = new TestableMutableObjectModelBinder(); // Act - testableBinder.SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + testableBinder.SetProperty(bindingContext, metadata, propertyMetadata, result); // Assert - Assert.Equal("Joe", propertAccessor(model)); + Assert.Equal("Joe", propertyAccessor(model)); Assert.True(modelState.IsValid); Assert.Empty(modelState); } @@ -1436,14 +1435,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var bindingContext = CreateContext(GetMetadataForType(type), model); var modelState = bindingContext.ModelState; var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; - var modelExplorer = metadataProvider.GetModelExplorerForType(type, model); + var metadata = metadataProvider.GetMetadataForType(type); var propertyMetadata = bindingContext.ModelMetadata.Properties[propertyName]; var result = ModelBindingResult.Success(propertyName, collection); var testableBinder = new TestableMutableObjectModelBinder(); // Act - testableBinder.SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + testableBinder.SetProperty(bindingContext, metadata, propertyMetadata, result); // Assert Assert.Equal(collection, propertyAccessor(model)); @@ -1459,14 +1458,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model); var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; - var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model); + var metadata = metadataProvider.GetMetadataForType(typeof(Person)); var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.DateOfBirth)]; var result = ModelBindingResult.Success("foo", new DateTime(2001, 1, 1)); var testableBinder = new TestableMutableObjectModelBinder(); // Act - testableBinder.SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + testableBinder.SetProperty(bindingContext, metadata, propertyMetadata, result); // Assert Assert.True(bindingContext.ModelState.IsValid); @@ -1486,14 +1485,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model); var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; - var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model); + var metadata = metadataProvider.GetMetadataForType(typeof(Person)); var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.DateOfDeath)]; var result = ModelBindingResult.Success("foo", new DateTime(1800, 1, 1)); var testableBinder = new TestableMutableObjectModelBinder(); // Act - testableBinder.SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + testableBinder.SetProperty(bindingContext, metadata, propertyMetadata, result); // Assert Assert.Equal("Date of death can't be before date of birth." + Environment.NewLine @@ -1511,14 +1510,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model); var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; - var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model); + var metadata = metadataProvider.GetMetadataForType(typeof(Person)); var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.DateOfBirth)]; var result = ModelBindingResult.Success("foo.DateOfBirth", model: null); var testableBinder = new TestableMutableObjectModelBinder(); // Act - testableBinder.SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + testableBinder.SetProperty(bindingContext, metadata, propertyMetadata, result); // Assert Assert.False(bindingContext.ModelState.IsValid); @@ -1539,14 +1538,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding bindingContext.ModelName = "foo"; var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; - var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(ModelWhosePropertySetterThrows), model); + var metadata = metadataProvider.GetMetadataForType(typeof(ModelWhosePropertySetterThrows)); var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.NameNoAttribute)]; var result = ModelBindingResult.Success("foo.NameNoAttribute", model: null); var testableBinder = new TestableMutableObjectModelBinder(); // Act - testableBinder.SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + testableBinder.SetProperty(bindingContext, metadata, propertyMetadata, result); // Assert Assert.False(bindingContext.ModelState.IsValid); @@ -1898,11 +1897,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public new void SetProperty( ModelBindingContext bindingContext, - ModelExplorer modelExplorer, + ModelMetadata metadata, ModelMetadata propertyMetadata, ModelBindingResult result) { - base.SetProperty(bindingContext, modelExplorer, propertyMetadata, result); + base.SetProperty(bindingContext, metadata, propertyMetadata, result); } } } diff --git a/test/Microsoft.AspNet.Mvc.DataAnnotations.Test/DataAnnotationsModelValidatorTest.cs b/test/Microsoft.AspNet.Mvc.DataAnnotations.Test/DataAnnotationsModelValidatorTest.cs index c0dc751b97..47b32d7fed 100644 --- a/test/Microsoft.AspNet.Mvc.DataAnnotations.Test/DataAnnotationsModelValidatorTest.cs +++ b/test/Microsoft.AspNet.Mvc.DataAnnotations.Test/DataAnnotationsModelValidatorTest.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation private static IModelMetadataProvider _metadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); [Fact] - public void ValuesSet() + public void Constructor_SetsAttribute() { // Arrange var attribute = new RequiredAttribute(); @@ -33,29 +33,35 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation Assert.Same(attribute, validator.Attribute); } - public static IEnumerable ValidateSetsMemberNamePropertyDataSet + public static IEnumerable Validate_SetsMemberName_OnValidationContext_ForProperties_Data { get { yield return new object[] { - _metadataProvider.GetModelExplorerForType(typeof(string), "Hello").GetExplorerForProperty("Length"), - "Length" + _metadataProvider.GetMetadataForType(typeof(string)).Properties["Length"], + "Hello", + "Hello".Length, + "Length", }; yield return new object[] { - _metadataProvider.GetModelExplorerForType(typeof(SampleModel), 15), - "SampleModel" + _metadataProvider.GetMetadataForType(typeof(SampleModel)), + null, + 15, + "SampleModel", }; } } #if DNX451 [Theory] - [MemberData(nameof(ValidateSetsMemberNamePropertyDataSet))] - public void ValidateSetsMemberNamePropertyOfValidationContextForProperties( - ModelExplorer modelExplorer, + [MemberData(nameof(Validate_SetsMemberName_OnValidationContext_ForProperties_Data))] + public void Validate_SetsMemberName_OnValidationContext_ForProperties( + ModelMetadata metadata, + object container, + object model, string expectedMemberName) { // Arrange @@ -69,7 +75,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation .Returns(ValidationResult.Success) .Verifiable(); var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null); - var validationContext = CreateValidationContext(modelExplorer); + var validationContext = new ModelValidationContext() + { + Metadata = metadata, + Container = container, + Model = model, + }; // Act var results = validator.Validate(validationContext); @@ -80,18 +91,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation } [Fact] - public void ValidateWithIsValidTrue() + public void Validate_Valid() { // Arrange - var modelExplorer = _metadataProvider - .GetModelExplorerForType(typeof(string), "Hello") - .GetExplorerForProperty("Length"); + var metadata = _metadataProvider.GetMetadataForType(typeof(string)); + var container = "Hello"; + var model = container.Length; var attribute = new Mock { CallBase = true }; - attribute.Setup(a => a.IsValid(modelExplorer.Model)).Returns(true); + attribute.Setup(a => a.IsValid(model)).Returns(true); var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null); - var validationContext = CreateValidationContext(modelExplorer); + var validationContext = new ModelValidationContext() + { + Metadata = metadata, + Container = container, + Model = model, + }; // Act var result = validator.Validate(validationContext); @@ -101,18 +117,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation } [Fact] - public void ValidateWithIsValidFalse() + public void Validate_Invalid() { // Arrange - var modelExplorer = _metadataProvider - .GetModelExplorerForType(typeof(string), "Hello") - .GetExplorerForProperty("Length"); + var metadata = _metadataProvider.GetMetadataForProperty(typeof(string), "Length"); + var container = "Hello"; + var model = container.Length; var attribute = new Mock { CallBase = true }; - attribute.Setup(a => a.IsValid(modelExplorer.Model)).Returns(false); + attribute.Setup(a => a.IsValid(model)).Returns(false); var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null); - var validationContext = CreateValidationContext(modelExplorer); + var validationContext = new ModelValidationContext() + { + Metadata = metadata, + Container = container, + Model = model, + }; // Act var result = validator.Validate(validationContext); @@ -124,19 +145,24 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation } [Fact] - public void ValidatateWithValidationResultSuccess() + public void Validatate_ValidationResultSuccess() { // Arrange - var modelExplorer = _metadataProvider - .GetModelExplorerForType(typeof(string), "Hello") - .GetExplorerForProperty("Length"); + var metadata = _metadataProvider.GetMetadataForType(typeof(string)); + var container = "Hello"; + var model = container.Length; var attribute = new Mock { CallBase = true }; attribute.Protected() .Setup("IsValid", ItExpr.IsAny(), ItExpr.IsAny()) .Returns(ValidationResult.Success); var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null); - var validationContext = CreateValidationContext(modelExplorer); + var validationContext = new ModelValidationContext() + { + Metadata = metadata, + Container = container, + Model = model, + }; // Act var result = validator.Validate(validationContext); @@ -146,14 +172,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation } [Fact] - public void ValidateReturnsSingleValidationResultIfMemberNameSequenceIsEmpty() + public void Validate_ReturnsSingleValidationResult_IfMemberNameSequenceIsEmpty() { // Arrange const string errorMessage = "Some error message"; - var modelExplorer = _metadataProvider - .GetModelExplorerForType(typeof(string), "Hello") - .GetExplorerForProperty("Length"); + var metadata = _metadataProvider.GetMetadataForType(typeof(string)); + var container = "Hello"; + var model = container.Length; var attribute = new Mock { CallBase = true }; attribute.Protected() @@ -161,24 +187,30 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation .Returns(new ValidationResult(errorMessage, memberNames: null)); var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null); - var validationContext = CreateValidationContext(modelExplorer); + var validationContext = new ModelValidationContext() + { + Metadata = metadata, + Container = container, + Model = model, + }; // Act var results = validator.Validate(validationContext); // Assert - ModelValidationResult validationResult = Assert.Single(results); + var validationResult = Assert.Single(results); Assert.Equal(errorMessage, validationResult.Message); Assert.Empty(validationResult.MemberName); } [Fact] - public void ValidateReturnsSingleValidationResultIfOneMemberNameIsSpecified() + public void Validate_ReturnsSingleValidationResult_IfOneMemberNameIsSpecified() { // Arrange const string errorMessage = "A different error message"; - var modelExplorer = _metadataProvider.GetModelExplorerForType(typeof(object), new object()); + var metadata = _metadataProvider.GetMetadataForType(typeof(object)); + var model = new object(); var attribute = new Mock { CallBase = true }; attribute.Protected() @@ -186,7 +218,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation .Returns(new ValidationResult(errorMessage, new[] { "FirstName" })); var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null); - var validationContext = CreateValidationContext(modelExplorer); + var validationContext = new ModelValidationContext() + { + Metadata = metadata, + Model = model, + }; // Act var results = validator.Validate(validationContext); @@ -198,10 +234,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation } [Fact] - public void ValidateReturnsMemberNameIfItIsDifferentFromDisplayName() + public void Validate_ReturnsMemberName_IfItIsDifferentFromDisplayName() { // Arrange - var modelExplorer = _metadataProvider.GetModelExplorerForType(typeof(SampleModel), new SampleModel()); + var metadata = _metadataProvider.GetMetadataForType(typeof(SampleModel)); + var model = new SampleModel(); var attribute = new Mock { CallBase = true }; attribute.Protected() @@ -209,7 +246,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation .Returns(new ValidationResult("Name error", new[] { "Name" })); var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer: null); - var validationContext = CreateValidationContext(modelExplorer); + var validationContext = new ModelValidationContext() + { + Metadata = metadata, + Model = model, + }; // Act var results = validator.Validate(validationContext); @@ -220,15 +261,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation } [Fact] - public void ValidateWithIsValidFalse_StringLocalizerReturnsLocalizerErrorMessage() + public void Validate_IsValidFalse_StringLocalizerReturnsLocalizerErrorMessage() { // Arrange - var modelExplorer = _metadataProvider - .GetModelExplorerForType(typeof(string), "Hello") - .GetExplorerForProperty("Length"); + var metadata = _metadataProvider.GetMetadataForType(typeof(string)); + var container = "Hello"; + var model = container.Length; var attribute = new Mock { CallBase = true }; - attribute.Setup(a => a.IsValid(modelExplorer.Model)).Returns(false); + attribute.Setup(a => a.IsValid(model)).Returns(false); attribute.Object.ErrorMessage = "Length"; @@ -237,7 +278,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation stringLocalizer.Setup(s => s["Length"]).Returns(localizedString); var validator = new DataAnnotationsModelValidator(attribute.Object, stringLocalizer.Object); - var validationContext = CreateValidationContext(modelExplorer); + var validationContext = new ModelValidationContext() + { + Metadata = metadata, + Container = container, + Model = model, + }; // Act var result = validator.Validate(validationContext); @@ -260,16 +306,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation .IsRequired); } - private static ModelValidationContext CreateValidationContext(ModelExplorer modelExplorer) - { - return new ModelValidationContext() - { - Container = modelExplorer.Container, - Metadata = modelExplorer.Metadata, - Model = modelExplorer.Model, - }; - } - private class DerivedRequiredAttribute : RequiredAttribute { } diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LabelTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LabelTagHelperTest.cs index 2d9d586531..be52aa5fc2 100644 --- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LabelTagHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LabelTagHelperTest.cs @@ -6,8 +6,9 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding; -using Microsoft.AspNet.Mvc.TestCommon; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.TestCommon; +using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Razor.Runtime.TagHelpers; using Xunit; diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperLabelExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperLabelExtensionsTest.cs index d0dc9570ef..6ede8bfc1d 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperLabelExtensionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperLabelExtensionsTest.cs @@ -5,6 +5,7 @@ using System; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.TestCommon; +using Microsoft.AspNet.Mvc.ViewFeatures; using Xunit; namespace Microsoft.AspNet.Mvc.Core diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/Metadata/ModelExplorerExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ModelExplorerExtensionsTest.cs similarity index 96% rename from test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/Metadata/ModelExplorerExtensionsTest.cs rename to test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ModelExplorerExtensionsTest.cs index 7ea0c683d5..e5bb3e88e2 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/Metadata/ModelExplorerExtensionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ModelExplorerExtensionsTest.cs @@ -2,10 +2,10 @@ // 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.AspNet.Mvc.ModelBinding; using Xunit; -namespace Microsoft.AspNet.Mvc.ModelBinding +namespace Microsoft.AspNet.Mvc.ViewFeatures { public class ModelExplorerExtensionsTest { diff --git a/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ModelExplorerTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ModelExplorerTest.cs similarity index 98% rename from test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ModelExplorerTest.cs rename to test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ModelExplorerTest.cs index b60df64df2..28976ef3cf 100644 --- a/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ModelExplorerTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ModelExplorerTest.cs @@ -2,9 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Linq; +using Microsoft.AspNet.Mvc.ModelBinding; using Xunit; -namespace Microsoft.AspNet.Mvc.ModelBinding +namespace Microsoft.AspNet.Mvc.ViewFeatures { public class ModelExplorerTest {