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.
This commit is contained in:
Ryan Nowak 2015-08-26 18:00:40 -07:00
parent e0e2ff6825
commit dadee80aa8
20 changed files with 179 additions and 239 deletions

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.Framework.Internal; using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.ModelBinding namespace Microsoft.AspNet.Mvc.ModelBinding
@ -15,10 +14,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
private static readonly Func<ModelBindingContext, string, bool> private static readonly Func<ModelBindingContext, string, bool>
_defaultPropertyFilter = (context, propertyName) => true; _defaultPropertyFilter = (context, propertyName) => true;
private string _modelName;
private ModelStateDictionary _modelState;
private Func<ModelBindingContext, string, bool> _propertyFilter;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ModelBindingContext"/> class. /// Initializes a new instance of the <see cref="ModelBindingContext"/> class.
/// </summary> /// </summary>
@ -27,67 +22,82 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
} }
/// <summary> /// <summary>
/// Constructs a new instance of the <see cref="ModelBindingContext"/> class using the /// Creates a new <see cref="ModelBindingContext"/> for top-level model binding operation.
/// <paramref name="bindingContext" />.
/// </summary> /// </summary>
/// <param name="bindingContext">Existing <see cref="ModelBindingContext"/>.</param> /// <param name="operationBindingContext">
/// <param name="modelName">Model name of associated with the new <see cref="ModelBindingContext"/>.</param> /// The <see cref="OperationBindingContext"/> associated with the binding operation.
/// <param name="modelMetadata">Model metadata of associated with the new <see cref="ModelBindingContext"/>.
/// </param> /// </param>
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;
}
/// <summary>
/// Constructs a new instance of <see cref="ModelBindingContext"/> from given <paramref name="metadata"/>
/// and <paramref name="bindingInfo"/>.
/// </summary>
/// <param name="metadata"><see cref="ModelMetadata"/> associated with the model.</param> /// <param name="metadata"><see cref="ModelMetadata"/> associated with the model.</param>
/// <param name="bindingInfo"><see cref="BindingInfo"/> associated with the model.</param> /// <param name="bindingInfo"><see cref="BindingInfo"/> associated with the model.</param>
/// <param name="modelName">An optional name of the model to be used.</param> /// <param name="modelName">The name of the property or parameter being bound.</param>
/// <returns>A new instance of <see cref="ModelBindingContext"/>.</returns> /// <returns>A new instance of <see cref="ModelBindingContext"/>.</returns>
public static ModelBindingContext GetModelBindingContext( public static ModelBindingContext CreateBindingContext(
[NotNull] OperationBindingContext operationBindingContext,
[NotNull] ModelStateDictionary modelState,
[NotNull] ModelMetadata metadata, [NotNull] ModelMetadata metadata,
BindingInfo bindingInfo, BindingInfo bindingInfo,
string modelName) [NotNull] string modelName)
{ {
var binderModelName = bindingInfo?.BinderModelName ?? metadata.BinderModelName; var binderModelName = bindingInfo?.BinderModelName ?? metadata.BinderModelName;
var propertyPredicateProvider = var propertyPredicateProvider =
bindingInfo?.PropertyBindingPredicateProvider ?? metadata.PropertyBindingPredicateProvider; 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, 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, 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,
}; };
} }
/// <summary> /// <summary>
/// Represents the <see cref="OperationBindingContext"/> associated with this context. /// Represents the <see cref="OperationBindingContext"/> associated with this context.
/// </summary> /// </summary>
public OperationBindingContext OperationBindingContext { get; set; } public OperationBindingContext OperationBindingContext { get; [param:NotNull] set; }
/// <summary>
/// Gets or sets the name of the current field being bound.
/// </summary>
public string FieldName { get; [param: NotNull] set; }
/// <summary> /// <summary>
/// Gets or sets the model value for the current operation. /// Gets or sets the model value for the current operation.
@ -101,41 +111,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// <summary> /// <summary>
/// Gets or sets the metadata for the model associated with this context. /// Gets or sets the metadata for the model associated with this context.
/// </summary> /// </summary>
public ModelMetadata ModelMetadata { get; set; } public ModelMetadata ModelMetadata { get; [param: NotNull] set; }
/// <summary> /// <summary>
/// Gets or sets the name of the model. This property is used as a key for looking up values in /// Gets or sets the name of the model. This property is used as a key for looking up values in
/// <see cref="IValueProvider"/> during model binding. /// <see cref="IValueProvider"/> during model binding.
/// </summary> /// </summary>
public string ModelName public string ModelName { get; [param: NotNull] set; }
{
get
{
if (_modelName == null)
{
_modelName = string.Empty;
}
return _modelName;
}
set { _modelName = value; }
}
/// <summary> /// <summary>
/// Gets or sets the <see cref="ModelStateDictionary"/> used to capture <see cref="ModelState"/> values /// Gets or sets the <see cref="ModelStateDictionary"/> used to capture <see cref="ModelState"/> values
/// for properties in the object graph of the model when binding. /// for properties in the object graph of the model when binding.
/// </summary> /// </summary>
public ModelStateDictionary ModelState public ModelStateDictionary ModelState { get; [param: NotNull] set; }
{
get
{
if (_modelState == null)
{
_modelState = new ModelStateDictionary();
}
return _modelState;
}
set { _modelState = value; }
}
/// <summary> /// <summary>
/// Gets the type of the model. /// Gets the type of the model.
@ -143,14 +131,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// <remarks> /// <remarks>
/// The <see cref="ModelMetadata"/> property must be set to access this property. /// The <see cref="ModelMetadata"/> property must be set to access this property.
/// </remarks> /// </remarks>
public Type ModelType public Type ModelType => ModelMetadata?.ModelType;
{
get
{
EnsureModelMetadata();
return ModelMetadata.ModelType;
}
}
/// <summary> /// <summary>
/// Gets or sets a model name which is explicitly set using an <see cref="IModelNameProvider"/>. /// Gets or sets a model name which is explicitly set using an <see cref="IModelNameProvider"/>.
@ -202,27 +183,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// <summary> /// <summary>
/// Gets or sets the <see cref="IValueProvider"/> associated with this context. /// Gets or sets the <see cref="IValueProvider"/> associated with this context.
/// </summary> /// </summary>
public IValueProvider ValueProvider { get; set; } public IValueProvider ValueProvider { get; [param: NotNull] set; }
public Func<ModelBindingContext, string, bool> PropertyFilter /// <summary>
{ /// Gets or sets a predicate which will be evaluated for each property to determine if the property
get /// is eligible for model binding.
{ /// </summary>
if (_propertyFilter == null) public Func<ModelBindingContext, string, bool> PropertyFilter { get; set; }
{
_propertyFilter = _defaultPropertyFilter;
}
return _propertyFilter;
}
set { _propertyFilter = value; }
}
private void EnsureModelMetadata()
{
if (ModelMetadata == null)
{
throw new InvalidOperationException(Resources.ModelBindingContext_ModelMetadataMustBeSet);
}
}
} }
} }

