Support user overrides of system-provided `ModelError` messages
- #2969 - add `ModelBindingMessages` for configuration and `IBindingMetadataProvider` overrides - use `interface` to avoid `new` oddities when adding a setter to an `abstract` property - add `IModelBindingMessages` to `ModelMetadata` for use in rest of the product code - plumb the various bits through the system - add integration tests using a custom `IBindingMetadataProvider`s to override messages nits: - remove unused resources - use `AttemptedValue` and not `model` in `SimpleTypeModelBinder`
This commit is contained in:
parent
0d6edf240a
commit
28aec3f5cc
|
|
@ -0,0 +1,34 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provider for error messages the model binding system detects.
|
||||||
|
/// </summary>
|
||||||
|
public interface IModelBindingMessageProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Error message the model binding system adds when a property with an associated
|
||||||
|
/// <c>BindRequiredAttribute</c> is not bound.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>Default <see cref="string"/> is "A value for the '{0}' property was not provided.".</value>
|
||||||
|
Func<string, string> MissingBindRequiredValueAccessor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error message the model binding system adds when either the key or the value of a
|
||||||
|
/// <see cref="System.Collections.Generic.KeyValuePair{TKey, TValue}"/> is bound but not both.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>Default <see cref="string"/> is "A value is required.".</value>
|
||||||
|
Func<string> MissingKeyOrValueAccessor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error message the model binding system adds when a <c>null</c> value is bound to a
|
||||||
|
/// non-<see cref="Nullable"/> property.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>Default <see cref="string"/> is "The value '{0}' is invalid.".</value>
|
||||||
|
Func<string, string> ValueMustNotBeNullAccessor { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -242,6 +242,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public abstract bool IsRequired { get; }
|
public abstract bool IsRequired { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="IModelBindingMessageProvider"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
public abstract IModelBindingMessageProvider ModelBindingMessageProvider { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating where the current metadata should be ordered relative to other properties
|
/// Gets a value indicating where the current metadata should be ordered relative to other properties
|
||||||
/// in its containing type.
|
/// in its containing type.
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.AspNet.Mvc.Formatters;
|
using Microsoft.AspNet.Mvc.Formatters;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||||
|
|
@ -23,6 +24,12 @@ namespace Microsoft.AspNet.Mvc.Internal
|
||||||
|
|
||||||
public static void ConfigureMvc(MvcOptions options)
|
public static void ConfigureMvc(MvcOptions options)
|
||||||
{
|
{
|
||||||
|
// Set up default error messages
|
||||||
|
var messageProvider = options.ModelBindingMessageProvider;
|
||||||
|
messageProvider.MissingBindRequiredValueAccessor = Resources.FormatModelBinding_MissingBindRequiredMember;
|
||||||
|
messageProvider.MissingKeyOrValueAccessor = Resources.FormatKeyValuePair_BothKeyAndValueMustBePresent;
|
||||||
|
messageProvider.ValueMustNotBeNullAccessor = Resources.FormatModelBinding_NullValueNotValid;
|
||||||
|
|
||||||
// Set up ModelBinding
|
// Set up ModelBinding
|
||||||
options.ModelBinders.Add(new BinderTypeBasedModelBinder());
|
options.ModelBinders.Add(new BinderTypeBasedModelBinder());
|
||||||
options.ModelBinders.Add(new ServicesModelBinder());
|
options.ModelBinders.Add(new ServicesModelBinder());
|
||||||
|
|
@ -48,7 +55,7 @@ namespace Microsoft.AspNet.Mvc.Internal
|
||||||
options.ValueProviderFactories.Add(new JQueryFormValueProviderFactory());
|
options.ValueProviderFactories.Add(new JQueryFormValueProviderFactory());
|
||||||
|
|
||||||
// Set up metadata providers
|
// Set up metadata providers
|
||||||
options.ModelMetadataDetailsProviders.Add(new DefaultBindingMetadataProvider());
|
options.ModelMetadataDetailsProviders.Add(new DefaultBindingMetadataProvider(messageProvider));
|
||||||
options.ModelMetadataDetailsProviders.Add(new DefaultValidationMetadataProvider());
|
options.ModelMetadataDetailsProviders.Add(new DefaultValidationMetadataProvider());
|
||||||
|
|
||||||
// Set up validators
|
// Set up validators
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
@ -7,8 +9,33 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public class EmptyModelMetadataProvider : DefaultModelMetadataProvider
|
public class EmptyModelMetadataProvider : DefaultModelMetadataProvider
|
||||||
{
|
{
|
||||||
public EmptyModelMetadataProvider()
|
public EmptyModelMetadataProvider()
|
||||||
: base(new DefaultCompositeMetadataDetailsProvider(new IMetadataDetailsProvider[0]))
|
: base(new DefaultCompositeMetadataDetailsProvider(new IMetadataDetailsProvider[]
|
||||||
|
{
|
||||||
|
new MessageOnlyBindingProvider()
|
||||||
|
}))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class MessageOnlyBindingProvider : IBindingMetadataProvider
|
||||||
|
{
|
||||||
|
private readonly ModelBindingMessageProvider _messageProvider = CreateMessageProvider();
|
||||||
|
|
||||||
|
public void GetBindingMetadata(BindingMetadataProviderContext context)
|
||||||
|
{
|
||||||
|
// Don't bother with ModelBindingMessageProvider copy constructor. No other provider can change the
|
||||||
|
// delegates.
|
||||||
|
context.BindingMetadata.ModelBindingMessageProvider = _messageProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ModelBindingMessageProvider CreateMessageProvider()
|
||||||
|
{
|
||||||
|
return new ModelBindingMessageProvider
|
||||||
|
{
|
||||||
|
MissingBindRequiredValueAccessor = Resources.FormatModelBinding_MissingBindRequiredMember,
|
||||||
|
MissingKeyOrValueAccessor = Resources.FormatKeyValuePair_BothKeyAndValueMustBePresent,
|
||||||
|
ValueMustNotBeNullAccessor = Resources.FormatModelBinding_NullValueNotValid,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
|
|
@ -30,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
bindingContext.ModelState.TryAddModelError(
|
bindingContext.ModelState.TryAddModelError(
|
||||||
keyResult.Key,
|
keyResult.Key,
|
||||||
Resources.KeyValuePair_BothKeyAndValueMustBePresent);
|
bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingKeyOrValueAccessor());
|
||||||
|
|
||||||
// Were able to get some data for this model.
|
// Were able to get some data for this model.
|
||||||
// Always tell the model binding system to skip other model binders.
|
// Always tell the model binding system to skip other model binders.
|
||||||
|
|
@ -40,7 +39,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
bindingContext.ModelState.TryAddModelError(
|
bindingContext.ModelState.TryAddModelError(
|
||||||
valueResult.Key,
|
valueResult.Key,
|
||||||
Resources.KeyValuePair_BothKeyAndValueMustBePresent);
|
bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingKeyOrValueAccessor());
|
||||||
|
|
||||||
// Were able to get some data for this model.
|
// Were able to get some data for this model.
|
||||||
// Always tell the model binding system to skip other model binders.
|
// Always tell the model binding system to skip other model binders.
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BindingMetadata
|
public class BindingMetadata
|
||||||
{
|
{
|
||||||
|
private ModelBindingMessageProvider _messageProvider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="ModelBinding.BindingSource"/>.
|
/// Gets or sets the <see cref="ModelBinding.BindingSource"/>.
|
||||||
/// See <see cref="ModelMetadata.BindingSource"/>.
|
/// See <see cref="ModelMetadata.BindingSource"/>.
|
||||||
|
|
@ -50,6 +52,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? IsReadOnly { get; set; }
|
public bool? IsReadOnly { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Metadata.ModelBindingMessageProvider"/> instance. See
|
||||||
|
/// <see cref="ModelMetadata.ModelBindingMessageProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
public ModelBindingMessageProvider ModelBindingMessageProvider
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _messageProvider;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_messageProvider = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="ModelBinding.IPropertyBindingPredicateProvider"/>.
|
/// Gets or sets the <see cref="ModelBinding.IPropertyBindingPredicateProvider"/>.
|
||||||
/// See <see cref="ModelMetadata.PropertyBindingPredicateProvider"/>.
|
/// See <see cref="ModelMetadata.PropertyBindingPredicateProvider"/>.
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DefaultBindingMetadataProvider : IBindingMetadataProvider
|
public class DefaultBindingMetadataProvider : IBindingMetadataProvider
|
||||||
{
|
{
|
||||||
|
private readonly ModelBindingMessageProvider _messageProvider;
|
||||||
|
|
||||||
|
public DefaultBindingMetadataProvider(ModelBindingMessageProvider messageProvider)
|
||||||
|
{
|
||||||
|
if (messageProvider == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(messageProvider));
|
||||||
|
}
|
||||||
|
|
||||||
|
_messageProvider = messageProvider;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void GetBindingMetadata([NotNull] BindingMetadataProviderContext context)
|
public void GetBindingMetadata([NotNull] BindingMetadataProviderContext context)
|
||||||
{
|
{
|
||||||
|
|
@ -47,6 +59,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ModelBindingMessageProvider
|
||||||
|
// Provide a unique instance based on one passed to the constructor.
|
||||||
|
context.BindingMetadata.ModelBindingMessageProvider = new ModelBindingMessageProvider(_messageProvider);
|
||||||
|
|
||||||
// PropertyBindingPredicateProvider
|
// PropertyBindingPredicateProvider
|
||||||
var predicateProviders = context.Attributes.OfType<IPropertyBindingPredicateProvider>().ToArray();
|
var predicateProviders = context.Attributes.OfType<IPropertyBindingPredicateProvider>().ToArray();
|
||||||
if (predicateProviders.Length > 0)
|
if (predicateProviders.Length > 0)
|
||||||
|
|
@ -62,7 +78,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
var bindingBehavior = context.PropertyAttributes.OfType<BindingBehaviorAttribute>().FirstOrDefault();
|
var bindingBehavior = context.PropertyAttributes.OfType<BindingBehaviorAttribute>().FirstOrDefault();
|
||||||
if (bindingBehavior == null)
|
if (bindingBehavior == null)
|
||||||
{
|
{
|
||||||
bindingBehavior =
|
bindingBehavior =
|
||||||
context.Key.ContainerType.GetTypeInfo()
|
context.Key.ContainerType.GetTypeInfo()
|
||||||
.GetCustomAttributes(typeof(BindingBehaviorAttribute), inherit: true)
|
.GetCustomAttributes(typeof(BindingBehaviorAttribute), inherit: true)
|
||||||
.OfType<BindingBehaviorAttribute>()
|
.OfType<BindingBehaviorAttribute>()
|
||||||
|
|
|
||||||
|
|
@ -418,6 +418,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override IModelBindingMessageProvider ModelBindingMessageProvider
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BindingMetadata.ModelBindingMessageProvider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string NullDisplayText
|
public override string NullDisplayText
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// 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.Validation;
|
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
|
|
@ -19,8 +18,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
{
|
{
|
||||||
if (attribute is IModelValidator || attribute is IClientModelValidator)
|
if (attribute is IModelValidator || attribute is IClientModelValidator)
|
||||||
{
|
{
|
||||||
// If another provider has already added this attribute, do not repeat it.
|
// If another provider has already added this attribute, do not repeat it.
|
||||||
// This will prevent attributes like RemoteAttribute (which implement ValidationAttribute and
|
// This will prevent attributes like RemoteAttribute (which implement ValidationAttribute and
|
||||||
// IClientModelValidator) to be added to the ValidationMetadata twice.
|
// IClientModelValidator) to be added to the ValidationMetadata twice.
|
||||||
// This is to ensure we do not end up with duplication validation rules on the client side.
|
// This is to ensure we do not end up with duplication validation rules on the client side.
|
||||||
if (!context.ValidationMetadata.ValidatorMetadata.Contains(attribute))
|
if (!context.ValidationMetadata.ValidatorMetadata.Contains(attribute))
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Read / write <see cref="IModelBindingMessageProvider"/> implementation.
|
||||||
|
/// </summary>
|
||||||
|
public class ModelBindingMessageProvider : IModelBindingMessageProvider
|
||||||
|
{
|
||||||
|
private Func<string, string> _missingBindRequiredValueAccessor;
|
||||||
|
private Func<string> _missingKeyOrValueAccessor;
|
||||||
|
private Func<string, string> _valueMustNotBeNullAccessor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ModelBindingMessageProvider"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public ModelBindingMessageProvider()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ModelBindingMessageProvider"/> class based on
|
||||||
|
/// <paramref name="originalProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="originalProvider">The <see cref="ModelBindingMessageProvider"/> to duplicate.</param>
|
||||||
|
public ModelBindingMessageProvider(ModelBindingMessageProvider originalProvider)
|
||||||
|
{
|
||||||
|
if (originalProvider == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(originalProvider));
|
||||||
|
}
|
||||||
|
|
||||||
|
MissingBindRequiredValueAccessor = originalProvider.MissingBindRequiredValueAccessor;
|
||||||
|
MissingKeyOrValueAccessor = originalProvider.MissingKeyOrValueAccessor;
|
||||||
|
ValueMustNotBeNullAccessor = originalProvider.ValueMustNotBeNullAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public Func<string, string> MissingBindRequiredValueAccessor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _missingBindRequiredValueAccessor;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_missingBindRequiredValueAccessor = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public Func<string> MissingKeyOrValueAccessor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _missingKeyOrValueAccessor;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_missingKeyOrValueAccessor = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public Func<string, string> ValueMustNotBeNullAccessor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _valueMustNotBeNullAccessor;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
_valueMustNotBeNullAccessor = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,8 +6,6 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
@ -414,7 +412,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
bindingContext.ModelState.TryAddModelError(
|
bindingContext.ModelState.TryAddModelError(
|
||||||
modelStateKey,
|
modelStateKey,
|
||||||
Resources.FormatModelBinding_MissingBindRequiredMember(propertyName));
|
bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(
|
||||||
|
propertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each property that BindPropertiesAsync() attempted to bind, call the setter, recording
|
// For each property that BindPropertiesAsync() attempted to bind, call the setter, recording
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
|
|
@ -51,7 +50,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
bindingContext.ModelState.TryAddModelError(
|
bindingContext.ModelState.TryAddModelError(
|
||||||
bindingContext.ModelName,
|
bindingContext.ModelName,
|
||||||
Resources.FormatCommon_ValueNotValidForProperty(model));
|
bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(
|
||||||
|
valueProviderResult.ToString()));
|
||||||
|
|
||||||
return ModelBindingResult.FailedAsync(bindingContext.ModelName);
|
return ModelBindingResult.FailedAsync(bindingContext.ModelName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
InputFormatters = new FormatterCollection<IInputFormatter>();
|
InputFormatters = new FormatterCollection<IInputFormatter>();
|
||||||
OutputFormatters = new FormatterCollection<IOutputFormatter>();
|
OutputFormatters = new FormatterCollection<IOutputFormatter>();
|
||||||
ModelBinders = new List<IModelBinder>();
|
ModelBinders = new List<IModelBinder>();
|
||||||
|
ModelBindingMessageProvider = new ModelBindingMessageProvider();
|
||||||
ModelMetadataDetailsProviders = new List<IMetadataDetailsProvider>();
|
ModelMetadataDetailsProviders = new List<IMetadataDetailsProvider>();
|
||||||
ModelValidatorProviders = new List<IModelValidatorProvider>();
|
ModelValidatorProviders = new List<IModelValidatorProvider>();
|
||||||
ValidationExcludeFilters = new ExcludeTypeValidationFilterCollection();
|
ValidationExcludeFilters = new ExcludeTypeValidationFilterCollection();
|
||||||
|
|
@ -87,7 +88,14 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public IList<IModelBinder> ModelBinders { get; }
|
public IList<IModelBinder> ModelBinders { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a list of <see cref="IMetadataDetailsProvider"/> instances that will be used to
|
/// Gets the default <see cref="IModelBindingMessageProvider"/>. Changes here are copied to the
|
||||||
|
/// <see cref="ModelMetadata.ModelBindingMessageProvider"/> property of all <see cref="ModelMetadata"/>
|
||||||
|
/// instances unless overridden in a custom <see cref="IBindingMetadataProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
public ModelBindingMessageProvider ModelBindingMessageProvider { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of <see cref="IMetadataDetailsProvider"/> instances that will be used to
|
||||||
/// create <see cref="ModelMetadata"/> instances.
|
/// create <see cref="ModelMetadata"/> instances.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
|
|
@ -112,7 +120,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public FormatterCollection<IOutputFormatter> OutputFormatters { get; }
|
public FormatterCollection<IOutputFormatter> OutputFormatters { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the flag which causes content negotiation to ignore Accept header
|
/// Gets or sets the flag which causes content negotiation to ignore Accept header
|
||||||
/// when it contains the media type */*. <see langword="false"/> by default.
|
/// when it contains the media type */*. <see langword="false"/> by default.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool RespectBrowserAcceptHeader { get; set; }
|
public bool RespectBrowserAcceptHeader { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -74,22 +74,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ActionExecutor_UnexpectedTaskInstance"), p0, p1);
|
return string.Format(CultureInfo.CurrentCulture, GetString("ActionExecutor_UnexpectedTaskInstance"), p0, p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Replacing the action context is not supported.
|
|
||||||
/// </summary>
|
|
||||||
internal static string ActionContextAccessor_SetValueNotSupported
|
|
||||||
{
|
|
||||||
get { return GetString("ActionContextAccessor_SetValueNotSupported"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Replacing the action context is not supported.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatActionContextAccessor_SetValueNotSupported()
|
|
||||||
{
|
|
||||||
return GetString("ActionContextAccessor_SetValueNotSupported");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An action invoker could not be created for action '{0}'.
|
/// An action invoker could not be created for action '{0}'.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -171,51 +155,19 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The supplied route values are ambiguous and can select multiple sets of actions.
|
/// The value '{0}' is invalid.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ActionSelector_GetCandidateActionsIsAmbiguous
|
internal static string ModelBinding_NullValueNotValid
|
||||||
{
|
{
|
||||||
get { return GetString("ActionSelector_GetCandidateActionsIsAmbiguous"); }
|
get { return GetString("ModelBinding_NullValueNotValid"); }
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The supplied route values are ambiguous and can select multiple sets of actions.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatActionSelector_GetCandidateActionsIsAmbiguous()
|
|
||||||
{
|
|
||||||
return GetString("ActionSelector_GetCandidateActionsIsAmbiguous");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Property '{0}' is of type '{1}', but this method requires a value of type '{2}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string ArgumentPropertyUnexpectedType
|
|
||||||
{
|
|
||||||
get { return GetString("ArgumentPropertyUnexpectedType"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Property '{0}' is of type '{1}', but this method requires a value of type '{2}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatArgumentPropertyUnexpectedType(object p0, object p1, object p2)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentPropertyUnexpectedType"), p0, p1, p2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The value '{0}' is invalid.
|
/// The value '{0}' is invalid.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string Common_ValueNotValidForProperty
|
internal static string FormatModelBinding_NullValueNotValid(object p0)
|
||||||
{
|
{
|
||||||
get { return GetString("Common_ValueNotValidForProperty"); }
|
return string.Format(CultureInfo.CurrentCulture, GetString("ModelBinding_NullValueNotValid"), p0);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The value '{0}' is invalid.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatCommon_ValueNotValidForProperty(object p0)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("Common_ValueNotValidForProperty"), p0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -282,38 +234,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("AsyncResultFilter_InvalidShortCircuit"), p0, p1, p2, p3);
|
return string.Format(CultureInfo.CurrentCulture, GetString("AsyncResultFilter_InvalidShortCircuit"), p0, p1, p2, p3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unable to locate an implementation of IAuthorizationService.
|
|
||||||
/// </summary>
|
|
||||||
internal static string AuthorizeAttribute_AuthorizationServiceMustBeDefined
|
|
||||||
{
|
|
||||||
get { return GetString("AuthorizeAttribute_AuthorizationServiceMustBeDefined"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unable to locate an implementation of IAuthorizationService.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatAuthorizeAttribute_AuthorizationServiceMustBeDefined()
|
|
||||||
{
|
|
||||||
return GetString("AuthorizeAttribute_AuthorizationServiceMustBeDefined");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// OnAuthorization is not implemented by this filter, use OnAuthorizationAsync instead.
|
|
||||||
/// </summary>
|
|
||||||
internal static string AuthorizeAttribute_OnAuthorizationNotImplemented
|
|
||||||
{
|
|
||||||
get { return GetString("AuthorizeAttribute_OnAuthorizationNotImplemented"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// OnAuthorization is not implemented by this filter, use OnAuthorizationAsync instead.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatAuthorizeAttribute_OnAuthorizationNotImplemented()
|
|
||||||
{
|
|
||||||
return GetString("AuthorizeAttribute_OnAuthorizationNotImplemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The type provided to '{0}' must implement '{1}'.
|
/// The type provided to '{0}' must implement '{1}'.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -826,22 +746,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("Format_NotValid"), p0);
|
return string.Format(CultureInfo.CurrentCulture, GetString("Format_NotValid"), p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The property '{0}' on controller '{1}' cannot be activated.
|
|
||||||
/// </summary>
|
|
||||||
internal static string ControllerFactory_PropertyCannotBeActivated
|
|
||||||
{
|
|
||||||
get { return GetString("ControllerFactory_PropertyCannotBeActivated"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The property '{0}' on controller '{1}' cannot be activated.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatControllerFactory_PropertyCannotBeActivated(object p0, object p1)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ControllerFactory_PropertyCannotBeActivated"), p0, p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The '{0}' cache profile is not defined.
|
/// The '{0}' cache profile is not defined.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -938,22 +842,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("BindingSource_CannotBeGreedy"), p0, p1);
|
return string.Format(CultureInfo.CurrentCulture, GetString("BindingSource_CannotBeGreedy"), p0, p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The provided binding source '{0}' is not a request-based binding source. '{1}' requires that the source must represent data from an HTTP request.
|
|
||||||
/// </summary>
|
|
||||||
internal static string BindingSource_MustBeFromRequest
|
|
||||||
{
|
|
||||||
get { return GetString("BindingSource_MustBeFromRequest"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The provided binding source '{0}' is not a request-based binding source. '{1}' requires that the source must represent data from an HTTP request.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatBindingSource_MustBeFromRequest(object p0, object p1)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("BindingSource_MustBeFromRequest"), p0, p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The property {0}.{1} could not be found.
|
/// The property {0}.{1} could not be found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -1082,38 +970,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ModelBinding_MissingBindRequiredMember"), p0);
|
return string.Format(CultureInfo.CurrentCulture, GetString("ModelBinding_MissingBindRequiredMember"), p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A value is required.
|
|
||||||
/// </summary>
|
|
||||||
internal static string ModelBinding_ValueRequired
|
|
||||||
{
|
|
||||||
get { return GetString("ModelBinding_ValueRequired"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A value is required.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatModelBinding_ValueRequired()
|
|
||||||
{
|
|
||||||
return GetString("ModelBinding_ValueRequired");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// More than one parameter and/or property is bound to the HTTP request's content.
|
|
||||||
/// </summary>
|
|
||||||
internal static string MultipleBodyParametersOrPropertiesAreNotAllowed
|
|
||||||
{
|
|
||||||
get { return GetString("MultipleBodyParametersOrPropertiesAreNotAllowed"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// More than one parameter and/or property is bound to the HTTP request's content.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatMultipleBodyParametersOrPropertiesAreNotAllowed()
|
|
||||||
{
|
|
||||||
return GetString("MultipleBodyParametersOrPropertiesAreNotAllowed");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The type '{0}' does not implement the interface '{1}'.
|
/// The type '{0}' does not implement the interface '{1}'.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -1130,38 +986,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("PropertyBindingPredicateProvider_WrongType"), p0, p1);
|
return string.Format(CultureInfo.CurrentCulture, GetString("PropertyBindingPredicateProvider_WrongType"), p0, p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The model object inside the metadata claimed to be compatible with '{0}', but was actually '{1}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string ValidatableObjectAdapter_IncompatibleType
|
|
||||||
{
|
|
||||||
get { return GetString("ValidatableObjectAdapter_IncompatibleType"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The model object inside the metadata claimed to be compatible with '{0}', but was actually '{1}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatValidatableObjectAdapter_IncompatibleType(object p0, object p1)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ValidatableObjectAdapter_IncompatibleType"), p0, p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cannot convert value '{0}' to enum type '{1}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string ValueProviderResult_CannotConvertEnum
|
|
||||||
{
|
|
||||||
get { return GetString("ValueProviderResult_CannotConvertEnum"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cannot convert value '{0}' to enum type '{1}'.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatValueProviderResult_CannotConvertEnum(object p0, object p1)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ValueProviderResult_CannotConvertEnum"), p0, p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.
|
/// The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -129,9 +129,6 @@
|
||||||
<data name="ActionExecutor_UnexpectedTaskInstance" xml:space="preserve">
|
<data name="ActionExecutor_UnexpectedTaskInstance" xml:space="preserve">
|
||||||
<value>The method '{0}' on type '{1}' returned a Task instance even though it is not an asynchronous method.</value>
|
<value>The method '{0}' on type '{1}' returned a Task instance even though it is not an asynchronous method.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionContextAccessor_SetValueNotSupported" xml:space="preserve">
|
|
||||||
<value>Replacing the action context is not supported.</value>
|
|
||||||
</data>
|
|
||||||
<data name="ActionInvokerFactory_CouldNotCreateInvoker" xml:space="preserve">
|
<data name="ActionInvokerFactory_CouldNotCreateInvoker" xml:space="preserve">
|
||||||
<value>An action invoker could not be created for action '{0}'.</value>
|
<value>An action invoker could not be created for action '{0}'.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -147,13 +144,7 @@
|
||||||
<data name="TypeMethodMustReturnNotNullValue" xml:space="preserve">
|
<data name="TypeMethodMustReturnNotNullValue" xml:space="preserve">
|
||||||
<value>The '{0}' method of type '{1}' cannot return a null value.</value>
|
<value>The '{0}' method of type '{1}' cannot return a null value.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ActionSelector_GetCandidateActionsIsAmbiguous" xml:space="preserve">
|
<data name="ModelBinding_NullValueNotValid" xml:space="preserve">
|
||||||
<value>The supplied route values are ambiguous and can select multiple sets of actions.</value>
|
|
||||||
</data>
|
|
||||||
<data name="ArgumentPropertyUnexpectedType" xml:space="preserve">
|
|
||||||
<value>Property '{0}' is of type '{1}', but this method requires a value of type '{2}'.</value>
|
|
||||||
</data>
|
|
||||||
<data name="Common_ValueNotValidForProperty" xml:space="preserve">
|
|
||||||
<value>The value '{0}' is invalid.</value>
|
<value>The value '{0}' is invalid.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Invalid_IncludePropertyExpression" xml:space="preserve">
|
<data name="Invalid_IncludePropertyExpression" xml:space="preserve">
|
||||||
|
|
@ -168,12 +159,6 @@
|
||||||
<data name="AsyncResultFilter_InvalidShortCircuit" xml:space="preserve">
|
<data name="AsyncResultFilter_InvalidShortCircuit" xml:space="preserve">
|
||||||
<value>If an {0} cancels execution by setting the {1} property of {2} to 'true', then it cannot call the next filter by invoking {3}.</value>
|
<value>If an {0} cancels execution by setting the {1} property of {2} to 'true', then it cannot call the next filter by invoking {3}.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AuthorizeAttribute_AuthorizationServiceMustBeDefined" xml:space="preserve">
|
|
||||||
<value>Unable to locate an implementation of IAuthorizationService.</value>
|
|
||||||
</data>
|
|
||||||
<data name="AuthorizeAttribute_OnAuthorizationNotImplemented" xml:space="preserve">
|
|
||||||
<value>OnAuthorization is not implemented by this filter, use OnAuthorizationAsync instead.</value>
|
|
||||||
</data>
|
|
||||||
<data name="FilterFactoryAttribute_TypeMustImplementIFilter" xml:space="preserve">
|
<data name="FilterFactoryAttribute_TypeMustImplementIFilter" xml:space="preserve">
|
||||||
<value>The type provided to '{0}' must implement '{1}'.</value>
|
<value>The type provided to '{0}' must implement '{1}'.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -279,9 +264,6 @@
|
||||||
<data name="Format_NotValid" xml:space="preserve">
|
<data name="Format_NotValid" xml:space="preserve">
|
||||||
<value>The format provided is invalid '{0}'. A format must be a non-empty file-extension, optionally prefixed with a '.' character.</value>
|
<value>The format provided is invalid '{0}'. A format must be a non-empty file-extension, optionally prefixed with a '.' character.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ControllerFactory_PropertyCannotBeActivated" xml:space="preserve">
|
|
||||||
<value>The property '{0}' on controller '{1}' cannot be activated.</value>
|
|
||||||
</data>
|
|
||||||
<data name="CacheProfileNotFound" xml:space="preserve">
|
<data name="CacheProfileNotFound" xml:space="preserve">
|
||||||
<value>The '{0}' cache profile is not defined.</value>
|
<value>The '{0}' cache profile is not defined.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -300,9 +282,6 @@
|
||||||
<data name="BindingSource_CannotBeGreedy" xml:space="preserve">
|
<data name="BindingSource_CannotBeGreedy" xml:space="preserve">
|
||||||
<value>The provided binding source '{0}' is a greedy data source. '{1}' does not support greedy data sources.</value>
|
<value>The provided binding source '{0}' is a greedy data source. '{1}' does not support greedy data sources.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="BindingSource_MustBeFromRequest" xml:space="preserve">
|
|
||||||
<value>The provided binding source '{0}' is not a request-based binding source. '{1}' requires that the source must represent data from an HTTP request.</value>
|
|
||||||
</data>
|
|
||||||
<data name="Common_PropertyNotFound" xml:space="preserve">
|
<data name="Common_PropertyNotFound" xml:space="preserve">
|
||||||
<value>The property {0}.{1} could not be found.</value>
|
<value>The property {0}.{1} could not be found.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
@ -327,21 +306,9 @@
|
||||||
<data name="ModelBinding_MissingBindRequiredMember" xml:space="preserve">
|
<data name="ModelBinding_MissingBindRequiredMember" xml:space="preserve">
|
||||||
<value>A value for the '{0}' property was not provided.</value>
|
<value>A value for the '{0}' property was not provided.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModelBinding_ValueRequired" xml:space="preserve">
|
|
||||||
<value>A value is required.</value>
|
|
||||||
</data>
|
|
||||||
<data name="MultipleBodyParametersOrPropertiesAreNotAllowed" xml:space="preserve">
|
|
||||||
<value>More than one parameter and/or property is bound to the HTTP request's content.</value>
|
|
||||||
</data>
|
|
||||||
<data name="PropertyBindingPredicateProvider_WrongType" xml:space="preserve">
|
<data name="PropertyBindingPredicateProvider_WrongType" xml:space="preserve">
|
||||||
<value>The type '{0}' does not implement the interface '{1}'.</value>
|
<value>The type '{0}' does not implement the interface '{1}'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ValidatableObjectAdapter_IncompatibleType" xml:space="preserve">
|
|
||||||
<value>The model object inside the metadata claimed to be compatible with '{0}', but was actually '{1}'.</value>
|
|
||||||
</data>
|
|
||||||
<data name="ValueProviderResult_CannotConvertEnum" xml:space="preserve">
|
|
||||||
<value>Cannot convert value '{0}' to enum type '{1}'.</value>
|
|
||||||
</data>
|
|
||||||
<data name="ValueProviderResult_NoConverterExists" xml:space="preserve">
|
<data name="ValueProviderResult_NoConverterExists" xml:space="preserve">
|
||||||
<value>The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.</value>
|
<value>The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
|
||||||
|
|
@ -457,6 +457,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IModelBindingMessageProvider ModelBindingMessageProvider
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override string NullDisplayText
|
public override string NullDisplayText
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
#if DNX451
|
#if DNX451
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||||
|
|
@ -54,7 +53,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||||
Assert.Null(result.Model);
|
Assert.Null(result.Model);
|
||||||
Assert.False(bindingContext.ModelState.IsValid);
|
Assert.False(bindingContext.ModelState.IsValid);
|
||||||
Assert.Equal("someName", bindingContext.ModelName);
|
Assert.Equal("someName", bindingContext.ModelName);
|
||||||
Assert.Equal(bindingContext.ModelState["someName.Value"].Errors.First().ErrorMessage, "A value is required.");
|
var state = bindingContext.ModelState["someName.Value"];
|
||||||
|
Assert.NotNull(state);
|
||||||
|
var error = Assert.Single(state.Errors);
|
||||||
|
Assert.Equal("A value is required.", error.ErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -117,7 +119,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||||
{
|
{
|
||||||
innerResult = ModelBindingResult.Failed("somename.key");
|
innerResult = ModelBindingResult.Failed("somename.key");
|
||||||
}
|
}
|
||||||
|
|
||||||
var innerBinder = new Mock<IModelBinder>();
|
var innerBinder = new Mock<IModelBinder>();
|
||||||
innerBinder
|
innerBinder
|
||||||
.Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
.Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||||
|
|
@ -161,7 +163,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotEqual(ModelBindingResult.NoResult, result);
|
Assert.NotEqual(ModelBindingResult.NoResult, result);
|
||||||
|
|
||||||
Assert.Equal(default(KeyValuePair<string, string>), Assert.IsType<KeyValuePair<string, string>>(result.Model));
|
var model = Assert.IsType<KeyValuePair<string, string>>(result.Model);
|
||||||
|
Assert.Equal(default(KeyValuePair<string, string>), model);
|
||||||
Assert.Equal("modelName", result.Key);
|
Assert.Equal("modelName", result.Key);
|
||||||
Assert.True(result.IsModelSet);
|
Assert.True(result.IsModelSet);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
|
|
@ -21,7 +22,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForType(typeof(string)),
|
ModelMetadataIdentity.ForType(typeof(string)),
|
||||||
new ModelAttributes(attributes));
|
new ModelAttributes(attributes));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -45,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForType(typeof(string)),
|
ModelMetadataIdentity.ForType(typeof(string)),
|
||||||
new ModelAttributes(attributes));
|
new ModelAttributes(attributes));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -68,7 +69,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForType(typeof(string)),
|
ModelMetadataIdentity.ForType(typeof(string)),
|
||||||
new ModelAttributes(attributes));
|
new ModelAttributes(attributes));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -92,7 +93,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForType(typeof(string)),
|
ModelMetadataIdentity.ForType(typeof(string)),
|
||||||
new ModelAttributes(attributes));
|
new ModelAttributes(attributes));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -115,7 +116,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForType(typeof(string)),
|
ModelMetadataIdentity.ForType(typeof(string)),
|
||||||
new ModelAttributes(attributes));
|
new ModelAttributes(attributes));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -139,7 +140,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForType(typeof(string)),
|
ModelMetadataIdentity.ForType(typeof(string)),
|
||||||
new ModelAttributes(attributes));
|
new ModelAttributes(attributes));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -161,7 +162,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
||||||
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -184,7 +185,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
||||||
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -207,7 +208,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
||||||
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -230,7 +231,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
||||||
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -253,7 +254,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
||||||
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -279,7 +280,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
ModelMetadataIdentity.ForProperty(typeof(int), "Length", typeof(string)),
|
||||||
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -297,7 +298,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindRequiredOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindRequiredOnClass)),
|
||||||
new ModelAttributes(propertyAttributes: new object[0], typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes: new object[0], typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -315,7 +316,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindNeverOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindNeverOnClass)),
|
||||||
new ModelAttributes(propertyAttributes: new object[0], typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes: new object[0], typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -333,7 +334,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(InheritedBindNeverOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(InheritedBindNeverOnClass)),
|
||||||
new ModelAttributes(propertyAttributes: new object[0], typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes: new object[0], typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -356,7 +357,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindNeverOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindNeverOnClass)),
|
||||||
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -379,7 +380,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindNeverOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindNeverOnClass)),
|
||||||
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -402,7 +403,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(InheritedBindNeverOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(InheritedBindNeverOnClass)),
|
||||||
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -425,7 +426,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindRequiredOnClass)),
|
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindRequiredOnClass)),
|
||||||
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes, typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -444,7 +445,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindRequiredOverridesInheritedBindNever)),
|
ModelMetadataIdentity.ForProperty(typeof(string), "Property", typeof(BindRequiredOverridesInheritedBindNever)),
|
||||||
new ModelAttributes(propertyAttributes: new object[0], typeAttributes: new object[0]));
|
new ModelAttributes(propertyAttributes: new object[0], typeAttributes: new object[0]));
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -473,7 +474,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
context.BindingMetadata.IsBindingAllowed = initialValue;
|
context.BindingMetadata.IsBindingAllowed = initialValue;
|
||||||
context.BindingMetadata.IsBindingRequired = initialValue;
|
context.BindingMetadata.IsBindingRequired = initialValue;
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -504,7 +505,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
context.BindingMetadata.IsBindingAllowed = initialValue;
|
context.BindingMetadata.IsBindingAllowed = initialValue;
|
||||||
context.BindingMetadata.IsBindingRequired = initialValue;
|
context.BindingMetadata.IsBindingRequired = initialValue;
|
||||||
|
|
||||||
var provider = new DefaultBindingMetadataProvider();
|
var provider = new DefaultBindingMetadataProvider(CreateMessageProvider());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
provider.GetBindingMetadata(context);
|
provider.GetBindingMetadata(context);
|
||||||
|
|
@ -514,6 +515,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
Assert.Equal(initialValue, context.BindingMetadata.IsBindingRequired);
|
Assert.Equal(initialValue, context.BindingMetadata.IsBindingRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ModelBindingMessageProvider CreateMessageProvider()
|
||||||
|
{
|
||||||
|
return new ModelBindingMessageProvider
|
||||||
|
{
|
||||||
|
MissingBindRequiredValueAccessor = Resources.FormatModelBinding_MissingBindRequiredMember,
|
||||||
|
MissingKeyOrValueAccessor = Resources.FormatKeyValuePair_BothKeyAndValueMustBePresent,
|
||||||
|
ValueMustNotBeNullAccessor = Resources.FormatModelBinding_NullValueNotValid,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
[BindNever]
|
[BindNever]
|
||||||
private class BindNeverOnClass
|
private class BindNeverOnClass
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -787,7 +787,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
property => ModelBindingResult.Failed(property.PropertyName));
|
property => ModelBindingResult.Failed(property.PropertyName));
|
||||||
var nameProperty = containerMetadata.Properties[nameof(model.Name)];
|
var nameProperty = containerMetadata.Properties[nameof(model.Name)];
|
||||||
results[nameProperty] = ModelBindingResult.Success(string.Empty, "John Doe");
|
results[nameProperty] = ModelBindingResult.Success(string.Empty, "John Doe");
|
||||||
|
|
||||||
var testableBinder = new TestableMutableObjectModelBinder();
|
var testableBinder = new TestableMutableObjectModelBinder();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -1219,7 +1219,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
results[lastNameProperty] = ModelBindingResult.Success(
|
results[lastNameProperty] = ModelBindingResult.Success(
|
||||||
nameof(model.LastName),
|
nameof(model.LastName),
|
||||||
"Doe");
|
"Doe");
|
||||||
|
|
||||||
var testableBinder = new TestableMutableObjectModelBinder();
|
var testableBinder = new TestableMutableObjectModelBinder();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||||
Assert.Null(result.Model);
|
Assert.Null(result.Model);
|
||||||
|
|
||||||
var error = Assert.Single(bindingContext.ModelState["theModelName"].Errors);
|
var error = Assert.Single(bindingContext.ModelState["theModelName"].Errors);
|
||||||
Assert.Equal(error.ErrorMessage, "The value '' is invalid.", StringComparer.Ordinal);
|
Assert.Equal("The value '' is invalid.", error.ErrorMessage, StringComparer.Ordinal);
|
||||||
Assert.Null(error.Exception);
|
Assert.Null(error.Exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1026,13 +1026,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
||||||
public AttributeInjectModelMetadataProvider(object[] attributes)
|
public AttributeInjectModelMetadataProvider(object[] attributes)
|
||||||
: base(new DefaultCompositeMetadataDetailsProvider(new IMetadataDetailsProvider[]
|
: base(new DefaultCompositeMetadataDetailsProvider(new IMetadataDetailsProvider[]
|
||||||
{
|
{
|
||||||
new DefaultBindingMetadataProvider(),
|
new DefaultBindingMetadataProvider(CreateMessageProvider()),
|
||||||
new DataAnnotationsMetadataProvider(),
|
new DataAnnotationsMetadataProvider(),
|
||||||
}))
|
}))
|
||||||
{
|
{
|
||||||
_attributes = attributes;
|
_attributes = attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ModelBindingMessageProvider CreateMessageProvider()
|
||||||
|
{
|
||||||
|
return new ModelBindingMessageProvider
|
||||||
|
{
|
||||||
|
MissingBindRequiredValueAccessor = name => $"A value for the '{ name }' property was not provided.",
|
||||||
|
MissingKeyOrValueAccessor = () => $"A value is required.",
|
||||||
|
ValueMustNotBeNullAccessor = value => $"The value '{ value }' is invalid.",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
protected override DefaultMetadataDetails CreateTypeDetails(ModelMetadataIdentity key)
|
protected override DefaultMetadataDetails CreateTypeDetails(ModelMetadataIdentity key)
|
||||||
{
|
{
|
||||||
var entry = base.CreateTypeDetails(key);
|
var entry = base.CreateTypeDetails(key);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Mvc.Abstractions;
|
using Microsoft.AspNet.Mvc.Abstractions;
|
||||||
|
using Microsoft.AspNet.Mvc.Controllers;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -46,13 +47,183 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
|
|
||||||
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Key").Value;
|
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Key").Value;
|
||||||
Assert.Equal("key0", entry.AttemptedValue);
|
Assert.Equal("key0", entry.AttemptedValue);
|
||||||
Assert.Equal("key0", entry.RawValue);
|
Assert.Equal("key0", entry.RawValue);
|
||||||
|
|
||||||
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Value").Value;
|
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Value").Value;
|
||||||
Assert.Equal("10", entry.AttemptedValue);
|
Assert.Equal("10", entry.AttemptedValue);
|
||||||
Assert.Equal("10", entry.RawValue);
|
Assert.Equal("10", entry.RawValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task KeyValuePairModelBinder_SimpleTypes_WithNoKey_AddsError()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||||
|
var parameter = new ParameterDescriptor
|
||||||
|
{
|
||||||
|
Name = "parameter",
|
||||||
|
ParameterType = typeof(KeyValuePair<string, int>)
|
||||||
|
};
|
||||||
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||||
|
{
|
||||||
|
request.QueryString = new QueryString("?parameter.Value=10");
|
||||||
|
});
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(modelBindingResult.IsModelSet);
|
||||||
|
Assert.Equal(2, modelState.Count);
|
||||||
|
|
||||||
|
Assert.False(modelState.IsValid);
|
||||||
|
Assert.Equal(1, modelState.ErrorCount);
|
||||||
|
|
||||||
|
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Key").Value;
|
||||||
|
var error = Assert.Single(entry.Errors);
|
||||||
|
Assert.Null(error.Exception);
|
||||||
|
Assert.Equal("A value is required.", error.ErrorMessage);
|
||||||
|
|
||||||
|
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Value").Value;
|
||||||
|
Assert.Empty(entry.Errors);
|
||||||
|
Assert.Equal("10", entry.AttemptedValue);
|
||||||
|
Assert.Equal("10", entry.RawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task KeyValuePairModelBinder_SimpleTypes_WithNoKey_AndCustomizedMessage_AddsGivenMessage()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var metadataProvider = new TestModelMetadataProvider();
|
||||||
|
metadataProvider
|
||||||
|
.ForType(typeof(KeyValuePair<string, int>))
|
||||||
|
.BindingDetails((System.Action<ModelBinding.Metadata.BindingMetadata>)(binding =>
|
||||||
|
{
|
||||||
|
// A real details provider could customize message based on BindingMetadataProviderContext.
|
||||||
|
binding.ModelBindingMessageProvider.MissingKeyOrValueAccessor = () => $"Hurts when nothing is provided.";
|
||||||
|
}));
|
||||||
|
|
||||||
|
var argumentBinder = new DefaultControllerActionArgumentBinder(
|
||||||
|
metadataProvider,
|
||||||
|
ModelBindingTestHelper.GetObjectValidator());
|
||||||
|
var parameter = new ParameterDescriptor
|
||||||
|
{
|
||||||
|
Name = "parameter",
|
||||||
|
ParameterType = typeof(KeyValuePair<string, int>)
|
||||||
|
};
|
||||||
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||||
|
{
|
||||||
|
request.QueryString = new QueryString("?parameter.Value=10");
|
||||||
|
});
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(modelBindingResult.IsModelSet);
|
||||||
|
Assert.Equal(2, modelState.Count);
|
||||||
|
|
||||||
|
Assert.False(modelState.IsValid);
|
||||||
|
Assert.Equal(1, modelState.ErrorCount);
|
||||||
|
|
||||||
|
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Key").Value;
|
||||||
|
var error = Assert.Single(entry.Errors);
|
||||||
|
Assert.Null(error.Exception);
|
||||||
|
Assert.Equal("Hurts when nothing is provided.", error.ErrorMessage);
|
||||||
|
|
||||||
|
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Value").Value;
|
||||||
|
Assert.Empty(entry.Errors);
|
||||||
|
Assert.Equal("10", entry.AttemptedValue);
|
||||||
|
Assert.Equal("10", entry.RawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task KeyValuePairModelBinder_SimpleTypes_WithNoValue_AddsError()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||||
|
var parameter = new ParameterDescriptor
|
||||||
|
{
|
||||||
|
Name = "parameter",
|
||||||
|
ParameterType = typeof(KeyValuePair<string, int>)
|
||||||
|
};
|
||||||
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||||
|
{
|
||||||
|
request.QueryString = new QueryString("?parameter.Key=10");
|
||||||
|
});
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(modelBindingResult.IsModelSet);
|
||||||
|
Assert.Equal(2, modelState.Count);
|
||||||
|
|
||||||
|
Assert.False(modelState.IsValid);
|
||||||
|
Assert.Equal(1, modelState.ErrorCount);
|
||||||
|
|
||||||
|
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Key").Value;
|
||||||
|
Assert.Empty(entry.Errors);
|
||||||
|
Assert.Equal("10", entry.AttemptedValue);
|
||||||
|
Assert.Equal("10", entry.RawValue);
|
||||||
|
|
||||||
|
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Value").Value;
|
||||||
|
var error = Assert.Single(entry.Errors);
|
||||||
|
Assert.Null(error.Exception);
|
||||||
|
Assert.Equal("A value is required.", error.ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task KeyValuePairModelBinder_SimpleTypes_WithNoValue_AndCustomizedMessage_AddsGivenMessage()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var metadataProvider = new TestModelMetadataProvider();
|
||||||
|
metadataProvider
|
||||||
|
.ForType(typeof(KeyValuePair<string, int>))
|
||||||
|
.BindingDetails((System.Action<ModelBinding.Metadata.BindingMetadata>)(binding =>
|
||||||
|
{
|
||||||
|
// A real details provider could customize message based on BindingMetadataProviderContext.
|
||||||
|
binding.ModelBindingMessageProvider.MissingKeyOrValueAccessor = () => $"Hurts when nothing is provided.";
|
||||||
|
}));
|
||||||
|
var argumentBinder = new DefaultControllerActionArgumentBinder(
|
||||||
|
metadataProvider,
|
||||||
|
ModelBindingTestHelper.GetObjectValidator());
|
||||||
|
|
||||||
|
var parameter = new ParameterDescriptor
|
||||||
|
{
|
||||||
|
Name = "parameter",
|
||||||
|
ParameterType = typeof(KeyValuePair<string, int>)
|
||||||
|
};
|
||||||
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||||
|
{
|
||||||
|
request.QueryString = new QueryString("?parameter.Key=10");
|
||||||
|
});
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(modelBindingResult.IsModelSet);
|
||||||
|
Assert.Equal(2, modelState.Count);
|
||||||
|
|
||||||
|
Assert.False(modelState.IsValid);
|
||||||
|
Assert.Equal(1, modelState.ErrorCount);
|
||||||
|
|
||||||
|
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Key").Value;
|
||||||
|
Assert.Empty(entry.Errors);
|
||||||
|
Assert.Equal("10", entry.AttemptedValue);
|
||||||
|
Assert.Equal("10", entry.RawValue);
|
||||||
|
|
||||||
|
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Value").Value;
|
||||||
|
var error = Assert.Single(entry.Errors);
|
||||||
|
Assert.Null(error.Exception);
|
||||||
|
Assert.Equal("Hurts when nothing is provided.", error.ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task KeyValuePairModelBinder_BindsKeyValuePairOfSimpleType_WithExplicitPrefix_Success()
|
public async Task KeyValuePairModelBinder_BindsKeyValuePairOfSimpleType_WithExplicitPrefix_Success()
|
||||||
{
|
{
|
||||||
|
|
@ -90,7 +261,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
|
|
||||||
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix.Key").Value;
|
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix.Key").Value;
|
||||||
Assert.Equal("key0", entry.AttemptedValue);
|
Assert.Equal("key0", entry.AttemptedValue);
|
||||||
Assert.Equal("key0", entry.RawValue);
|
Assert.Equal("key0", entry.RawValue);
|
||||||
|
|
||||||
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix.Value").Value;
|
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix.Value").Value;
|
||||||
Assert.Equal("10", entry.AttemptedValue);
|
Assert.Equal("10", entry.AttemptedValue);
|
||||||
|
|
@ -130,7 +301,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
|
|
||||||
var entry = Assert.Single(modelState, kvp => kvp.Key == "Key").Value;
|
var entry = Assert.Single(modelState, kvp => kvp.Key == "Key").Value;
|
||||||
Assert.Equal("key0", entry.AttemptedValue);
|
Assert.Equal("key0", entry.AttemptedValue);
|
||||||
Assert.Equal("key0", entry.RawValue);
|
Assert.Equal("key0", entry.RawValue);
|
||||||
|
|
||||||
entry = Assert.Single(modelState, kvp => kvp.Key == "Value").Value;
|
entry = Assert.Single(modelState, kvp => kvp.Key == "Value").Value;
|
||||||
Assert.Equal("10", entry.AttemptedValue);
|
Assert.Equal("10", entry.AttemptedValue);
|
||||||
|
|
@ -207,7 +378,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
|
|
||||||
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Key").Value;
|
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Key").Value;
|
||||||
Assert.Equal("key0", entry.AttemptedValue);
|
Assert.Equal("key0", entry.AttemptedValue);
|
||||||
Assert.Equal("key0", entry.RawValue);
|
Assert.Equal("key0", entry.RawValue);
|
||||||
|
|
||||||
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Value.Id").Value;
|
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter.Value.Id").Value;
|
||||||
Assert.Equal("10", entry.AttemptedValue);
|
Assert.Equal("10", entry.AttemptedValue);
|
||||||
|
|
@ -252,7 +423,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
|
|
||||||
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix.Key").Value;
|
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix.Key").Value;
|
||||||
Assert.Equal("key0", entry.AttemptedValue);
|
Assert.Equal("key0", entry.AttemptedValue);
|
||||||
Assert.Equal("key0", entry.RawValue);
|
Assert.Equal("key0", entry.RawValue);
|
||||||
|
|
||||||
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix.Value.Id").Value;
|
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix.Value.Id").Value;
|
||||||
Assert.Equal("10", entry.AttemptedValue);
|
Assert.Equal("10", entry.AttemptedValue);
|
||||||
|
|
@ -293,7 +464,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
|
|
||||||
var entry = Assert.Single(modelState, kvp => kvp.Key == "Key").Value;
|
var entry = Assert.Single(modelState, kvp => kvp.Key == "Key").Value;
|
||||||
Assert.Equal("key0", entry.AttemptedValue);
|
Assert.Equal("key0", entry.AttemptedValue);
|
||||||
Assert.Equal("key0", entry.RawValue);
|
Assert.Equal("key0", entry.RawValue);
|
||||||
|
|
||||||
entry = Assert.Single(modelState, kvp => kvp.Key == "Value.Id").Value;
|
entry = Assert.Single(modelState, kvp => kvp.Key == "Value.Id").Value;
|
||||||
Assert.Equal("10", entry.AttemptedValue);
|
Assert.Equal("10", entry.AttemptedValue);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Features.Internal;
|
using Microsoft.AspNet.Http.Features.Internal;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Abstractions;
|
using Microsoft.AspNet.Mvc.Abstractions;
|
||||||
|
using Microsoft.AspNet.Mvc.Controllers;
|
||||||
using Microsoft.AspNet.Mvc.Infrastructure;
|
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.Framework.Primitives;
|
using Microsoft.Framework.Primitives;
|
||||||
|
|
@ -859,8 +860,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
||||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||||
{
|
{
|
||||||
request.QueryString =
|
request.QueryString = new QueryString("?Name=bill&ProductIds[0]=10&ProductIds[1]=11");
|
||||||
new QueryString("?Name=bill&ProductIds[0]=10&ProductIds[1]=11");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -1032,8 +1032,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
||||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||||
{
|
{
|
||||||
request.QueryString =
|
request.QueryString = new QueryString("?Name=bill&ProductIds[0]=10&ProductIds[1]=11");
|
||||||
new QueryString("?Name=bill&ProductIds[0]=10&ProductIds[1]=11");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -1205,8 +1204,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
||||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||||
{
|
{
|
||||||
request.QueryString =
|
request.QueryString = new QueryString("?Name=bill&ProductIds[0].Key=key0&ProductIds[0].Value=10");
|
||||||
new QueryString("?Name=bill&ProductIds[0].Key=key0&ProductIds[0].Value=10");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -1378,8 +1376,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
||||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||||
{
|
{
|
||||||
request.QueryString =
|
request.QueryString = new QueryString("?Name=bill&ProductId.Key=key0&ProductId.Value=10");
|
||||||
new QueryString("?Name=bill&ProductId.Key=key0&ProductId.Value=10");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
@ -1563,9 +1560,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
};
|
};
|
||||||
|
|
||||||
// No Data
|
// No Data
|
||||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
|
||||||
{
|
|
||||||
});
|
|
||||||
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
||||||
|
|
@ -1589,6 +1584,53 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
Assert.Equal("A value for the 'Customer' property was not provided.", error.ErrorMessage);
|
Assert.Equal("A value for the 'Customer' property was not provided.", error.ErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MutableObjectModelBinder_WithBindRequired_NoData_AndCustomizedMessage_AddsGivenMessage()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var metadataProvider = new TestModelMetadataProvider();
|
||||||
|
metadataProvider
|
||||||
|
.ForType(typeof(Order10))
|
||||||
|
.BindingDetails((Action<ModelBinding.Metadata.BindingMetadata>)(binding =>
|
||||||
|
{
|
||||||
|
// A real details provider could customize message based on BindingMetadataProviderContext.
|
||||||
|
binding.ModelBindingMessageProvider.MissingBindRequiredValueAccessor =
|
||||||
|
name => $"Hurts when '{ name }' is not provided.";
|
||||||
|
}));
|
||||||
|
var argumentBinder = new DefaultControllerActionArgumentBinder(
|
||||||
|
metadataProvider,
|
||||||
|
ModelBindingTestHelper.GetObjectValidator());
|
||||||
|
var parameter = new ParameterDescriptor()
|
||||||
|
{
|
||||||
|
Name = "parameter",
|
||||||
|
ParameterType = typeof(Order10)
|
||||||
|
};
|
||||||
|
|
||||||
|
// No Data
|
||||||
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
|
||||||
|
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(modelBindingResult.IsModelSet);
|
||||||
|
|
||||||
|
var model = Assert.IsType<Order10>(modelBindingResult.Model);
|
||||||
|
Assert.Null(model.Customer);
|
||||||
|
|
||||||
|
Assert.Equal(1, modelState.Count);
|
||||||
|
Assert.Equal(1, modelState.ErrorCount);
|
||||||
|
Assert.False(modelState.IsValid);
|
||||||
|
|
||||||
|
var entry = Assert.Single(modelState, e => e.Key == "Customer").Value;
|
||||||
|
Assert.Null(entry.RawValue);
|
||||||
|
Assert.Null(entry.AttemptedValue);
|
||||||
|
var error = Assert.Single(modelState["Customer"].Errors);
|
||||||
|
Assert.Equal("Hurts when 'Customer' is not provided.", error.ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
private class Order11
|
private class Order11
|
||||||
{
|
{
|
||||||
public Person11 Customer { get; set; }
|
public Person11 Customer { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Abstractions;
|
using Microsoft.AspNet.Mvc.Abstractions;
|
||||||
|
using Microsoft.AspNet.Mvc.Controllers;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.Framework.Primitives;
|
using Microsoft.Framework.Primitives;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -262,7 +263,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
};
|
};
|
||||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||||
{
|
{
|
||||||
request.QueryString = QueryString.Create("Parameter1", string.Empty);
|
request.QueryString = QueryString.Create("Parameter1", " ");
|
||||||
});
|
});
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
||||||
|
|
@ -277,6 +278,58 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
// Model
|
// Model
|
||||||
Assert.Null(modelBindingResult.Model);
|
Assert.Null(modelBindingResult.Model);
|
||||||
|
|
||||||
|
// ModelState
|
||||||
|
Assert.False(modelState.IsValid);
|
||||||
|
var key = Assert.Single(modelState.Keys);
|
||||||
|
Assert.Equal("Parameter1", key);
|
||||||
|
Assert.Equal(" ", modelState[key].AttemptedValue);
|
||||||
|
Assert.Equal(" ", modelState[key].RawValue);
|
||||||
|
var error = Assert.Single(modelState[key].Errors);
|
||||||
|
Assert.Equal("The value ' ' is invalid.", error.ErrorMessage, StringComparer.Ordinal);
|
||||||
|
Assert.Null(error.Exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(typeof(int))]
|
||||||
|
[InlineData(typeof(bool))]
|
||||||
|
public async Task BindParameter_WithEmptyData_AndPerTypeMessage_AddsGivenMessage(Type parameterType)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var metadataProvider = new TestModelMetadataProvider();
|
||||||
|
metadataProvider
|
||||||
|
.ForType(parameterType)
|
||||||
|
.BindingDetails((Action<ModelBinding.Metadata.BindingMetadata>)(binding =>
|
||||||
|
{
|
||||||
|
// A real details provider could customize message based on BindingMetadataProviderContext.
|
||||||
|
binding.ModelBindingMessageProvider.ValueMustNotBeNullAccessor =
|
||||||
|
value => $"Hurts when '{ value }' is provided.";
|
||||||
|
}));
|
||||||
|
var argumentBinder = new DefaultControllerActionArgumentBinder(
|
||||||
|
metadataProvider,
|
||||||
|
ModelBindingTestHelper.GetObjectValidator());
|
||||||
|
var parameter = new ParameterDescriptor
|
||||||
|
{
|
||||||
|
Name = "Parameter1",
|
||||||
|
BindingInfo = new BindingInfo(),
|
||||||
|
|
||||||
|
ParameterType = parameterType
|
||||||
|
};
|
||||||
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||||
|
{
|
||||||
|
request.QueryString = QueryString.Create("Parameter1", string.Empty);
|
||||||
|
});
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
// ModelBindingResult
|
||||||
|
Assert.False(modelBindingResult.IsModelSet);
|
||||||
|
|
||||||
|
// Model
|
||||||
|
Assert.Null(modelBindingResult.Model);
|
||||||
|
|
||||||
// ModelState
|
// ModelState
|
||||||
Assert.False(modelState.IsValid);
|
Assert.False(modelState.IsValid);
|
||||||
var key = Assert.Single(modelState.Keys);
|
var key = Assert.Single(modelState.Keys);
|
||||||
|
|
@ -284,7 +337,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
Assert.Equal(string.Empty, modelState[key].AttemptedValue);
|
Assert.Equal(string.Empty, modelState[key].AttemptedValue);
|
||||||
Assert.Equal(string.Empty, modelState[key].RawValue);
|
Assert.Equal(string.Empty, modelState[key].RawValue);
|
||||||
var error = Assert.Single(modelState[key].Errors);
|
var error = Assert.Single(modelState[key].Errors);
|
||||||
Assert.Equal(error.ErrorMessage, "The value '' is invalid.", StringComparer.Ordinal);
|
Assert.Equal("Hurts when '' is provided.", error.ErrorMessage, StringComparer.Ordinal);
|
||||||
Assert.Null(error.Exception);
|
Assert.Null(error.Exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
var detailsProviders = new IMetadataDetailsProvider[]
|
var detailsProviders = new IMetadataDetailsProvider[]
|
||||||
{
|
{
|
||||||
new DefaultBindingMetadataProvider(),
|
new DefaultBindingMetadataProvider(CreateMessageProvider()),
|
||||||
new DefaultValidationMetadataProvider(),
|
new DefaultValidationMetadataProvider(),
|
||||||
new DataAnnotationsMetadataProvider(),
|
new DataAnnotationsMetadataProvider(),
|
||||||
new DataMemberRequiredBindingMetadataProvider(),
|
new DataMemberRequiredBindingMetadataProvider(),
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
private TestModelMetadataProvider(TestModelMetadataDetailsProvider detailsProvider)
|
private TestModelMetadataProvider(TestModelMetadataDetailsProvider detailsProvider)
|
||||||
: base(new DefaultCompositeMetadataDetailsProvider(new IMetadataDetailsProvider[]
|
: base(new DefaultCompositeMetadataDetailsProvider(new IMetadataDetailsProvider[]
|
||||||
{
|
{
|
||||||
new DefaultBindingMetadataProvider(),
|
new DefaultBindingMetadataProvider(CreateMessageProvider()),
|
||||||
new DefaultValidationMetadataProvider(),
|
new DefaultValidationMetadataProvider(),
|
||||||
new DataAnnotationsMetadataProvider(),
|
new DataAnnotationsMetadataProvider(),
|
||||||
detailsProvider
|
detailsProvider
|
||||||
|
|
@ -76,6 +76,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
return ForProperty(typeof(TContainer), propertyName);
|
return ForProperty(typeof(TContainer), propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ModelBindingMessageProvider CreateMessageProvider()
|
||||||
|
{
|
||||||
|
return new ModelBindingMessageProvider
|
||||||
|
{
|
||||||
|
MissingBindRequiredValueAccessor = name => $"A value for the '{ name }' property was not provided.",
|
||||||
|
MissingKeyOrValueAccessor = () => $"A value is required.",
|
||||||
|
ValueMustNotBeNullAccessor = value => $"The value '{ value }' is invalid.",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private class TestModelMetadataDetailsProvider :
|
private class TestModelMetadataDetailsProvider :
|
||||||
IBindingMetadataProvider,
|
IBindingMetadataProvider,
|
||||||
IDisplayMetadataProvider,
|
IDisplayMetadataProvider,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue