From dadee80aa8e38d43c7e89de4b24dbf6a46deb6da Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Wed, 26 Aug 2015 18:00:40 -0700 Subject: [PATCH] Add FieldName to model binding context Adds a new property, FieldName, to ModelBindingContext. The FieldName is the name of whatever code-element is being bound, regardless of what model-prefix is in use. This is needed for cases like the Header model binder. We always want to use the property/parameter name and we don't care about model prefixes. --- .../ModelBinding/ModelBindingContext.cs | 168 +++++++----------- .../DefaultControllerActionArgumentBinder.cs | 28 +-- .../ModelBinding/CollectionModelBinder.cs | 21 ++- .../ModelBinding/CompositeModelBinder.cs | 1 + .../ModelBinding/DictionaryModelBinder.cs | 8 +- .../ModelBinding/HeaderModelBinder.cs | 2 +- .../ModelBinding/KeyValuePairModelBinder.cs | 7 +- .../ModelBinding/MutableObjectModelBinder.cs | 40 +++-- .../ModelBindingHelper.cs | 23 ++- .../ModelBinding/ArrayModelBinderTest.cs | 3 +- .../ModelBinding/ByteArrayModelBinderTests.cs | 3 +- .../ModelBinding/CollectionModelBinderTest.cs | 1 + .../ModelBinding/CompositeModelBinderTest.cs | 69 ++----- .../ModelBinding/DictionaryModelBinderTest.cs | 2 + .../ModelBinding/FormFileModelBinderTest.cs | 1 + .../ModelBinding/HeaderModelBinderTests.cs | 6 +- .../KeyValuePairModelBinderTest.cs | 1 + .../ModelBinding/ModelBindingContextTest.cs | 29 +-- .../MutableObjectModelBinderTest.cs | 4 +- .../ModelBinding/SimpleTypeModelBinderTest.cs | 1 + 20 files changed, 179 insertions(+), 239 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs b/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs index 1baacfe984..9b161125f8 100644 --- a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs +++ b/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding @@ -15,10 +14,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding private static readonly Func _defaultPropertyFilter = (context, propertyName) => true; - private string _modelName; - private ModelStateDictionary _modelState; - private Func _propertyFilter; - /// /// Initializes a new instance of the class. /// @@ -27,67 +22,82 @@ namespace Microsoft.AspNet.Mvc.ModelBinding } /// - /// Constructs a new instance of the class using the - /// . + /// Creates a new for top-level model binding operation. /// - /// Existing . - /// Model name of associated with the new . - /// Model metadata of associated with the new . + /// + /// The associated with the binding operation. /// - public static ModelBindingContext GetChildModelBindingContext( - [NotNull] ModelBindingContext bindingContext, - [NotNull] string modelName, - [NotNull] ModelMetadata modelMetadata) - { - var modelBindingContext = new ModelBindingContext - { - ModelName = modelName, - ModelMetadata = modelMetadata, - - ModelState = bindingContext.ModelState, - ValueProvider = bindingContext.ValueProvider, - OperationBindingContext = bindingContext.OperationBindingContext, - - BindingSource = modelMetadata.BindingSource, - BinderModelName = modelMetadata.BinderModelName, - BinderType = modelMetadata.BinderType, - }; - - return modelBindingContext; - } - - /// - /// Constructs a new instance of from given - /// and . - /// /// associated with the model. /// associated with the model. - /// An optional name of the model to be used. + /// The name of the property or parameter being bound. /// A new instance of . - public static ModelBindingContext GetModelBindingContext( + public static ModelBindingContext CreateBindingContext( + [NotNull] OperationBindingContext operationBindingContext, + [NotNull] ModelStateDictionary modelState, [NotNull] ModelMetadata metadata, BindingInfo bindingInfo, - string modelName) + [NotNull] string modelName) { var binderModelName = bindingInfo?.BinderModelName ?? metadata.BinderModelName; var propertyPredicateProvider = bindingInfo?.PropertyBindingPredicateProvider ?? metadata.PropertyBindingPredicateProvider; - return new ModelBindingContext + + return new ModelBindingContext() { - ModelMetadata = metadata, - BindingSource = bindingInfo?.BindingSource ?? metadata.BindingSource, - PropertyFilter = propertyPredicateProvider?.PropertyFilter, - BinderType = bindingInfo?.BinderType ?? metadata.BinderType, BinderModelName = binderModelName, - ModelName = binderModelName ?? metadata.PropertyName ?? modelName, + BindingSource = bindingInfo?.BindingSource ?? metadata.BindingSource, + BinderType = bindingInfo?.BinderType ?? metadata.BinderType, + PropertyFilter = propertyPredicateProvider?.PropertyFilter, + + // We only support fallback to empty prefix in cases where the model name is inferred from + // the parameter or property being bound. FallbackToEmptyPrefix = binderModelName == null, + + // Because this is the top-level context, FieldName and ModelName should be the same. + FieldName = binderModelName ?? modelName, + ModelName = binderModelName ?? modelName, + + IsTopLevelObject = true, + ModelMetadata = metadata, + ModelState = modelState, + OperationBindingContext = operationBindingContext, + ValueProvider = operationBindingContext.ValueProvider, + }; + } + + public static ModelBindingContext CreateChildBindingContext( + [NotNull] ModelBindingContext parent, + [NotNull] ModelMetadata modelMetadata, + [NotNull] string fieldName, + [NotNull] string modelName, + object model) + { + return new ModelBindingContext() + { + ModelState = parent.ModelState, + OperationBindingContext = parent.OperationBindingContext, + ValueProvider = parent.ValueProvider, + + Model = model, + ModelMetadata = modelMetadata, + ModelName = modelName, + FieldName = fieldName, + BinderModelName = modelMetadata.BinderModelName, + BinderType = modelMetadata.BinderType, + BindingSource = modelMetadata.BindingSource, + PropertyFilter = modelMetadata.PropertyBindingPredicateProvider?.PropertyFilter, }; } /// /// Represents the associated with this context. /// - public OperationBindingContext OperationBindingContext { get; set; } + public OperationBindingContext OperationBindingContext { get; [param:NotNull] set; } + + /// + /// Gets or sets the name of the current field being bound. + /// + public string FieldName { get; [param: NotNull] set; } /// /// Gets or sets the model value for the current operation. @@ -101,41 +111,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// Gets or sets the metadata for the model associated with this context. /// - public ModelMetadata ModelMetadata { get; set; } + public ModelMetadata ModelMetadata { get; [param: NotNull] set; } /// /// Gets or sets the name of the model. This property is used as a key for looking up values in /// during model binding. /// - public string ModelName - { - get - { - if (_modelName == null) - { - _modelName = string.Empty; - } - return _modelName; - } - set { _modelName = value; } - } + public string ModelName { get; [param: NotNull] set; } /// /// Gets or sets the used to capture values /// for properties in the object graph of the model when binding. /// - public ModelStateDictionary ModelState - { - get - { - if (_modelState == null) - { - _modelState = new ModelStateDictionary(); - } - return _modelState; - } - set { _modelState = value; } - } + public ModelStateDictionary ModelState { get; [param: NotNull] set; } /// /// Gets the type of the model. @@ -143,14 +131,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// The property must be set to access this property. /// - public Type ModelType - { - get - { - EnsureModelMetadata(); - return ModelMetadata.ModelType; - } - } + public Type ModelType => ModelMetadata?.ModelType; /// /// Gets or sets a model name which is explicitly set using an . @@ -202,27 +183,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// Gets or sets the associated with this context. /// - public IValueProvider ValueProvider { get; set; } + public IValueProvider ValueProvider { get; [param: NotNull] set; } - public Func PropertyFilter - { - get - { - if (_propertyFilter == null) - { - _propertyFilter = _defaultPropertyFilter; - } - return _propertyFilter; - } - set { _propertyFilter = value; } - } - - private void EnsureModelMetadata() - { - if (ModelMetadata == null) - { - throw new InvalidOperationException(Resources.ModelBindingContext_ModelMetadataMustBeSet); - } - } + /// + /// Gets or sets a predicate which will be evaluated for each property to determine if the property + /// is eligible for model binding. + /// + public Func PropertyFilter { get; set; } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/DefaultControllerActionArgumentBinder.cs b/src/Microsoft.AspNet.Mvc.Core/DefaultControllerActionArgumentBinder.cs index 12b96429fe..65fbbe458e 100644 --- a/src/Microsoft.AspNet.Mvc.Core/DefaultControllerActionArgumentBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DefaultControllerActionArgumentBinder.cs @@ -73,12 +73,12 @@ namespace Microsoft.AspNet.Mvc [NotNull] OperationBindingContext operationContext) { var metadata = _modelMetadataProvider.GetMetadataForType(parameter.ParameterType); - var modelBindingContext = GetModelBindingContext( - parameter.Name, + var modelBindingContext = ModelBindingContext.CreateBindingContext( + operationContext, + modelState, metadata, parameter.BindingInfo, - modelState, - operationContext); + parameter.Name); var modelBindingResult = await operationContext.ModelBinder.BindModelAsync(modelBindingContext); if (modelBindingResult != null && @@ -187,26 +187,6 @@ namespace Microsoft.AspNet.Mvc } } - private static ModelBindingContext GetModelBindingContext( - string parameterName, - ModelMetadata metadata, - BindingInfo bindingInfo, - ModelStateDictionary modelState, - OperationBindingContext operationBindingContext) - { - var modelBindingContext = ModelBindingContext.GetModelBindingContext( - metadata, - bindingInfo, - parameterName); - - modelBindingContext.IsTopLevelObject = true; - modelBindingContext.ModelState = modelState; - modelBindingContext.ValueProvider = operationBindingContext.ValueProvider; - modelBindingContext.OperationBindingContext = operationBindingContext; - - return modelBindingContext; - } - private OperationBindingContext GetOperationBindingContext( ActionContext actionContext, ActionBindingContext bindingContext) diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/CollectionModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/CollectionModelBinder.cs index 8177bfa34c..a2e3561e41 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/CollectionModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/CollectionModelBinder.cs @@ -149,12 +149,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding bindingContext.ModelName, bindingContext.ModelMetadata, boundCollection); + + var innerBindingContext = ModelBindingContext.CreateChildBindingContext( + bindingContext, + elementMetadata, + fieldName: bindingContext.FieldName, + modelName: bindingContext.ModelName, + model: null); + foreach (var value in values) { - var innerBindingContext = ModelBindingContext.GetChildModelBindingContext( - bindingContext, - bindingContext.ModelName, - elementMetadata); innerBindingContext.ValueProvider = new CompositeValueProvider { // our temporary provider goes at the front of the list @@ -222,10 +226,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding foreach (var indexName in indexNames) { var fullChildName = ModelNames.CreateIndexModelName(bindingContext.ModelName, indexName); - var childBindingContext = ModelBindingContext.GetChildModelBindingContext( + var childBindingContext = ModelBindingContext.CreateChildBindingContext( bindingContext, - fullChildName, - elementMetadata); + elementMetadata, + fieldName: indexName, + modelName: fullChildName, + model: null); + var didBind = false; object boundValue = null; diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/CompositeModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/CompositeModelBinder.cs index 1cc67fb877..ee7f34f928 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/CompositeModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/CompositeModelBinder.cs @@ -148,6 +148,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding Model = oldBindingContext.Model, ModelMetadata = oldBindingContext.ModelMetadata, ModelName = modelName, + FieldName = oldBindingContext.FieldName, ModelState = oldBindingContext.ModelState, ValueProvider = oldBindingContext.ValueProvider, OperationBindingContext = oldBindingContext.OperationBindingContext, diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/DictionaryModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/DictionaryModelBinder.cs index 640f5c8c7d..85f229eb71 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/DictionaryModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/DictionaryModelBinder.cs @@ -57,10 +57,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding // Update the existing successful but empty ModelBindingResult. var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; var valueMetadata = metadataProvider.GetMetadataForType(typeof(TValue)); - var valueBindingContext = ModelBindingContext.GetChildModelBindingContext( + var valueBindingContext = ModelBindingContext.CreateChildBindingContext( bindingContext, - bindingContext.ModelName, - valueMetadata); + valueMetadata, + fieldName: bindingContext.FieldName, + modelName: bindingContext.ModelName, + model: null); var modelBinder = bindingContext.OperationBindingContext.ModelBinder; var validationNode = result.ValidationNode; diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/HeaderModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/HeaderModelBinder.cs index addca0ccda..21cd423056 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/HeaderModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/HeaderModelBinder.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var modelMetadata = bindingContext.ModelMetadata; // Property name can be null if the model metadata represents a type (rather than a property or parameter). - var headerName = bindingContext.BinderModelName ?? modelMetadata.PropertyName ?? bindingContext.ModelName; + var headerName = bindingContext.FieldName; object model = null; if (bindingContext.ModelType == typeof(string)) { diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/KeyValuePairModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/KeyValuePairModelBinder.cs index f0b4321a76..4a54e68747 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/KeyValuePairModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/KeyValuePairModelBinder.cs @@ -93,11 +93,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding parentBindingContext.OperationBindingContext.MetadataProvider.GetMetadataForType(typeof(TModel)); var propertyModelName = ModelNames.CreatePropertyModelName(parentBindingContext.ModelName, propertyName); - var propertyBindingContext = ModelBindingContext.GetChildModelBindingContext( + var propertyBindingContext = ModelBindingContext.CreateChildBindingContext( parentBindingContext, + propertyModelMetadata, + propertyName, propertyModelName, - propertyModelMetadata); - propertyBindingContext.BinderModelName = propertyModelMetadata.BinderModelName; + model: null); var modelBindingResult = await propertyBindingContext.OperationBindingContext.ModelBinder.BindModelAsync( propertyBindingContext); diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs index b3806828b9..7e65459545 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs @@ -160,14 +160,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding { isAnyPropertyEnabledForValueProviderBasedBinding = true; - var propertyModelName = ModelNames.CreatePropertyModelName( + var fieldName = propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName; + var modelName = ModelNames.CreatePropertyModelName( context.ModelBindingContext.ModelName, - propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName); + fieldName); - var propertyModelBindingContext = ModelBindingContext.GetChildModelBindingContext( + var propertyModelBindingContext = ModelBindingContext.CreateChildBindingContext( context.ModelBindingContext, - propertyModelName, - propertyMetadata); + propertyMetadata, + fieldName: fieldName, + modelName: modelName, + model: null); // If any property can return a true value. if (CanBindValue(propertyModelBindingContext)) @@ -274,31 +277,34 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var results = new Dictionary(); foreach (var propertyMetadata in propertyMetadatas) { - var propertyModelName = ModelNames.CreatePropertyModelName( - bindingContext.ModelName, - propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName); - var childContext = ModelBindingContext.GetChildModelBindingContext( - bindingContext, - propertyModelName, - propertyMetadata); - // ModelBindingContext.Model property values may be non-null when invoked via TryUpdateModel(). Pass // complex (including collection) values down so that binding system does not unnecessarily recreate // instances or overwrite inner properties that are not bound. No need for this with simple values // because they will be overwritten if binding succeeds. Arrays are never reused because they cannot // be resized. + object model = null; if (propertyMetadata.PropertyGetter != null && propertyMetadata.IsComplexType && !propertyMetadata.ModelType.IsArray) { - childContext.Model = propertyMetadata.PropertyGetter(bindingContext.Model); + model = propertyMetadata.PropertyGetter(bindingContext.Model); } - var result = await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(childContext); + var fieldName = propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName; + var modelName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, fieldName); + + var propertyContext = ModelBindingContext.CreateChildBindingContext( + bindingContext, + propertyMetadata, + fieldName: fieldName, + modelName: modelName, + model: model); + + var result = await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(propertyContext); if (result == null) { // Could not bind. Let ProcessResult() know explicitly. - result = new ModelBindingResult(model: null, key: propertyModelName, isModelSet: false); + result = new ModelBindingResult(model: null, key: propertyContext.ModelName, isModelSet: false); } results[propertyMetadata] = result; @@ -359,7 +365,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var modelMetadataPredicate = context.ModelMetadata.PropertyBindingPredicateProvider?.PropertyFilter; return - context.PropertyFilter(context, propertyName) && + (context.PropertyFilter == null || context.PropertyFilter(context, propertyName)) && (modelMetadataPredicate == null || modelMetadataPredicate(context, propertyName)); }; } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBindingHelper.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBindingHelper.cs index fb857b24d0..a0c8104610 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBindingHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBindingHelper.cs @@ -293,21 +293,18 @@ namespace Microsoft.AspNet.Mvc ModelBinder = modelBinder, ValidatorProvider = validatorProvider, MetadataProvider = metadataProvider, - HttpContext = httpContext + HttpContext = httpContext, + ValueProvider = valueProvider, }; - var modelBindingContext = new ModelBindingContext - { - Model = model, - ModelMetadata = modelMetadata, - ModelName = prefix, - ModelState = modelState, - ValueProvider = valueProvider, - FallbackToEmptyPrefix = true, - IsTopLevelObject = true, - OperationBindingContext = operationBindingContext, - PropertyFilter = predicate, - }; + var modelBindingContext = ModelBindingContext.CreateBindingContext( + operationBindingContext, + modelState, + modelMetadata, + bindingInfo: null, + modelName: prefix ?? string.Empty); + modelBindingContext.Model = model; + modelBindingContext.PropertyFilter = predicate; var modelBindingResult = await modelBinder.BindModelAsync(modelBindingContext); if (modelBindingResult != null && modelBindingResult.IsModelSet) diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ArrayModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ArrayModelBinderTest.cs index e525fadd9f..7c8caeeb23 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ArrayModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ArrayModelBinderTest.cs @@ -222,11 +222,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { ModelMetadata = modelMetadata, ModelName = "someName", + ModelState = new ModelStateDictionary(), ValueProvider = valueProvider, OperationBindingContext = new OperationBindingContext { ModelBinder = CreateIntBinder(), - MetadataProvider = metadataProvider + MetadataProvider = metadataProvider, }, }; return bindingContext; diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ByteArrayModelBinderTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ByteArrayModelBinderTests.cs index 4c94bd9cfb..a5ce295316 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ByteArrayModelBinderTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ByteArrayModelBinderTests.cs @@ -129,10 +129,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { ModelMetadata = metadataProvider.GetMetadataForType(modelType), ModelName = "foo", + ModelState = new ModelStateDictionary(), ValueProvider = valueProvider, OperationBindingContext = new OperationBindingContext { - MetadataProvider = metadataProvider + MetadataProvider = metadataProvider, } }; return bindingContext; diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/CollectionModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/CollectionModelBinderTest.cs index 28f553726a..5855ec4008 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/CollectionModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/CollectionModelBinderTest.cs @@ -419,6 +419,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { ModelMetadata = metadataProvider.GetMetadataForType(typeof(IList)), ModelName = "someName", + ModelState = new ModelStateDictionary(), ValueProvider = valueProvider, OperationBindingContext = new OperationBindingContext { diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/CompositeModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/CompositeModelBinderTest.cs index 4ee4418633..2a7da19eca 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/CompositeModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/CompositeModelBinderTest.cs @@ -24,14 +24,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int)), ModelName = "someName", ModelState = new ModelStateDictionary(), + OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider { { "someName", "dummyValue" } }, - OperationBindingContext = new OperationBindingContext - { - ValidatorProvider = GetValidatorProvider() - } }; var mockIntBinder = new Mock(); @@ -71,14 +68,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List)), ModelName = "someName", ModelState = new ModelStateDictionary(), + OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider { { "someOtherName", "dummyValue" } }, - OperationBindingContext = new OperationBindingContext - { - ValidatorProvider = GetValidatorProvider() - } }; var mockIntBinder = new Mock(); @@ -121,14 +115,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List)), ModelName = "someName", ModelState = new ModelStateDictionary(), + OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider { { "someOtherName", "dummyValue" } }, - OperationBindingContext = new OperationBindingContext - { - ValidatorProvider = GetValidatorProvider() - } }; var modelBinder = new Mock(); @@ -155,14 +146,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List)), ModelName = "someName", ModelState = new ModelStateDictionary(), + OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider { { "someOtherName", "dummyValue" } }, - OperationBindingContext = new OperationBindingContext - { - ValidatorProvider = GetValidatorProvider() - } }; var count = 0; @@ -201,14 +189,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List)), ModelName = "someName", ModelState = new ModelStateDictionary(), + OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider { { "someOtherName", "dummyValue" } }, - OperationBindingContext = new OperationBindingContext - { - ValidatorProvider = GetValidatorProvider() - } }; var modelBinder = new Mock(); @@ -238,14 +223,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List)), ModelName = "someName", ModelState = new ModelStateDictionary(), + OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider { { "someOtherName", "dummyValue" } }, - OperationBindingContext = new OperationBindingContext - { - ValidatorProvider = GetValidatorProvider() - } }; var modelBinder = new Mock(); @@ -276,14 +258,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List)), ModelName = "someName", ModelState = new ModelStateDictionary(), + OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider { { "someOtherName", "dummyValue" } }, - OperationBindingContext = new OperationBindingContext - { - ValidatorProvider = GetValidatorProvider() - } }; var modelBinder = new Mock(); @@ -318,6 +297,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { FallbackToEmptyPrefix = false, ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List)), + ModelState = new ModelStateDictionary(), }; // Act @@ -341,7 +321,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test FallbackToEmptyPrefix = true, ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int)), ModelState = new ModelStateDictionary(), - OperationBindingContext = Mock.Of(), + OperationBindingContext = new OperationBindingContext(), }; // Act @@ -504,24 +484,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test Assert.Same(validationNode, result.ValidationNode); } - private static ModelBindingContext CreateBindingContext(IModelBinder binder, - IValueProvider valueProvider, - Type type, - IModelValidatorProvider validatorProvider = null) + private static ModelBindingContext CreateBindingContext( + IModelBinder binder, + IValueProvider valueProvider, + Type type) { - validatorProvider = validatorProvider ?? GetValidatorProvider(); var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var bindingContext = new ModelBindingContext { FallbackToEmptyPrefix = true, ModelMetadata = metadataProvider.GetMetadataForType(type), + ModelName = "parameter", ModelState = new ModelStateDictionary(), ValueProvider = valueProvider, OperationBindingContext = new OperationBindingContext { MetadataProvider = metadataProvider, ModelBinder = binder, - ValidatorProvider = validatorProvider } }; return bindingContext; @@ -547,26 +526,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test return shimBinder; } - private static IModelValidatorProvider GetValidatorProvider(params IModelValidator[] validators) - { - var provider = new Mock(); - provider - .Setup(v => v.GetValidators(It.IsAny())) - .Callback(c => - { - if (validators == null) - { - return; - } - - foreach (var validator in validators) - { - c.Validators.Add(validator); - } - }); - - return provider.Object; - } private class SimplePropertiesModel { diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/DictionaryModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/DictionaryModelBinderTest.cs index 14afbb6e9f..bdabc7ae90 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/DictionaryModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/DictionaryModelBinderTest.cs @@ -429,6 +429,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { var modelBindingContext = new ModelBindingContext() { + ModelState = new ModelStateDictionary(), OperationBindingContext = new OperationBindingContext() { HttpContext = new DefaultHttpContext(), @@ -510,6 +511,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { ModelMetadata = metadataProvider.GetMetadataForType(typeof(IDictionary)), ModelName = "someName", + ModelState = new ModelStateDictionary(), OperationBindingContext = new OperationBindingContext { ModelBinder = binder.Object, diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/FormFileModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/FormFileModelBinderTest.cs index 29fb58d72c..135b8388fe 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/FormFileModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/FormFileModelBinderTest.cs @@ -159,6 +159,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding { ModelMetadata = metadataProvider.GetMetadataForType(modelType), ModelName = "file", + ModelState = new ModelStateDictionary(), OperationBindingContext = new OperationBindingContext { ModelBinder = new FormFileModelBinder(), diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/HeaderModelBinderTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/HeaderModelBinderTests.cs index 3706737c70..6fa2f45d63 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/HeaderModelBinderTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/HeaderModelBinderTests.cs @@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new HeaderModelBinder(); var modelBindingContext = GetBindingContext(type); - modelBindingContext.ModelName = header; + modelBindingContext.FieldName = header; modelBindingContext.OperationBindingContext.HttpContext.Request.Headers.Add(header, new[] { headerValue }); // Act @@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new HeaderModelBinder(); var modelBindingContext = GetBindingContext(type); - modelBindingContext.ModelName = header; + modelBindingContext.FieldName = header; modelBindingContext.OperationBindingContext.HttpContext.Request.Headers.Add(header, new[] { headerValue }); // Act @@ -81,6 +81,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { ModelMetadata = modelMetadata, ModelName = "modelName", + FieldName = "modelName", + ModelState = new ModelStateDictionary(), OperationBindingContext = new OperationBindingContext { ModelBinder = new HeaderModelBinder(), diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/KeyValuePairModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/KeyValuePairModelBinderTest.cs index 7f70c3bdc8..5935dd4009 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/KeyValuePairModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/KeyValuePairModelBinderTest.cs @@ -255,6 +255,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { ModelMetadata = metataProvider.GetMetadataForType(keyValuePairType ?? typeof(KeyValuePair)), ModelName = "someName", + ModelState = new ModelStateDictionary(), ValueProvider = valueProvider, OperationBindingContext = new OperationBindingContext { diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ModelBindingContextTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ModelBindingContextTest.cs index e12e8aac16..cebc30f69a 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ModelBindingContextTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ModelBindingContextTest.cs @@ -10,14 +10,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test public class ModelBindingContextTest { [Fact] - public void GetChildModelBindingContext() + public void CreateChildBindingContext_CopiesProperties() { // Arrange var originalBindingContext = new ModelBindingContext { + Model = new object(), ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)), ModelName = "theName", - ModelState = new ModelStateDictionary(), + OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider() }; @@ -32,19 +33,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var newModelMetadata = metadataProvider.GetMetadataForType(typeof(object)); // Act - var newBindingContext = ModelBindingContext.GetChildModelBindingContext( + var newBindingContext = ModelBindingContext.CreateChildBindingContext( originalBindingContext, - string.Empty, - newModelMetadata); + newModelMetadata, + fieldName: "fieldName", + modelName: "modelprefix.fieldName", + model: null); // Assert - Assert.Same(newModelMetadata, newBindingContext.ModelMetadata); - Assert.Same(newModelMetadata.BindingSource, newBindingContext.BindingSource); Assert.Same(newModelMetadata.BinderModelName, newBindingContext.BinderModelName); Assert.Same(newModelMetadata.BinderType, newBindingContext.BinderType); - Assert.Equal("", newBindingContext.ModelName); - Assert.Equal(originalBindingContext.ModelState, newBindingContext.ModelState); - Assert.Equal(originalBindingContext.ValueProvider, newBindingContext.ValueProvider); + Assert.Same(newModelMetadata.BindingSource, newBindingContext.BindingSource); + Assert.False(newBindingContext.FallbackToEmptyPrefix); + Assert.Equal("fieldName", newBindingContext.FieldName); + Assert.False(newBindingContext.IsFirstChanceBinding); + Assert.False(newBindingContext.IsTopLevelObject); + Assert.Null(newBindingContext.Model); + Assert.Same(newModelMetadata, newBindingContext.ModelMetadata); + Assert.Equal("modelprefix.fieldName", newBindingContext.ModelName); + Assert.Same(originalBindingContext.ModelState, newBindingContext.ModelState); + Assert.Same(originalBindingContext.OperationBindingContext, newBindingContext.OperationBindingContext); + Assert.Same(originalBindingContext.ValueProvider, newBindingContext.ValueProvider); } [Fact] diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/MutableObjectModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/MutableObjectModelBinderTest.cs index 324286d243..5f5e9c9453 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/MutableObjectModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/MutableObjectModelBinderTest.cs @@ -796,6 +796,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding Model = model, ModelMetadata = containerMetadata, ModelName = "theModel", + ModelState = new ModelStateDictionary(), OperationBindingContext = new OperationBindingContext { MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(), @@ -846,6 +847,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding Model = model, ModelMetadata = containerMetadata, ModelName = "theModel", + ModelState = new ModelStateDictionary(), OperationBindingContext = new OperationBindingContext { MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(), @@ -1649,9 +1651,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return new ModelBindingContext { Model = model, - ModelState = new ModelStateDictionary(), ModelMetadata = metadata, ModelName = "theModel", + ModelState = new ModelStateDictionary(), OperationBindingContext = new OperationBindingContext { MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(), diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/SimpleTypeModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/SimpleTypeModelBinderTest.cs index bd210613c3..c0dab16541 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/SimpleTypeModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/SimpleTypeModelBinderTest.cs @@ -185,6 +185,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(modelType), ModelName = "theModelName", + ModelState = new ModelStateDictionary(), ValueProvider = new SimpleValueProvider() // empty }; }