View File

@ -73,12 +73,12 @@ namespace Microsoft.AspNet.Mvc
[NotNull] OperationBindingContext operationContext) [NotNull] OperationBindingContext operationContext)
{ {
var metadata = _modelMetadataProvider.GetMetadataForType(parameter.ParameterType); var metadata = _modelMetadataProvider.GetMetadataForType(parameter.ParameterType);
var modelBindingContext = GetModelBindingContext( var modelBindingContext = ModelBindingContext.CreateBindingContext(
parameter.Name, operationContext,
modelState,
metadata, metadata,
parameter.BindingInfo, parameter.BindingInfo,
modelState, parameter.Name);
operationContext);
var modelBindingResult = await operationContext.ModelBinder.BindModelAsync(modelBindingContext); var modelBindingResult = await operationContext.ModelBinder.BindModelAsync(modelBindingContext);
if (modelBindingResult != null && 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( private OperationBindingContext GetOperationBindingContext(
ActionContext actionContext, ActionContext actionContext,
ActionBindingContext bindingContext) ActionBindingContext bindingContext)

View File

@ -149,12 +149,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
bindingContext.ModelName, bindingContext.ModelName,
bindingContext.ModelMetadata, bindingContext.ModelMetadata,
boundCollection); boundCollection);
var innerBindingContext = ModelBindingContext.CreateChildBindingContext(
bindingContext,
elementMetadata,
fieldName: bindingContext.FieldName,
modelName: bindingContext.ModelName,
model: null);
foreach (var value in values) foreach (var value in values)
{ {
var innerBindingContext = ModelBindingContext.GetChildModelBindingContext(
bindingContext,
bindingContext.ModelName,
elementMetadata);
innerBindingContext.ValueProvider = new CompositeValueProvider innerBindingContext.ValueProvider = new CompositeValueProvider
{ {
// our temporary provider goes at the front of the list // our temporary provider goes at the front of the list
@ -222,10 +226,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
foreach (var indexName in indexNames) foreach (var indexName in indexNames)
{ {
var fullChildName = ModelNames.CreateIndexModelName(bindingContext.ModelName, indexName); var fullChildName = ModelNames.CreateIndexModelName(bindingContext.ModelName, indexName);
var childBindingContext = ModelBindingContext.GetChildModelBindingContext( var childBindingContext = ModelBindingContext.CreateChildBindingContext(
bindingContext, bindingContext,
fullChildName, elementMetadata,
elementMetadata); fieldName: indexName,
modelName: fullChildName,
model: null);
var didBind = false; var didBind = false;
object boundValue = null; object boundValue = null;

View File

@ -148,6 +148,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
Model = oldBindingContext.Model, Model = oldBindingContext.Model,
ModelMetadata = oldBindingContext.ModelMetadata, ModelMetadata = oldBindingContext.ModelMetadata,
ModelName = modelName, ModelName = modelName,
FieldName = oldBindingContext.FieldName,
ModelState = oldBindingContext.ModelState, ModelState = oldBindingContext.ModelState,
ValueProvider = oldBindingContext.ValueProvider, ValueProvider = oldBindingContext.ValueProvider,
OperationBindingContext = oldBindingContext.OperationBindingContext, OperationBindingContext = oldBindingContext.OperationBindingContext,

View File

@ -57,10 +57,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Update the existing successful but empty ModelBindingResult. // Update the existing successful but empty ModelBindingResult.
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider; var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
var valueMetadata = metadataProvider.GetMetadataForType(typeof(TValue)); var valueMetadata = metadataProvider.GetMetadataForType(typeof(TValue));
var valueBindingContext = ModelBindingContext.GetChildModelBindingContext( var valueBindingContext = ModelBindingContext.CreateChildBindingContext(
bindingContext, bindingContext,
bindingContext.ModelName, valueMetadata,
valueMetadata); fieldName: bindingContext.FieldName,
modelName: bindingContext.ModelName,
model: null);
var modelBinder = bindingContext.OperationBindingContext.ModelBinder; var modelBinder = bindingContext.OperationBindingContext.ModelBinder;
var validationNode = result.ValidationNode; var validationNode = result.ValidationNode;

View File

@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var modelMetadata = bindingContext.ModelMetadata; var modelMetadata = bindingContext.ModelMetadata;
// Property name can be null if the model metadata represents a type (rather than a property or parameter). // 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; object model = null;
if (bindingContext.ModelType == typeof(string)) if (bindingContext.ModelType == typeof(string))
{ {

View File

@ -93,11 +93,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
parentBindingContext.OperationBindingContext.MetadataProvider.GetMetadataForType(typeof(TModel)); parentBindingContext.OperationBindingContext.MetadataProvider.GetMetadataForType(typeof(TModel));
var propertyModelName = var propertyModelName =
ModelNames.CreatePropertyModelName(parentBindingContext.ModelName, propertyName); ModelNames.CreatePropertyModelName(parentBindingContext.ModelName, propertyName);
var propertyBindingContext = ModelBindingContext.GetChildModelBindingContext( var propertyBindingContext = ModelBindingContext.CreateChildBindingContext(
parentBindingContext, parentBindingContext,
propertyModelMetadata,
propertyName,
propertyModelName, propertyModelName,
propertyModelMetadata); model: null);
propertyBindingContext.BinderModelName = propertyModelMetadata.BinderModelName;
var modelBindingResult = await propertyBindingContext.OperationBindingContext.ModelBinder.BindModelAsync( var modelBindingResult = await propertyBindingContext.OperationBindingContext.ModelBinder.BindModelAsync(
propertyBindingContext); propertyBindingContext);

View File

@ -160,14 +160,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
isAnyPropertyEnabledForValueProviderBasedBinding = true; isAnyPropertyEnabledForValueProviderBasedBinding = true;
var propertyModelName = ModelNames.CreatePropertyModelName( var fieldName = propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName;
var modelName = ModelNames.CreatePropertyModelName(
context.ModelBindingContext.ModelName, context.ModelBindingContext.ModelName,
propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName); fieldName);
var propertyModelBindingContext = ModelBindingContext.GetChildModelBindingContext( var propertyModelBindingContext = ModelBindingContext.CreateChildBindingContext(
context.ModelBindingContext, context.ModelBindingContext,
propertyModelName, propertyMetadata,
propertyMetadata); fieldName: fieldName,
modelName: modelName,
model: null);
// If any property can return a true value. // If any property can return a true value.
if (CanBindValue(propertyModelBindingContext)) if (CanBindValue(propertyModelBindingContext))
@ -274,31 +277,34 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var results = new Dictionary<ModelMetadata, ModelBindingResult>(); var results = new Dictionary<ModelMetadata, ModelBindingResult>();
foreach (var propertyMetadata in propertyMetadatas) 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 // 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 // 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 // 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 // because they will be overwritten if binding succeeds. Arrays are never reused because they cannot
// be resized. // be resized.
object model = null;
if (propertyMetadata.PropertyGetter != null && if (propertyMetadata.PropertyGetter != null &&
propertyMetadata.IsComplexType && propertyMetadata.IsComplexType &&
!propertyMetadata.ModelType.IsArray) !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) if (result == null)
{ {
// Could not bind. Let ProcessResult() know explicitly. // 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; results[propertyMetadata] = result;
@ -359,7 +365,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var modelMetadataPredicate = context.ModelMetadata.PropertyBindingPredicateProvider?.PropertyFilter; var modelMetadataPredicate = context.ModelMetadata.PropertyBindingPredicateProvider?.PropertyFilter;
return return
context.PropertyFilter(context, propertyName) && (context.PropertyFilter == null || context.PropertyFilter(context, propertyName)) &&
(modelMetadataPredicate == null || modelMetadataPredicate(context, propertyName)); (modelMetadataPredicate == null || modelMetadataPredicate(context, propertyName));
}; };
} }

View File

@ -293,21 +293,18 @@ namespace Microsoft.AspNet.Mvc
ModelBinder = modelBinder, ModelBinder = modelBinder,
ValidatorProvider = validatorProvider, ValidatorProvider = validatorProvider,
MetadataProvider = metadataProvider, MetadataProvider = metadataProvider,
HttpContext = httpContext HttpContext = httpContext,
ValueProvider = valueProvider,
}; };
var modelBindingContext = new ModelBindingContext var modelBindingContext = ModelBindingContext.CreateBindingContext(
{ operationBindingContext,
Model = model, modelState,
ModelMetadata = modelMetadata, modelMetadata,
ModelName = prefix, bindingInfo: null,
ModelState = modelState, modelName: prefix ?? string.Empty);
ValueProvider = valueProvider, modelBindingContext.Model = model;
FallbackToEmptyPrefix = true, modelBindingContext.PropertyFilter = predicate;
IsTopLevelObject = true,
OperationBindingContext = operationBindingContext,
PropertyFilter = predicate,
};
var modelBindingResult = await modelBinder.BindModelAsync(modelBindingContext); var modelBindingResult = await modelBinder.BindModelAsync(modelBindingContext);
if (modelBindingResult != null && modelBindingResult.IsModelSet) if (modelBindingResult != null && modelBindingResult.IsModelSet)

View File

@ -222,11 +222,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
ModelMetadata = modelMetadata, ModelMetadata = modelMetadata,
ModelName = "someName", ModelName = "someName",
ModelState = new ModelStateDictionary(),
ValueProvider = valueProvider, ValueProvider = valueProvider,
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {
ModelBinder = CreateIntBinder(), ModelBinder = CreateIntBinder(),
MetadataProvider = metadataProvider MetadataProvider = metadataProvider,
}, },
}; };
return bindingContext; return bindingContext;

View File

@ -129,10 +129,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
ModelMetadata = metadataProvider.GetMetadataForType(modelType), ModelMetadata = metadataProvider.GetMetadataForType(modelType),
ModelName = "foo", ModelName = "foo",
ModelState = new ModelStateDictionary(),
ValueProvider = valueProvider, ValueProvider = valueProvider,
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {
MetadataProvider = metadataProvider MetadataProvider = metadataProvider,
} }
}; };
return bindingContext; return bindingContext;

View File

@ -419,6 +419,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
ModelMetadata = metadataProvider.GetMetadataForType(typeof(IList<int>)), ModelMetadata = metadataProvider.GetMetadataForType(typeof(IList<int>)),
ModelName = "someName", ModelName = "someName",
ModelState = new ModelStateDictionary(),
ValueProvider = valueProvider, ValueProvider = valueProvider,
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {

View File

@ -24,14 +24,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int)), ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int)),
ModelName = "someName", ModelName = "someName",
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext(),
ValueProvider = new SimpleValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someName", "dummyValue" } { "someName", "dummyValue" }
}, },
OperationBindingContext = new OperationBindingContext
{
ValidatorProvider = GetValidatorProvider()
}
}; };
var mockIntBinder = new Mock<IModelBinder>(); var mockIntBinder = new Mock<IModelBinder>();
@ -71,14 +68,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)), ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)),
ModelName = "someName", ModelName = "someName",
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext(),
ValueProvider = new SimpleValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
OperationBindingContext = new OperationBindingContext
{
ValidatorProvider = GetValidatorProvider()
}
}; };
var mockIntBinder = new Mock<IModelBinder>(); var mockIntBinder = new Mock<IModelBinder>();
@ -121,14 +115,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)), ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)),
ModelName = "someName", ModelName = "someName",
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext(),
ValueProvider = new SimpleValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
OperationBindingContext = new OperationBindingContext
{
ValidatorProvider = GetValidatorProvider()
}
}; };
var modelBinder = new Mock<IModelBinder>(); var modelBinder = new Mock<IModelBinder>();
@ -155,14 +146,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)), ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)),
ModelName = "someName", ModelName = "someName",
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext(),
ValueProvider = new SimpleValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
OperationBindingContext = new OperationBindingContext
{
ValidatorProvider = GetValidatorProvider()
}
}; };
var count = 0; var count = 0;
@ -201,14 +189,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)), ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)),
ModelName = "someName", ModelName = "someName",
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext(),
ValueProvider = new SimpleValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
OperationBindingContext = new OperationBindingContext
{
ValidatorProvider = GetValidatorProvider()
}
}; };
var modelBinder = new Mock<IModelBinder>(); var modelBinder = new Mock<IModelBinder>();
@ -238,14 +223,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)), ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)),
ModelName = "someName", ModelName = "someName",
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext(),
ValueProvider = new SimpleValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
OperationBindingContext = new OperationBindingContext
{
ValidatorProvider = GetValidatorProvider()
}
}; };
var modelBinder = new Mock<IModelBinder>(); var modelBinder = new Mock<IModelBinder>();
@ -276,14 +258,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)), ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)),
ModelName = "someName", ModelName = "someName",
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext(),
ValueProvider = new SimpleValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
OperationBindingContext = new OperationBindingContext
{
ValidatorProvider = GetValidatorProvider()
}
}; };
var modelBinder = new Mock<IModelBinder>(); var modelBinder = new Mock<IModelBinder>();
@ -318,6 +297,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
FallbackToEmptyPrefix = false, FallbackToEmptyPrefix = false,
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)), ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)),
ModelState = new ModelStateDictionary(),
}; };
// Act // Act
@ -341,7 +321,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
FallbackToEmptyPrefix = true, FallbackToEmptyPrefix = true,
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int)), ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int)),
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
OperationBindingContext = Mock.Of<OperationBindingContext>(), OperationBindingContext = new OperationBindingContext(),
}; };
// Act // Act
@ -504,24 +484,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
Assert.Same(validationNode, result.ValidationNode); Assert.Same(validationNode, result.ValidationNode);
} }
private static ModelBindingContext CreateBindingContext(IModelBinder binder, private static ModelBindingContext CreateBindingContext(
IValueProvider valueProvider, IModelBinder binder,
Type type, IValueProvider valueProvider,
IModelValidatorProvider validatorProvider = null) Type type)
{ {
validatorProvider = validatorProvider ?? GetValidatorProvider();
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
var bindingContext = new ModelBindingContext var bindingContext = new ModelBindingContext
{ {
FallbackToEmptyPrefix = true, FallbackToEmptyPrefix = true,
ModelMetadata = metadataProvider.GetMetadataForType(type), ModelMetadata = metadataProvider.GetMetadataForType(type),
ModelName = "parameter",
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
ValueProvider = valueProvider, ValueProvider = valueProvider,
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {
MetadataProvider = metadataProvider, MetadataProvider = metadataProvider,
ModelBinder = binder, ModelBinder = binder,
ValidatorProvider = validatorProvider
} }
}; };
return bindingContext; return bindingContext;
@ -547,26 +526,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
return shimBinder; return shimBinder;
} }
private static IModelValidatorProvider GetValidatorProvider(params IModelValidator[] validators)
{
var provider = new Mock<IModelValidatorProvider>();
provider
.Setup(v => v.GetValidators(It.IsAny<ModelValidatorProviderContext>()))
.Callback<ModelValidatorProviderContext>(c =>
{
if (validators == null)
{
return;
}
foreach (var validator in validators)
{
c.Validators.Add(validator);
}
});
return provider.Object;
}
private class SimplePropertiesModel private class SimplePropertiesModel
{ {

View File

@ -429,6 +429,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
var modelBindingContext = new ModelBindingContext() var modelBindingContext = new ModelBindingContext()
{ {
ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext() OperationBindingContext = new OperationBindingContext()
{ {
HttpContext = new DefaultHttpContext(), HttpContext = new DefaultHttpContext(),
@ -510,6 +511,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
ModelMetadata = metadataProvider.GetMetadataForType(typeof(IDictionary<int, string>)), ModelMetadata = metadataProvider.GetMetadataForType(typeof(IDictionary<int, string>)),
ModelName = "someName", ModelName = "someName",
ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {
ModelBinder = binder.Object, ModelBinder = binder.Object,

View File

@ -159,6 +159,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
ModelMetadata = metadataProvider.GetMetadataForType(modelType), ModelMetadata = metadataProvider.GetMetadataForType(modelType),
ModelName = "file", ModelName = "file",
ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {
ModelBinder = new FormFileModelBinder(), ModelBinder = new FormFileModelBinder(),

View File

@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var binder = new HeaderModelBinder(); var binder = new HeaderModelBinder();
var modelBindingContext = GetBindingContext(type); var modelBindingContext = GetBindingContext(type);
modelBindingContext.ModelName = header; modelBindingContext.FieldName = header;
modelBindingContext.OperationBindingContext.HttpContext.Request.Headers.Add(header, new[] { headerValue }); modelBindingContext.OperationBindingContext.HttpContext.Request.Headers.Add(header, new[] { headerValue });
// Act // Act
@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var binder = new HeaderModelBinder(); var binder = new HeaderModelBinder();
var modelBindingContext = GetBindingContext(type); var modelBindingContext = GetBindingContext(type);
modelBindingContext.ModelName = header; modelBindingContext.FieldName = header;
modelBindingContext.OperationBindingContext.HttpContext.Request.Headers.Add(header, new[] { headerValue }); modelBindingContext.OperationBindingContext.HttpContext.Request.Headers.Add(header, new[] { headerValue });
// Act // Act
@ -81,6 +81,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
ModelMetadata = modelMetadata, ModelMetadata = modelMetadata,
ModelName = "modelName", ModelName = "modelName",
FieldName = "modelName",
ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {
ModelBinder = new HeaderModelBinder(), ModelBinder = new HeaderModelBinder(),

View File

@ -255,6 +255,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
ModelMetadata = metataProvider.GetMetadataForType(keyValuePairType ?? typeof(KeyValuePair<int, string>)), ModelMetadata = metataProvider.GetMetadataForType(keyValuePairType ?? typeof(KeyValuePair<int, string>)),
ModelName = "someName", ModelName = "someName",
ModelState = new ModelStateDictionary(),
ValueProvider = valueProvider, ValueProvider = valueProvider,
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {

View File

@ -10,14 +10,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public class ModelBindingContextTest public class ModelBindingContextTest
{ {
[Fact] [Fact]
public void GetChildModelBindingContext() public void CreateChildBindingContext_CopiesProperties()
{ {
// Arrange // Arrange
var originalBindingContext = new ModelBindingContext var originalBindingContext = new ModelBindingContext
{ {
Model = new object(),
ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)), ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)),
ModelName = "theName", ModelName = "theName",
ModelState = new ModelStateDictionary(), OperationBindingContext = new OperationBindingContext(),
ValueProvider = new SimpleValueProvider() ValueProvider = new SimpleValueProvider()
}; };
@ -32,19 +33,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var newModelMetadata = metadataProvider.GetMetadataForType(typeof(object)); var newModelMetadata = metadataProvider.GetMetadataForType(typeof(object));
// Act // Act
var newBindingContext = ModelBindingContext.GetChildModelBindingContext( var newBindingContext = ModelBindingContext.CreateChildBindingContext(
originalBindingContext, originalBindingContext,
string.Empty, newModelMetadata,
newModelMetadata); fieldName: "fieldName",
modelName: "modelprefix.fieldName",
model: null);
// Assert // Assert
Assert.Same(newModelMetadata, newBindingContext.ModelMetadata);
Assert.Same(newModelMetadata.BindingSource, newBindingContext.BindingSource);
Assert.Same(newModelMetadata.BinderModelName, newBindingContext.BinderModelName); Assert.Same(newModelMetadata.BinderModelName, newBindingContext.BinderModelName);
Assert.Same(newModelMetadata.BinderType, newBindingContext.BinderType); Assert.Same(newModelMetadata.BinderType, newBindingContext.BinderType);
Assert.Equal("", newBindingContext.ModelName); Assert.Same(newModelMetadata.BindingSource, newBindingContext.BindingSource);
Assert.Equal(originalBindingContext.ModelState, newBindingContext.ModelState); Assert.False(newBindingContext.FallbackToEmptyPrefix);
Assert.Equal(originalBindingContext.ValueProvider, newBindingContext.ValueProvider); 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] [Fact]

View File

@ -796,6 +796,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
Model = model, Model = model,
ModelMetadata = containerMetadata, ModelMetadata = containerMetadata,
ModelName = "theModel", ModelName = "theModel",
ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {
MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(), MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
@ -846,6 +847,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
Model = model, Model = model,
ModelMetadata = containerMetadata, ModelMetadata = containerMetadata,
ModelName = "theModel", ModelName = "theModel",
ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {
MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(), MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
@ -1649,9 +1651,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return new ModelBindingContext return new ModelBindingContext
{ {
Model = model, Model = model,
ModelState = new ModelStateDictionary(),
ModelMetadata = metadata, ModelMetadata = metadata,
ModelName = "theModel", ModelName = "theModel",
ModelState = new ModelStateDictionary(),
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {
MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(), MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),

View File

@ -185,6 +185,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(modelType), ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(modelType),
ModelName = "theModelName", ModelName = "theModelName",
ModelState = new ModelStateDictionary(),
ValueProvider = new SimpleValueProvider() // empty ValueProvider = new SimpleValueProvider() // empty
}; };
} }