Make ValueProviderResult a string-ish struct

This commit is contained in:
Ryan Nowak 2015-08-18 15:02:58 -07:00
parent 02cc82a055
commit 6d365e9a32
73 changed files with 2135 additions and 1806 deletions

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<packageSources> <packageSources>
<add key="AspNetVNext" value="https://www.myget.org/F/aspnetlitedev/api/v2" /> <add key="AspNetVNext" value="https://www.myget.org/F/aspnetlitedev/api/v2" />

View File

@ -3,17 +3,29 @@
namespace Microsoft.AspNet.Mvc.ModelBinding namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
/// <summary>
/// An entry in a <see cref="ModelStateDictionary"/>.
/// </summary>
public class ModelState public class ModelState
{ {
private readonly ModelErrorCollection _errors = new ModelErrorCollection(); /// <summary>
/// Gets the raw value from the request associated with this entry.
/// </summary>
public object RawValue { get; set; }
public ValueProviderResult Value { get; set; } /// <summary>
/// Gets the set of values contained in <see cref="RawValue"/>, joined into a comma-separated string.
/// </summary>
public string AttemptedValue { get; set; }
public ModelErrorCollection Errors /// <summary>
{ /// Gets the <see cref="ModelErrorCollection"/> for this entry.
get { return _errors; } /// </summary>
} public ModelErrorCollection Errors { get; } = new ModelErrorCollection();
/// <summary>
/// Gets or sets the <see cref="ModelValidationState"/> for this entry.
/// </summary>
public ModelValidationState ValidationState { get; set; } public ModelValidationState ValidationState { get; set; }
} }
} }

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.Framework.Internal; using Microsoft.Framework.Internal;
@ -213,6 +214,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Convert FormatExceptions to Invalid value messages. // Convert FormatExceptions to Invalid value messages.
ModelState modelState; ModelState modelState;
TryGetValue(key, out modelState); TryGetValue(key, out modelState);
string errorMessage; string errorMessage;
if (modelState == null) if (modelState == null)
{ {
@ -221,7 +223,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
else else
{ {
errorMessage = Resources.FormatModelError_InvalidValue_MessageWithModelValue( errorMessage = Resources.FormatModelError_InvalidValue_MessageWithModelValue(
modelState.Value.AttemptedValue, modelState.AttemptedValue,
key); key);
} }
@ -359,14 +361,50 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
} }
/// <summary> /// <summary>
/// Sets the value for the <see cref="ModelState"/> with the specified <paramref name="key"/> to the /// Sets the of <see cref="ModelState.RawValue"/> and <see cref="ModelState.AttemptedValue"/> for
/// specified <paramref name="value"/>. /// the <see cref="ModelState"/> with the specified <paramref name="key"/>.
/// </summary> /// </summary>
/// <param name="key">The key for the <see cref="ModelState"/> entry.</param> /// <param name="key">The key for the <see cref="ModelState"/> entry.</param>
/// <param name="value">The value to assign.</param> /// <param name="rawvalue">The raw value for the <see cref="ModelState"/> entry.</param>
public void SetModelValue([NotNull] string key, [NotNull] ValueProviderResult value) /// <param name="attemptedValue">
/// The values of <param name="rawValue"/> in a comma-separated <see cref="string"/>.
/// </param>
public void SetModelValue([NotNull] string key, object rawValue, string attemptedValue)
{ {
GetModelStateForKey(key).Value = value; var modelState = GetModelStateForKey(key);
modelState.RawValue = rawValue;
modelState.AttemptedValue = attemptedValue;
}
/// <summary>
/// Sets the value for the <see cref="ModelState"/> with the specified <paramref name="key"/>.
/// </summary>
/// <param name="key">The key for the <see cref="ModelState"/> entry</param>
/// <param name="valueProviderResult">
/// A <see cref="ValueProviderResult"/> with data for the <see cref="ModelState"/> entry.
/// </param>
public void SetModelValue([NotNull] string key, ValueProviderResult valueProviderResult)
{
// Avoid creating a new array for rawvalue if there's only one value.
object rawValue;
if (valueProviderResult == ValueProviderResult.None)
{
rawValue = null;
}
else if (valueProviderResult.Value != null)
{
rawValue = valueProviderResult.Value;
}
else if (valueProviderResult.Length == 1)
{
rawValue = valueProviderResult.Values[0];
}
else
{
rawValue = valueProviderResult.Values;
}
SetModelValue(key, rawValue, (string)valueProviderResult);
} }
/// <summary> /// <summary>

View File

@ -3,227 +3,353 @@
using System; using System;
using System.Collections; using System.Collections;
using System.ComponentModel; using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Reflection;
using System.Runtime.ExceptionServices;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.Framework.Internal; using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.ModelBinding namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
/// <summary> /// <summary>
/// Result of an <see cref="IValueProvider.GetValueAsync"/> operation. /// Result of an <see cref="IValueProvider.GetValueAsync(string)"/> operation.
/// </summary> /// </summary>
public class ValueProviderResult /// <remarks>
/// <para>
/// <see cref="ValueProviderResult"/> can represent a single submitted value or multiple submitted values.
/// </para>
/// <para>
/// Use <see cref="FirstValue"/> to consume only a single value, regardless of whether a single value or
/// multiple values were submitted.
/// </para>
/// <para>
/// Treat <see cref="ValueProviderResult"/> as an <see cref="IEnumerable{string}"/> to consume all values,
/// regardless of whether a single value or multiple values were submitted.
/// </para>
/// </remarks>
public struct ValueProviderResult : IEquatable<ValueProviderResult>, IEnumerable<string>
{ {
private static readonly CultureInfo _staticCulture = CultureInfo.InvariantCulture; private static readonly CultureInfo _invariantCulture = CultureInfo.InvariantCulture;
/// <summary> /// <summary>
/// Instantiates a new instance of the <see cref="ValueProviderResult"/> class with given /// A <see cref="ValueProviderResult"/> that represents a lack of data.
/// <paramref name="rawValue"/>. Initializes <see cref="Culture"/> to
/// <see cref="CultureInfo.InvariantCulture"/>.
/// </summary> /// </summary>
/// <param name="rawValue">The <see cref="RawValue"/> value of the new instance.</param> public static ValueProviderResult None = new ValueProviderResult(new string[0]);
public ValueProviderResult(object rawValue)
: this(rawValue, attemptedValue: null, culture: _staticCulture) /// <summary>
/// Creates a new <see cref="ValueProviderResult"/> using <see cref="CultureInfo.InvariantCulture"/>.
/// </summary>
/// <param name="value">The submitted value.</param>
public ValueProviderResult(string value)
: this(value, _invariantCulture)
{ {
} }
/// <summary> /// <summary>
/// Instantiates a new instance of the <see cref="ValueProviderResult"/> class with given /// Creates a new <see cref="ValueProviderResult"/>.
/// <paramref name="rawValue"/>, <paramref name="attemptedValue"/>, and <paramref name="culture"/>.
/// </summary> /// </summary>
/// <param name="rawValue">The <see cref="RawValue"/> value of the new instance.</param> /// <param name="value">The submitted value.</param>
/// <param name="attemptedValue">The <see cref="AttemptedValue"/> value of the new instance.</param> /// <param name="culture">The <see cref="CultureInfo"/> associated with this value.</param>
/// <param name="culture">The <see cref="Culture"/> value of the new instance.</param> public ValueProviderResult(string value, CultureInfo culture)
public ValueProviderResult(object rawValue, string attemptedValue, CultureInfo culture)
{ {
RawValue = rawValue;
AttemptedValue = attemptedValue;
Culture = culture ?? _staticCulture;
}
/// <summary>
/// <see cref="string"/> conversion of <see cref="RawValue"/>.
/// </summary>
/// <remarks>
/// Used in helpers that generate <c>&lt;textarea&gt;</c> elements as well as some error messages.
/// </remarks>
public string AttemptedValue { get; }
/// <summary>
/// <see cref="CultureInfo"/> to use in <see cref="ConvertTo(Type)"/> or
/// <see cref="ConvertTo(Type, CultureInfo)"/> if passed <see cref="CultureInfo"/> is <c>null</c>.
/// </summary>
public CultureInfo Culture { get; }
/// <summary>
/// The provided <see cref="object"/>.
/// </summary>
public object RawValue { get; }
/// <summary>
/// Converts <see cref="RawValue"/> to the given <paramref name="type"/>. Uses <see cref="Culture"/> for
/// <see cref="TypeConverter"/> operations.
/// </summary>
/// <param name="type">The target <see cref="Type"/> of the conversion.</param>
/// <returns>
/// <see cref="RawValue"/> converted to the given <paramref name="type"/>. <c>null</c> if the conversion fails.
/// </returns>
public object ConvertTo(Type type)
{
return ConvertTo(type, culture: null);
}
/// <summary>
/// Converts <see cref="RawValue"/> to the given <paramref name="type"/> using the given
/// <paramref name="culture"/>.
/// </summary>
/// <param name="type">The target <see cref="Type"/> of the conversion.</param>
/// <param name="culture">
/// The <see cref="CultureInfo"/> to use for <see cref="TypeConverter"/> operations. Uses
/// <see cref="Culture"/> if this parameter is <c>null</c>.
/// </param>
/// <returns>
/// <see cref="RawValue"/> converted to the given <paramref name="type"/> using the given
/// <paramref name="culture"/>. <c>null</c> if the conversion fails.
/// </returns>
public virtual object ConvertTo([NotNull] Type type, CultureInfo culture)
{
var value = RawValue;
if (value == null) if (value == null)
{ {
// treat null route parameters as though they were the default value for the type Value = null;
return type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : Values = None.Values;
null;
} }
else
if (value.GetType().IsAssignableFrom(type))
{ {
return value; Value = value;
Values = null;
} }
var cultureToUse = culture ?? Culture; Culture = culture ?? _invariantCulture;
return UnwrapPossibleArrayType(cultureToUse, value, type);
} }
private object UnwrapPossibleArrayType(CultureInfo culture, object value, Type destinationType) /// <summary>
/// Creates a new <see cref="ValueProviderResult"/> using <see cref="CultureInfo.InvariantCulture"/>.
/// </summary>
/// <param name="values">The submitted values.</param>
public ValueProviderResult(string[] values)
: this(values, _invariantCulture)
{ {
// array conversion results in four cases, as below }
var valueAsArray = value as Array;
if (destinationType.IsArray) /// <summary>
/// Creates a new <see cref="ValueProviderResult"/>.
/// </summary>
/// <param name="values">The submitted values.</param>
/// <param name="culture">The <see cref="CultureInfo"/> associated with these values.</param>
public ValueProviderResult(string[] values, CultureInfo culture)
{
if (values == null)
{ {
var destinationElementType = destinationType.GetElementType(); Value = null;
if (valueAsArray != null) Values = None.Values;
{
// case 1: both destination + source type are arrays, so convert each element
var converted = (IList)Array.CreateInstance(destinationElementType, valueAsArray.Length);
for (var i = 0; i < valueAsArray.Length; i++)
{
converted[i] = ConvertSimpleType(culture, valueAsArray.GetValue(i), destinationElementType);
}
return converted;
}
else
{
// case 2: destination type is array but source is single element, so wrap element in
// array + convert
var element = ConvertSimpleType(culture, value, destinationElementType);
var converted = (IList)Array.CreateInstance(destinationElementType, 1);
converted[0] = element;
return converted;
}
} }
else if (valueAsArray != null) else
{ {
// case 3: destination type is single element but source is array, so extract first element + convert Value = null;
if (valueAsArray.Length > 0) Values = values;
}
Culture = culture;
}
/// <summary>
/// Gets or sets the <see cref="CultureInfo"/> associated with the values.
/// </summary>
public CultureInfo Culture { get; private set; }
/// <summary>
/// Gets or sets a single value. Will be <c>null</c> if multiple values are present.
/// </summary>
public string Value { get; private set; }
/// <summary>
/// Gets or sets an array of values. Will be <c>null</c> if only a single value was provided.
/// </summary>
public string[] Values { get; private set; }
/// <summary>
/// Gets the first value based on the order values were provided in the request. Use <see cref="FirstValue"/>
/// to get a single value for processing regarless of whether a single or multiple values were provided
/// in the request.
/// </summary>
public string FirstValue
{
get
{
if (Value != null)
{ {
value = valueAsArray.GetValue(0); return Value;
return ConvertSimpleType(culture, value, destinationType); }
else if (Values != null && Values.Length > 0)
{
return Values[0];
} }
else else
{ {
// case 3(a): source is empty array, so can't perform conversion
return null; return null;
} }
} }
// case 4: both destination + source type are single elements, so convert
return ConvertSimpleType(culture, value, destinationType);
} }
private object ConvertSimpleType(CultureInfo culture, object value, Type destinationType) /// <summary>
/// Gets the number of submitted values.
/// </summary>
public int Length
{ {
if (value == null || value.GetType().IsAssignableFrom(destinationType)) get
{ {
return value; if (Values != null)
}
// In case of a Nullable object, we try again with its underlying type.
destinationType = UnwrapNullableType(destinationType);
// if this is a user-input value but the user didn't type anything, return no value
var valueAsString = value as string;
if (valueAsString != null && string.IsNullOrWhiteSpace(valueAsString))
{
return null;
}
var converter = TypeDescriptor.GetConverter(destinationType);
var canConvertFrom = converter.CanConvertFrom(value.GetType());
if (!canConvertFrom)
{
converter = TypeDescriptor.GetConverter(value.GetType());
}
if (!(canConvertFrom || converter.CanConvertTo(destinationType)))
{
// EnumConverter cannot convert integer, so we verify manually
if (destinationType.GetTypeInfo().IsEnum &&
(value is int ||
value is uint ||
value is long ||
value is ulong ||
value is short ||
value is ushort ||
value is byte ||
value is sbyte))
{ {
return Enum.ToObject(destinationType, value); return Values.Length;
} }
else if (Value != null)
throw new InvalidOperationException(
Resources.FormatValueProviderResult_NoConverterExists(value.GetType(), destinationType));
}
try
{
return canConvertFrom
? converter.ConvertFrom(null, culture, value)
: converter.ConvertTo(null, culture, value, destinationType);
}
catch (Exception ex)
{
if (ex is FormatException)
{ {
throw ex; return 1;
} }
else else
{ {
// TypeConverter throws System.Exception wrapping the FormatException, return 0;
// so we throw the inner exception.
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
// this code is never reached because the previous line is throwing;
throw;
} }
} }
} }
private static Type UnwrapNullableType(Type destinationType) /// <inheritdoc />
public override bool Equals(object obj)
{ {
return Nullable.GetUnderlyingType(destinationType) ?? destinationType; var other = obj as ValueProviderResult?;
return other.HasValue ? Equals(other.Value) : false;
}
/// <inheritdoc />
public bool Equals(ValueProviderResult other)
{
if (Length != other.Length)
{
return false;
}
else
{
var x = (string[])this;
var y = (string[])other;
for (var i = 0; i < x.Length; i++)
{
if (!string.Equals(x[i], y[i], StringComparison.Ordinal))
{
return false;
}
}
return true;
}
}
/// <inheritdoc />
public override int GetHashCode()
{
return ((string)this)?.GetHashCode() ?? 0;
}
/// <inheritdoc />
public override string ToString()
{
return (string)this;
}
/// <summary>
/// Gets an <see cref="Enumerator"/> for this <see cref="ValueProviderResult"/>.
/// </summary>
/// <returns>An <see cref="Enumerator"/>.</returns>
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
/// <inheritdoc />
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
return GetEnumerator();
}
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Converts the provided <see cref="ValueProviderResult"/> into a comma-separated string containing all
/// submitted values.
/// </summary>
/// <param name="result">The <see cref="ValueProviderResult"/>.</param>
public static explicit operator string(ValueProviderResult result)
{
if (result.Values == null)
{
return result.Value;
}
else if (result.Values.Length == 0)
{
return null;
}
else if (result.Values.Length == 1)
{
return result.Values[0];
}
else
{
return string.Join(",", result.Values);
}
}
/// <summary>
/// Converts the provided <see cref="ValueProviderResult"/> into a an array of <see cref="string"/> containing
/// all submitted values.
/// </summary>
/// <param name="result">The <see cref="ValueProviderResult"/>.</param>
public static explicit operator string[](ValueProviderResult result)
{
if (result.Values != null)
{
return result.Values;
}
else if (result.Value != null)
{
return new string[] { result.Value };
}
else
{
return None.Values;
}
}
/// <summary>
/// Compares two <see cref="ValueProviderResult"/> objects for equality.
/// </summary>
/// <param name="x">A <see cref="ValueProviderResult"/>.</param>
/// <param name="y">A <see cref="ValueProviderResult"/>.</param>
/// <returns><c>true</c> if the values are equal, otherwise <c>false</c>.</returns>
public static bool operator ==(ValueProviderResult x, ValueProviderResult y)
{
return x.Equals(y);
}
/// <summary>
/// Compares two <see cref="ValueProviderResult"/> objects for inequality.
/// </summary>
/// <param name="x">A <see cref="ValueProviderResult"/>.</param>
/// <param name="y">A <see cref="ValueProviderResult"/>.</param>
/// <returns><c>false</c> if the values are equal, otherwise <c>true</c>.</returns>
public static bool operator !=(ValueProviderResult x, ValueProviderResult y)
{
return !x.Equals(y);
}
/// <summary>
/// An enumerator for <see cref="ValueProviderResult"/>.
/// </summary>
public struct Enumerator : IEnumerator<string>
{
private readonly ValueProviderResult _result;
private readonly int _length;
private int _index;
/// <summary>
/// Creates a new <see cref="Enumerator"/>.
/// </summary>
/// <param name="result">The <see cref="ValueProviderResult"/>.</param>
public Enumerator(ValueProviderResult result)
{
_result = result;
_index = -1;
_length = result.Length;
Current = null;
}
/// <inheritdoc />
public string Current { get; private set; }
/// <inheritdoc />
object IEnumerator.Current => Current;
/// <inheritdoc />
public void Dispose()
{
}
/// <inheritdoc />
public bool MoveNext()
{
++_index;
if (_index < _length)
{
if (_result.Values != null)
{
Debug.Assert(_index < _result.Values.Length);
Current = _result.Values[_index];
return true;
}
else if (_result.Value != null && _index == 0)
{
Current = _result.Value;
return true;
}
else
{
return false;
}
}
Current = null;
return false;
}
/// <inheritdoc />
public void Reset()
{
_index = -1;
}
} }
} }
} }

View File

@ -74,38 +74,6 @@ namespace Microsoft.AspNet.Mvc.Abstractions
return GetString("Validation_InvalidFieldCannotBeReset_ToSkipped"); return GetString("Validation_InvalidFieldCannotBeReset_ToSkipped");
} }
/// <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>
/// The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.
/// </summary>
internal static string ValueProviderResult_NoConverterExists
{
get { return GetString("ValueProviderResult_NoConverterExists"); }
}
/// <summary>
/// The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.
/// </summary>
internal static string FormatValueProviderResult_NoConverterExists(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("ValueProviderResult_NoConverterExists"), p0, p1);
}
/// <summary> /// <summary>
/// The maximum number of allowed model errors has been reached. /// The maximum number of allowed model errors has been reached.
/// </summary> /// </summary>

View File

@ -129,12 +129,6 @@
<data name="Validation_InvalidFieldCannotBeReset_ToSkipped" xml:space="preserve"> <data name="Validation_InvalidFieldCannotBeReset_ToSkipped" xml:space="preserve">
<value>A field previously marked invalid should not be marked skipped.</value> <value>A field previously marked invalid should not be marked skipped.</value>
</data> </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">
<value>The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.</value>
</data>
<data name="ModelStateDictionary_MaxModelStateErrors" xml:space="preserve"> <data name="ModelStateDictionary_MaxModelStateErrors" xml:space="preserve">
<value>The maximum number of allowed model errors has been reached.</value> <value>The maximum number of allowed model errors has been reached.</value>
</data> </data>

View File

@ -58,6 +58,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var previousCount = bindingContext.ModelState.ErrorCount; var previousCount = bindingContext.ModelState.ErrorCount;
var model = await formatter.ReadAsync(formatterContext); var model = await formatter.ReadAsync(formatterContext);
bindingContext.ModelState.SetModelValue(modelBindingKey, rawValue: model, attemptedValue: null);
if (bindingContext.ModelState.ErrorCount != previousCount) if (bindingContext.ModelState.ErrorCount != previousCount)
{ {
// Formatter added an error. Do not use the model it returned. As above, tell the model binding // Formatter added an error. Do not use the model it returned. As above, tell the model binding
@ -65,9 +67,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return new ModelBindingResult(modelBindingKey); return new ModelBindingResult(modelBindingKey);
} }
var valueProviderResult = new ValueProviderResult(rawValue: model);
bindingContext.ModelState.SetModelValue(modelBindingKey, valueProviderResult);
var validationNode = new ModelValidationNode(modelBindingKey, bindingContext.ModelMetadata, model) var validationNode = new ModelValidationNode(modelBindingKey, bindingContext.ModelMetadata, model)
{ {
ValidateAllProperties = true ValidateAllProperties = true

View File

@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Check for missing data case 1: There was no <input ... /> element containing this data. // Check for missing data case 1: There was no <input ... /> element containing this data.
var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName); var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName);
if (valueProviderResult == null) if (valueProviderResult == ValueProviderResult.None)
{ {
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false); return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
} }
@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
// Check for missing data case 2: There was an <input ... /> element but it was left blank. // Check for missing data case 2: There was an <input ... /> element but it was left blank.
var value = valueProviderResult.AttemptedValue; var value = valueProviderResult.FirstValue;
if (string.IsNullOrEmpty(value)) if (string.IsNullOrEmpty(value))
{ {
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false); return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);

View File

@ -56,31 +56,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName); var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName);
CollectionResult result; CollectionResult result;
if (valueProviderResult == null) if (valueProviderResult == ValueProviderResult.None)
{ {
result = await BindComplexCollection(bindingContext); result = await BindComplexCollection(bindingContext);
} }
else else
{ {
if (valueProviderResult.RawValue == null) result = await BindSimpleCollection(bindingContext, valueProviderResult);
{
// Value exists but is null. Handle similarly to fallback case above. This avoids a
// ModelBindingResult with IsModelSet = true but ValidationNode = null.
model = bindingContext.Model ?? CreateEmptyCollection(bindingContext.ModelType);
var validationNode =
new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model);
return new ModelBindingResult(
model,
bindingContext.ModelName,
isModelSet: true,
validationNode: validationNode);
}
result = await BindSimpleCollection(
bindingContext,
valueProviderResult.RawValue,
valueProviderResult.Culture);
} }
var boundCollection = result.Model; var boundCollection = result.Model;
@ -94,6 +76,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
CopyToModel(model, boundCollection); CopyToModel(model, boundCollection);
} }
if (valueProviderResult != ValueProviderResult.None)
{
// If we did simple binding, then modelstate should be updated to reflect what we bound for ModelName.
// If we did complex binding, there will already be an entry for each index.
bindingContext.ModelState.SetModelValue(
bindingContext.ModelName,
valueProviderResult);
}
return new ModelBindingResult( return new ModelBindingResult(
model, model,
bindingContext.ModelName, bindingContext.ModelName,
@ -147,8 +138,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Internal for testing. // Internal for testing.
internal async Task<CollectionResult> BindSimpleCollection( internal async Task<CollectionResult> BindSimpleCollection(
ModelBindingContext bindingContext, ModelBindingContext bindingContext,
object rawValue, ValueProviderResult values)
CultureInfo culture)
{ {
var boundCollection = new List<TElement>(); var boundCollection = new List<TElement>();
@ -159,8 +149,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
bindingContext.ModelName, bindingContext.ModelName,
bindingContext.ModelMetadata, bindingContext.ModelMetadata,
boundCollection); boundCollection);
var rawValueArray = RawValueToObjectArray(rawValue); foreach (var value in values)
foreach (var rawValueElement in rawValueArray)
{ {
var innerBindingContext = ModelBindingContext.GetChildModelBindingContext( var innerBindingContext = ModelBindingContext.GetChildModelBindingContext(
bindingContext, bindingContext,
@ -169,7 +158,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
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
new ElementalValueProvider(bindingContext.ModelName, rawValueElement, culture), new ElementalValueProvider(bindingContext.ModelName, value, values.Culture),
bindingContext.ValueProvider bindingContext.ValueProvider
}; };
@ -183,8 +172,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
validationNode.ChildNodes.Add(result.ValidationNode); validationNode.ChildNodes.Add(result.ValidationNode);
} }
boundCollection.Add(ModelBindingHelper.CastOrDefault<TElement>(boundValue));
} }
boundCollection.Add(ModelBindingHelper.CastOrDefault<TElement>(boundValue));
} }
return new CollectionResult return new CollectionResult
@ -364,7 +354,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
IEnumerable<string> indexNames = null; IEnumerable<string> indexNames = null;
if (valueProviderResult != null) if (valueProviderResult != null)
{ {
var indexes = (string[])valueProviderResult.ConvertTo(typeof(string[])); var indexes = (string[])valueProviderResult;
if (indexes != null && indexes.Length > 0) if (indexes != null && indexes.Length > 0)
{ {
indexNames = indexes; indexNames = indexes;

View File

@ -86,12 +86,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
var valueProvider = Items[i]; var valueProvider = Items[i];
var result = await valueProvider.GetValueAsync(key); var result = await valueProvider.GetValueAsync(key);
if (result != null) if (result != ValueProviderResult.None)
{ {
return result; return result;
} }
} }
return null;
return ValueProviderResult.None;
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -30,21 +30,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
_values = values; _values = values;
} }
protected PrefixContainer PrefixContainer
{
get
{
if (_prefixContainer == null)
{
_prefixContainer = new PrefixContainer(_values.Keys);
}
return _prefixContainer;
}
}
/// <inheritdoc /> /// <inheritdoc />
public override Task<bool> ContainsPrefixAsync(string key) public override Task<bool> ContainsPrefixAsync(string key)
{ {
var prefixContainer = GetOrCreatePrefixContainer(); return Task.FromResult(PrefixContainer.ContainsPrefix(key));
return Task.FromResult(prefixContainer.ContainsPrefix(key));
}
private PrefixContainer GetOrCreatePrefixContainer()
{
if (_prefixContainer == null)
{
_prefixContainer = new PrefixContainer(_values.Keys);
}
return _prefixContainer;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -54,12 +56,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
ValueProviderResult result; ValueProviderResult result;
if (_values.TryGetValue(key, out value)) if (_values.TryGetValue(key, out value))
{ {
var attemptedValue = value != null ? value.ToString() : null; var stringValue = value as string ?? value?.ToString() ?? string.Empty;
result = new ValueProviderResult(value, attemptedValue, CultureInfo.InvariantCulture); result = new ValueProviderResult(stringValue, CultureInfo.InvariantCulture);
} }
else else
{ {
result = null; result = ValueProviderResult.None;
} }
return Task.FromResult(result); return Task.FromResult(result);

View File

@ -65,15 +65,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var modelBinder = bindingContext.OperationBindingContext.ModelBinder; var modelBinder = bindingContext.OperationBindingContext.ModelBinder;
var validationNode = result.ValidationNode; var validationNode = result.ValidationNode;
foreach (var key in keys) foreach (var kvp in keys)
{ {
var dictionaryKey = ConvertFromString(key.Key); // Use InvariantCulture to convert the key since ExpressionHelper.GetExpressionText() would use
valueBindingContext.ModelName = key.Value; // that culture when rendering a form.
var convertedKey = ModelBindingHelper.ConvertTo<TKey>(kvp.Key, culture: null);
valueBindingContext.ModelName = kvp.Value;
var valueResult = await modelBinder.BindModelAsync(valueBindingContext); var valueResult = await modelBinder.BindModelAsync(valueBindingContext);
// Always add an entry to the dictionary but validate only if binding was successful. // Always add an entry to the dictionary but validate only if binding was successful.
model[dictionaryKey] = ModelBindingHelper.CastOrDefault<TValue>(valueResult?.Model); model[convertedKey] = ModelBindingHelper.CastOrDefault<TValue>(valueResult?.Model);
if (valueResult != null && valueResult.IsModelSet) if (valueResult != null && valueResult.IsModelSet)
{ {
validationNode.ChildNodes.Add(valueResult.ValidationNode); validationNode.ChildNodes.Add(valueResult.ValidationNode);
@ -116,14 +119,5 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return CreateInstance(targetType); return CreateInstance(targetType);
} }
private static TKey ConvertFromString(string keyString)
{
// Use InvariantCulture to convert string since ExpressionHelper.GetExpressionText() used that culture.
var keyResult = new ValueProviderResult(keyString);
var keyObject = keyResult.ConvertTo(typeof(TKey));
return ModelBindingHelper.CastOrDefault<TKey>(keyObject);
}
} }
} }

View File

@ -7,33 +7,36 @@ using System.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.ModelBinding namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
// Represents a value provider that contains a single value. public class ElementalValueProvider : IValueProvider
internal sealed class ElementalValueProvider : IValueProvider
{ {
public ElementalValueProvider(string name, object rawValue, CultureInfo culture) public ElementalValueProvider(string key, string value, CultureInfo culture)
{ {
Name = name; Key = key;
RawValue = rawValue; Value = value;
Culture = culture; Culture = culture;
} }
public CultureInfo Culture { get; private set; } public CultureInfo Culture { get; }
public string Name { get; private set; } public string Key { get; }
public object RawValue { get; private set; } public string Value { get; }
public Task<bool> ContainsPrefixAsync(string prefix) public Task<bool> ContainsPrefixAsync(string prefix)
{ {
return Task.FromResult(PrefixContainer.IsPrefixMatch(prefix, Name)); return Task.FromResult(PrefixContainer.IsPrefixMatch(prefix, Key));
} }
public Task<ValueProviderResult> GetValueAsync(string key) public Task<ValueProviderResult> GetValueAsync(string key)
{ {
var result = string.Equals(key, Name, StringComparison.OrdinalIgnoreCase) ? if (string.Equals(key, Key, StringComparison.OrdinalIgnoreCase))
new ValueProviderResult(RawValue, Convert.ToString(RawValue, Culture), Culture) : {
null; return Task.FromResult(new ValueProviderResult(Value, Culture));
return Task.FromResult(result); }
else
{
return Task.FromResult(ValueProviderResult.None);
}
} }
} }
} }

View File

@ -48,8 +48,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
SuppressValidation = true, SuppressValidation = true,
}; };
var valueProviderResult = new ValueProviderResult(rawValue: value); bindingContext.ModelState.SetModelValue(
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); bindingContext.ModelName,
rawValue: null,
attemptedValue: null);
} }
return new ModelBindingResult( return new ModelBindingResult(

View File

@ -2,7 +2,7 @@
// 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.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Linq;
#if DNXCORE50 #if DNXCORE50
using System.Reflection; using System.Reflection;
#endif #endif
@ -61,9 +61,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
bindingContext.ModelMetadata, bindingContext.ModelMetadata,
model); model);
var attemptedValue = (model as string) ?? request.Headers.Get(headerName); bindingContext.ModelState.SetModelValue(
var valueProviderResult = new ValueProviderResult(model, attemptedValue, CultureInfo.InvariantCulture); bindingContext.ModelName,
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); request.Headers.GetCommaSeparatedValues(headerName).ToArray(),
request.Headers.Get(headerName));
} }
return Task.FromResult( return Task.FromResult(

View File

@ -73,16 +73,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
string[] values; string[] values;
if (dictionary.TryGetValue(key, out values) && values != null && values.Length > 0) if (dictionary.TryGetValue(key, out values) && values != null && values.Length > 0)
{ {
// Success. return new ValueProviderResult(values, Culture);
if (values.Length == 1)
{
return new ValueProviderResult(values[0], values[0], Culture);
}
return new ValueProviderResult(values, string.Join(",", values), Culture);
} }
return null; return ValueProviderResult.None;
} }
private async Task<IDictionary<string, string[]>> GetDictionary() private async Task<IDictionary<string, string[]>> GetDictionary()

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.Framework.Internal; using Microsoft.Framework.Internal;
@ -85,16 +86,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
ValueProviderResult result; ValueProviderResult result;
if (values == null) if (values == null)
{ {
result = null; result = ValueProviderResult.None;
}
else if (values.Count == 1)
{
var value = (string)values[0];
result = new ValueProviderResult(value, value, _culture);
} }
else else
{ {
result = new ValueProviderResult(values, _values.Get(key), _culture); result = new ValueProviderResult(values.ToArray(), _culture);
} }
return result; return result;

View File

@ -8,12 +8,10 @@ using Microsoft.AspNet.Mvc.Core;
namespace Microsoft.AspNet.Mvc.ModelBinding namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
public sealed class TypeConverterModelBinder : IModelBinder public class SimpleTypeModelBinder : IModelBinder
{ {
public async Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext) public async Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
{ {
ModelBindingHelper.ValidateBindingContext(bindingContext);
if (bindingContext.ModelMetadata.IsComplexType) if (bindingContext.ModelMetadata.IsComplexType)
{ {
// this type cannot be converted // this type cannot be converted
@ -21,38 +19,48 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
} }
var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName); var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName);
if (valueProviderResult == null) if (valueProviderResult == ValueProviderResult.None)
{ {
// no entry // no entry
return null; return null;
} }
object newModel;
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
try try
{ {
newModel = valueProviderResult.ConvertTo(bindingContext.ModelType); var model = valueProviderResult.ConvertTo(bindingContext.ModelType);
ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref newModel);
if (bindingContext.ModelType == typeof(string))
{
var modelAsString = model as string;
if (bindingContext.ModelMetadata.ConvertEmptyStringToNull &&
string.IsNullOrWhiteSpace(modelAsString))
{
model = null;
}
}
var isModelSet = true; var isModelSet = true;
// When converting newModel a null value may indicate a failed conversion for an otherwise required // When converting newModel a null value may indicate a failed conversion for an otherwise required
// model (can't set a ValueType to null). This detects if a null model value is acceptable given the // model (can't set a ValueType to null). This detects if a null model value is acceptable given the
// current bindingContext. If not, an error is logged. // current bindingContext. If not, an error is logged.
if (newModel == null && !AllowsNullValue(bindingContext.ModelType)) if (model == null && !AllowsNullValue(bindingContext.ModelType))
{ {
bindingContext.ModelState.TryAddModelError( bindingContext.ModelState.TryAddModelError(
bindingContext.ModelName, bindingContext.ModelName,
Resources.FormatCommon_ValueNotValidForProperty(newModel)); Resources.FormatCommon_ValueNotValidForProperty(model));
isModelSet = false; isModelSet = false;
} }
// Include a ModelValidationNode if binding succeeded. // Include a ModelValidationNode if binding succeeded.
var validationNode = isModelSet ? var validationNode = isModelSet ?
new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, newModel) : new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model) :
null; null;
return new ModelBindingResult(newModel, bindingContext.ModelName, isModelSet, validationNode); return new ModelBindingResult(model, bindingContext.ModelName, isModelSet, validationNode);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -1,67 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public sealed class TypeMatchModelBinder : IModelBinder
{
public async Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
{
var valueProviderResult = await GetCompatibleValueProviderResult(bindingContext);
if (valueProviderResult == null)
{
// conversion would have failed
return null;
}
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
var model = valueProviderResult.RawValue;
ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref model);
var validationNode = new ModelValidationNode(
bindingContext.ModelName,
bindingContext.ModelMetadata,
model);
return new ModelBindingResult(
model,
bindingContext.ModelName,
isModelSet: true,
validationNode: validationNode);
}
internal static async Task<ValueProviderResult> GetCompatibleValueProviderResult(ModelBindingContext context)
{
ModelBindingHelper.ValidateBindingContext(context);
var valueProviderResult = await context.ValueProvider.GetValueAsync(context.ModelName);
if (valueProviderResult == null)
{
return null; // the value doesn't exist
}
if (!IsCompatibleWith(context.ModelType, valueProviderResult.RawValue))
{
return null; // value is of incompatible type
}
return valueProviderResult;
}
private static bool IsCompatibleWith([NotNull] Type type, object value)
{
if (value == null)
{
return !type.GetTypeInfo().IsValueType || Nullable.GetUnderlyingType(type) != null;
}
else
{
return type.GetTypeInfo().IsAssignableFrom(value.GetType().GetTypeInfo());
}
}
}
}

View File

@ -0,0 +1,42 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
/// <summary>
/// Extensions methods for <see cref="ValueProviderResult"/>.
/// </summary>
public static class ValueProviderResultExtensions
{
/// <summary>
/// Attempts to convert the values in <paramref name="result"/> to the specified type.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> for conversion.</typeparam>
/// <param name="result">The <see cref="ValueProviderResult"/>.</param>
/// <returns>
/// The converted value, or the default value of <typeparamref name="T"/> if the value could not be converted.
/// </returns>
public static T ConvertTo<T>(this ValueProviderResult result)
{
var valueToConvert = (object)result.Values ?? (object)result.Value;
return ModelBindingHelper.ConvertTo<T>(valueToConvert, result.Culture);
}
/// <summary>
/// Attempts to convert the values in <paramref name="result"/> to the specified type.
/// </summary>
/// <param name="result">The <see cref="ValueProviderResult"/>.</param>
/// <param name="type">The <see cref="Type"/> for conversion.</param>
/// <returns>
/// The converted value, or the default value of <paramref name="type"/> if the value could not be converted.
/// </returns>
public static object ConvertTo(this ValueProviderResult result, [NotNull] Type type)
{
var valueToConvert = (object)result.Values ?? (object)result.Value;
return ModelBindingHelper.ConvertTo(valueToConvert, type, result.Culture);
}
}
}

View File

@ -2,10 +2,14 @@
// 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 System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Core;
@ -488,16 +492,6 @@ namespace Microsoft.AspNet.Mvc
return (model is TModel) ? (TModel)model : default(TModel); return (model is TModel) ? (TModel)model : default(TModel);
} }
internal static void ReplaceEmptyStringWithNull(ModelMetadata modelMetadata, ref object model)
{
if (model is string &&
modelMetadata.ConvertEmptyStringToNull &&
string.IsNullOrWhiteSpace(model as string))
{
model = null;
}
}
public static object ConvertValuesToCollectionType<T>(Type modelType, IList<T> values) public static object ConvertValuesToCollectionType<T>(Type modelType, IList<T> values)
{ {
// There's a limited set of collection types we can support here. // There's a limited set of collection types we can support here.
@ -539,5 +533,196 @@ namespace Microsoft.AspNet.Mvc
return null; return null;
} }
} }
/// <summary>
/// Converts the provided <paramref name="value"/> to a value of <see cref="Type"/> <typeparamref name="T"/>
/// using the <see cref="CultureInfo.InvariantCulture"/>.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> for conversion.</typeparam>
/// <param name="value">The value to convert."/></param>
/// <returns>
/// The converted value or the default value of <typeparamref name="T"/> if the value could not be converted.
/// </returns>
public static T ConvertTo<T>(object value)
{
return ConvertTo<T>(value, culture: null);
}
/// <summary>
/// Converts the provided <paramref name="value"/> to a value of <see cref="Type"/> <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> for conversion.</typeparam>
/// <param name="value">The value to convert."/></param>
/// <param name="culture">The <see cref="CultureInfo"/> for conversion.</param>
/// <returns>
/// The converted value or the default value of <typeparamref name="T"/> if the value could not be converted.
/// </returns>
public static T ConvertTo<T>(object value, CultureInfo culture)
{
var converted = ConvertTo(value, typeof(T), culture);
return converted == null ? default(T) : (T)converted;
}
/// <summary>
/// Converts the provided <paramref name="value"/> to a value of <see cref="Type"/> <param name="type"/>
/// using the <see cref="CultureInfo.InvariantCulture"/>.
/// </summary>
/// <param name="value">The value to convert."/></param>
/// <param name="type">The <see cref="Type"/> for conversion.</param>
/// <returns>
/// The converted value or <c>null</c> if the value could not be converted.
/// </returns>
public static object ConvertTo(object value, [NotNull] Type type)
{
return ConvertTo(value, type, culture: null);
}
/// <summary>
/// Converts the provided <paramref name="value"/> to a value of <see cref="Type"/> <paramref name="type"/>.
/// </summary>
/// <param name="value">The value to convert."/></param>
/// <param name="type">The <see cref="Type"/> for conversion.</param>
/// <param name="culture">The <see cref="CultureInfo"/> for conversion.</param>
/// <returns>
/// The converted value or <c>null</c> if the value could not be converted.
/// </returns>
public static object ConvertTo(object value, [NotNull] Type type, CultureInfo culture)
{
if (value == null)
{
// For value types, treat null values as though they were the default value for the type.
return type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : null;
}
if (value.GetType().IsAssignableFrom(type))
{
return value;
}
var cultureToUse = culture ?? CultureInfo.InvariantCulture;
return UnwrapPossibleArrayType(value, type, cultureToUse);
}
private static object UnwrapPossibleArrayType(object value, Type destinationType, CultureInfo culture)
{
// array conversion results in four cases, as below
var valueAsArray = value as Array;
if (destinationType.IsArray)
{
var destinationElementType = destinationType.GetElementType();
if (valueAsArray != null)
{
// case 1: both destination + source type are arrays, so convert each element
var converted = (IList)Array.CreateInstance(destinationElementType, valueAsArray.Length);
for (var i = 0; i < valueAsArray.Length; i++)
{
converted[i] = ConvertSimpleType(valueAsArray.GetValue(i), destinationElementType, culture);
}
return converted;
}
else
{
// case 2: destination type is array but source is single element, so wrap element in
// array + convert
var element = ConvertSimpleType(value, destinationElementType, culture);
var converted = (IList)Array.CreateInstance(destinationElementType, 1);
converted[0] = element;
return converted;
}
}
else if (valueAsArray != null)
{
// case 3: destination type is single element but source is array, so extract first element + convert
if (valueAsArray.Length > 0)
{
value = valueAsArray.GetValue(0);
return ConvertSimpleType(value, destinationType, culture);
}
else
{
// case 3(a): source is empty array, so can't perform conversion
return null;
}
}
// case 4: both destination + source type are single elements, so convert
return ConvertSimpleType(value, destinationType, culture);
}
private static object ConvertSimpleType(object value, Type destinationType, CultureInfo culture)
{
if (value == null || value.GetType().IsAssignableFrom(destinationType))
{
return value;
}
// In case of a Nullable object, we try again with its underlying type.
destinationType = UnwrapNullableType(destinationType);
// if this is a user-input value but the user didn't type anything, return no value
var valueAsString = value as string;
if (valueAsString != null && string.IsNullOrWhiteSpace(valueAsString))
{
return null;
}
var converter = TypeDescriptor.GetConverter(destinationType);
var canConvertFrom = converter.CanConvertFrom(value.GetType());
if (!canConvertFrom)
{
converter = TypeDescriptor.GetConverter(value.GetType());
}
if (!(canConvertFrom || converter.CanConvertTo(destinationType)))
{
// EnumConverter cannot convert integer, so we verify manually
if (destinationType.GetTypeInfo().IsEnum &&
(value is int ||
value is uint ||
value is long ||
value is ulong ||
value is short ||
value is ushort ||
value is byte ||
value is sbyte))
{
return Enum.ToObject(destinationType, value);
}
throw new InvalidOperationException(
Resources.FormatValueProviderResult_NoConverterExists(value.GetType(), destinationType));
}
try
{
return canConvertFrom
? converter.ConvertFrom(null, culture, value)
: converter.ConvertTo(null, culture, value, destinationType);
}
catch (FormatException)
{
throw;
}
catch (Exception ex)
{
if (ex.InnerException == null)
{
throw;
}
else
{
// TypeConverter throws System.Exception wrapping the FormatException,
// so we throw the inner exception.
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
// This code is never reached because the previous line will always throw.
throw;
}
}
}
private static Type UnwrapNullableType(Type destinationType)
{
return Nullable.GetUnderlyingType(destinationType) ?? destinationType;
}
} }
} }

View File

@ -28,8 +28,7 @@ namespace Microsoft.AspNet.Mvc
options.ModelBinders.Add(new ServicesModelBinder()); options.ModelBinders.Add(new ServicesModelBinder());
options.ModelBinders.Add(new BodyModelBinder()); options.ModelBinders.Add(new BodyModelBinder());
options.ModelBinders.Add(new HeaderModelBinder()); options.ModelBinders.Add(new HeaderModelBinder());
options.ModelBinders.Add(new TypeConverterModelBinder()); options.ModelBinders.Add(new SimpleTypeModelBinder());
options.ModelBinders.Add(new TypeMatchModelBinder());
options.ModelBinders.Add(new CancellationTokenModelBinder()); options.ModelBinders.Add(new CancellationTokenModelBinder());
options.ModelBinders.Add(new ByteArrayModelBinder()); options.ModelBinders.Add(new ByteArrayModelBinder());
options.ModelBinders.Add(new FormFileModelBinder()); options.ModelBinders.Add(new FormFileModelBinder());

View File

@ -1162,6 +1162,38 @@ namespace Microsoft.AspNet.Mvc.Core
return string.Format(CultureInfo.CurrentCulture, GetString("ValidatableObjectAdapter_IncompatibleType"), p0, 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>
/// The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.
/// </summary>
internal static string ValueProviderResult_NoConverterExists
{
get { return GetString("ValueProviderResult_NoConverterExists"); }
}
/// <summary>
/// The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.
/// </summary>
internal static string FormatValueProviderResult_NoConverterExists(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("ValueProviderResult_NoConverterExists"), p0, p1);
}
private static string GetString(string name, params string[] formatterNames) private static string GetString(string name, params string[] formatterNames)
{ {
var value = _resourceManager.GetString(name); var value = _resourceManager.GetString(name);

View File

@ -342,4 +342,10 @@
<data name="ValidatableObjectAdapter_IncompatibleType" xml:space="preserve"> <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> <value>The model object inside the metadata claimed to be compatible with '{0}', but was actually '{1}'.</value>
</data> </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">
<value>The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.</value>
</data>
</root> </root>

View File

@ -506,9 +506,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
viewContext.ViewData.ModelState.TryGetValue(fullName, out modelState); viewContext.ViewData.ModelState.TryGetValue(fullName, out modelState);
var value = string.Empty; var value = string.Empty;
if (modelState != null && modelState.Value != null) if (modelState != null && modelState.AttemptedValue != null)
{ {
value = modelState.Value.AttemptedValue; value = modelState.AttemptedValue;
} }
else if (modelExplorer.Model != null) else if (modelExplorer.Model != null)
{ {
@ -940,9 +940,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
internal static object GetModelStateValue(ViewContext viewContext, string key, Type destinationType) internal static object GetModelStateValue(ViewContext viewContext, string key, Type destinationType)
{ {
ModelState modelState; ModelState modelState;
if (viewContext.ViewData.ModelState.TryGetValue(key, out modelState) && modelState.Value != null) if (viewContext.ViewData.ModelState.TryGetValue(key, out modelState) && modelState.RawValue != null)
{ {
return modelState.Value.ConvertTo(destinationType, culture: null); return ModelBindingHelper.ConvertTo(modelState.RawValue, destinationType, culture: null);
} }
return null; return null;

View File

@ -24,8 +24,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
return string.Empty; return string.Empty;
} }
var attemptedValue = (modelState.Value != null) ? modelState.Value.AttemptedValue : "null"; var attemptedValue = modelState.AttemptedValue ?? "null";
return Resources.FormatCommon_ValueNotValidForProperty(attemptedValue); return Resources.FormatCommon_ValueNotValidForProperty(attemptedValue);
} }

View File

@ -18,7 +18,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var modelState = new ModelState var modelState = new ModelState
{ {
Value = GetValueProviderResult("value"),
ValidationState = validationState ValidationState = validationState
}; };
@ -40,7 +39,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var modelState = new ModelState var modelState = new ModelState
{ {
Value = GetValueProviderResult("value"),
ValidationState = ModelValidationState.Valid ValidationState = ModelValidationState.Valid
}; };
@ -63,7 +61,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var modelState = new ModelState var modelState = new ModelState
{ {
Value = GetValueProviderResult("value"),
ValidationState = ModelValidationState.Invalid ValidationState = ModelValidationState.Invalid
}; };
@ -89,7 +86,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var modelState = new ModelState var modelState = new ModelState
{ {
Value = GetValueProviderResult("value"),
ValidationState = validationState ValidationState = validationState
}; };
@ -126,7 +122,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var modelState = new ModelState var modelState = new ModelState
{ {
Value = GetValueProviderResult("value"),
ValidationState = ModelValidationState.Invalid ValidationState = ModelValidationState.Invalid
}; };
@ -148,10 +143,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
public void CopyConstructor_CopiesModelStateData() public void CopyConstructor_CopiesModelStateData()
{ {
// Arrange // Arrange
var modelState = new ModelState var modelState = new ModelState();
{
Value = GetValueProviderResult("value")
};
var source = new ModelStateDictionary var source = new ModelStateDictionary
{ {
{ "key", modelState } { "key", modelState }
@ -211,7 +203,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var oldDictionary = new ModelStateDictionary() var oldDictionary = new ModelStateDictionary()
{ {
{ "foo", new ModelState() { Value = GetValueProviderResult("bar", "bar") } } { "foo", new ModelState() { RawValue = "bar" } }
}; };
// Act // Act
@ -219,7 +211,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Assert // Assert
Assert.Single(newDictionary); Assert.Single(newDictionary);
Assert.Equal("bar", newDictionary["foo"].Value.ConvertTo(typeof(string))); Assert.Equal("bar", newDictionary["foo"].RawValue);
} }
[Fact] [Fact]
@ -238,7 +230,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
[Fact] [Fact]
public void GetValidationState_ReturnsValidationStateForKey_IgnoresChildren() public void GetValidationState_ReturnsValidationStateForKey_IgnoresChildren()
{ {
// Arrange // Arrange
var msd = new ModelStateDictionary(); var msd = new ModelStateDictionary();
msd.AddModelError("foo.bar", "error text"); msd.AddModelError("foo.bar", "error text");
@ -277,7 +269,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var validState = new ModelState var validState = new ModelState
{ {
Value = new ValueProviderResult(rawValue: null),
ValidationState = ModelValidationState.Valid ValidationState = ModelValidationState.Valid
}; };
var msd = new ModelStateDictionary var msd = new ModelStateDictionary
@ -316,7 +307,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var validState = new ModelState var validState = new ModelState
{ {
Value = new ValueProviderResult(rawValue: null),
ValidationState = ModelValidationState.Valid ValidationState = ModelValidationState.Valid
}; };
var msd = new ModelStateDictionary var msd = new ModelStateDictionary
@ -337,12 +327,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var errorState = new ModelState var errorState = new ModelState
{ {
Value = GetValueProviderResult("quux", "quux"),
ValidationState = ModelValidationState.Invalid ValidationState = ModelValidationState.Invalid
}; };
var validState = new ModelState var validState = new ModelState
{ {
Value = GetValueProviderResult("bar", "bar"),
ValidationState = ModelValidationState.Valid ValidationState = ModelValidationState.Valid
}; };
errorState.Errors.Add("some error"); errorState.Errors.Add("some error");
@ -370,13 +358,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ "foo", new ModelState { "foo", new ModelState
{ {
ValidationState = ModelValidationState.Valid, ValidationState = ModelValidationState.Valid,
Value = GetValueProviderResult("bar", "bar")
} }
}, },
{ "baz", new ModelState { "baz", new ModelState
{ {
ValidationState = ModelValidationState.Skipped, ValidationState = ModelValidationState.Skipped,
Value = GetValueProviderResult("quux", "bar")
} }
} }
}; };
@ -396,12 +382,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var errorState = new ModelState var errorState = new ModelState
{ {
Value = GetValueProviderResult("quux", "quux"),
ValidationState = ModelValidationState.Invalid ValidationState = ModelValidationState.Invalid
}; };
var validState = new ModelState var validState = new ModelState
{ {
Value = GetValueProviderResult("bar", "bar"),
ValidationState = ModelValidationState.Valid ValidationState = ModelValidationState.Valid
}; };
errorState.Errors.Add("some error"); errorState.Errors.Add("some error");
@ -409,7 +393,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
{ "foo", validState }, { "foo", validState },
{ "baz", errorState }, { "baz", errorState },
{ "qux", new ModelState { Value = GetValueProviderResult() }} { "qux", new ModelState() }
}; };
// Act // Act
@ -457,14 +441,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var dictionary = new ModelStateDictionary(); var dictionary = new ModelStateDictionary();
// Act // Act
dictionary.SetModelValue("some key", GetValueProviderResult("some value", "some value")); dictionary.SetModelValue("some key", new string[] { "some value" }, "some value");
// Assert // Assert
Assert.Single(dictionary); Assert.Single(dictionary);
var modelState = dictionary["some key"]; var modelState = dictionary["some key"];
Assert.Empty(modelState.Errors); Assert.Empty(modelState.Errors);
Assert.Equal("some value", modelState.Value.ConvertTo(typeof(string))); Assert.Equal(new string[] { "some value" }, modelState.RawValue);
Assert.Equal("some value", modelState.AttemptedValue);
} }
[Fact] [Fact]
@ -476,7 +461,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var ex = new Exception(); var ex = new Exception();
// Act // Act
dictionary.SetModelValue("some key", GetValueProviderResult("some value", "some value")); dictionary.SetModelValue("some key", new string[] { "some value" }, "some value");
// Assert // Assert
Assert.Single(dictionary); Assert.Single(dictionary);
@ -484,7 +469,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
Assert.Single(modelState.Errors); Assert.Single(modelState.Errors);
Assert.Equal("some error", modelState.Errors[0].ErrorMessage); Assert.Equal("some error", modelState.Errors[0].ErrorMessage);
Assert.Equal("some value", modelState.Value.ConvertTo(typeof(string))); Assert.Equal(new string[] { "some value" }, modelState.RawValue);
Assert.Equal("some value", modelState.AttemptedValue);
} }
[Fact] [Fact]
@ -492,7 +478,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
// Arrange // Arrange
var dictionary = new ModelStateDictionary(); var dictionary = new ModelStateDictionary();
dictionary.SetModelValue("user.Name", GetValueProviderResult()); dictionary.SetModelValue("user.Name", new string[] { "some value" }, "some value");
// Act // Act
var validationState = dictionary.GetFieldValidationState("not-user"); var validationState = dictionary.GetFieldValidationState("not-user");
@ -507,7 +493,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var dictionary = new ModelStateDictionary(); var dictionary = new ModelStateDictionary();
dictionary["user.Address"] = new ModelState { ValidationState = ModelValidationState.Valid }; dictionary["user.Address"] = new ModelState { ValidationState = ModelValidationState.Valid };
dictionary.SetModelValue("user.Name", GetValueProviderResult()); dictionary.SetModelValue("user.Name", new string[] { "some value" }, "some value");
dictionary.AddModelError("user.Age", "Age is not a valid int"); dictionary.AddModelError("user.Age", "Age is not a valid int");
// Act // Act
@ -745,7 +731,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange // Arrange
var expected = "The value 'some value' is not valid for key."; var expected = "The value 'some value' is not valid for key.";
var dictionary = new ModelStateDictionary(); var dictionary = new ModelStateDictionary();
dictionary.SetModelValue("key", GetValueProviderResult()); dictionary.SetModelValue("key", new string[] { "some value" }, "some value");
// Act // Act
dictionary.TryAddModelError("key", new FormatException()); dictionary.TryAddModelError("key", new FormatException());
@ -760,7 +746,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
// Arrange // Arrange
var dictionary = new ModelStateDictionary(); var dictionary = new ModelStateDictionary();
dictionary.SetModelValue("key", GetValueProviderResult()); dictionary.SetModelValue("key", new string[] { "some value" }, "some value");
// Act // Act
dictionary.TryAddModelError("key", new InvalidOperationException()); dictionary.TryAddModelError("key", new InvalidOperationException());
@ -905,12 +891,5 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
Assert.Equal(0, dictionary["Property4"].Errors.Count); Assert.Equal(0, dictionary["Property4"].Errors.Count);
Assert.Equal(ModelValidationState.Unvalidated, dictionary["Property4"].ValidationState); Assert.Equal(ModelValidationState.Unvalidated, dictionary["Property4"].ValidationState);
} }
private static ValueProviderResult GetValueProviderResult(object rawValue = null, string attemptedValue = null)
{
return new ValueProviderResult(rawValue ?? "some value",
attemptedValue ?? "some value",
CultureInfo.InvariantCulture);
}
} }
} }

View File

@ -1,9 +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;
using System.Collections.Generic;
using System.Globalization;
using Xunit; using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding namespace Microsoft.AspNet.Mvc.ModelBinding
@ -11,563 +8,190 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
public class ValueProviderResultTest public class ValueProviderResultTest
{ {
[Fact] [Fact]
public void ConvertTo_ReturnsNullForReferenceTypes_WhenValueIsNull() public void Construct_With_NullString()
{ {
var valueProviderResult = new ValueProviderResult(rawValue: null); // Arrange & Act
var result = new ValueProviderResult((string)null);
var convertedValue = valueProviderResult.ConvertTo(typeof(string)); // Assert
Assert.Equal(0, result.Length);
Assert.Null(convertedValue); Assert.Null(result.Value);
Assert.Empty(result.Values);
Assert.Null(result.FirstValue);
Assert.Equal(ValueProviderResult.None, result);
Assert.Null((string)result);
Assert.Empty((string[])result);
} }
[Fact] [Fact]
public void ConvertTo_ReturnsDefaultForValueTypes_WhenValueIsNull() public void Construct_With_NullArray()
{ {
var valueProviderResult = new ValueProviderResult(rawValue: null); // Arrange & Act
var result = new ValueProviderResult((string[])null);
var convertedValue = valueProviderResult.ConvertTo(typeof(int)); // Assert
Assert.Equal(0, result.Length);
Assert.Equal(0, convertedValue); Assert.Null(result.Value);
Assert.Empty(result.Values);
Assert.Null(result.FirstValue);
Assert.Equal(ValueProviderResult.None, result);
Assert.Null((string)result);
Assert.Empty((string[])result);
} }
[Fact] [Fact]
public void ConvertToCanConvertArraysToSingleElements() public void Construct_With_None()
{ {
// Arrange // Arrange & Act
var valueProviderResult = new ValueProviderResult( var result = ValueProviderResult.None;
new int[] { 1, 20, 42 },
string.Empty,
CultureInfo.InvariantCulture);
// Act
var converted = (string)valueProviderResult.ConvertTo(typeof(string));
// Assert // Assert
Assert.Equal("1", converted); Assert.Equal(0, result.Length);
Assert.Null(result.Value);
Assert.Empty(result.Values);
Assert.Null(result.FirstValue);
Assert.Equal(ValueProviderResult.None, result);
Assert.Null((string)result);
Assert.Empty((string[])result);
} }
[Fact] [Fact]
public void ConvertToCanConvertSingleElementsToArrays() public void Construct_With_String()
{ {
// Arrange // Arrange & Act
var valueProviderResult = new ValueProviderResult(42, string.Empty, CultureInfo.InvariantCulture); var result = new ValueProviderResult("Hi There");
// Act
var converted = (string[])valueProviderResult.ConvertTo(typeof(string[]));
// Assert // Assert
Assert.NotNull(converted); Assert.Equal(1, result.Length);
var result = Assert.Single(converted); Assert.Equal("Hi There", result.Value);
Assert.Equal("42", result); Assert.Null(result.Values);
Assert.Equal("Hi There", result.FirstValue);
Assert.NotEqual(ValueProviderResult.None, result);
Assert.Equal("Hi There", (string)result);
Assert.Equal(new string[] { "Hi There" }, (string[])result);
} }
[Fact] [Fact]
public void ConvertToCanConvertSingleElementsToSingleElements() public void Construct_With_Array()
{ {
// Arrange // Arrange & Act
var valueProviderResult = new ValueProviderResult(42, string.Empty, CultureInfo.InvariantCulture); var result = new ValueProviderResult(new string[] { "Hi", "There" });
// Act
var converted = (string)valueProviderResult.ConvertTo(typeof(string));
// Assert // Assert
Assert.NotNull(converted);
Assert.Equal("42", converted);
}
[Fact]
public void ConvertingNullStringToNullableIntReturnsNull()
{
// Arrange
object original = null;
var valueProviderResult = new ValueProviderResult(original, string.Empty, CultureInfo.InvariantCulture);
// Act
var returned = (int?)valueProviderResult.ConvertTo(typeof(int?));
// Assert
Assert.Equal(returned, null);
}
[Fact]
public void ConvertingWhiteSpaceStringToNullableIntReturnsNull()
{
// Arrange
var original = " ";
var valueProviderResult = new ValueProviderResult(original, string.Empty, CultureInfo.InvariantCulture);
// Act
var returned = (int?)valueProviderResult.ConvertTo(typeof(int?));
// Assert
Assert.Equal(returned, null);
}
[Fact]
public void ConvertToReturnsNullIfArrayElementValueIsNull()
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: new string[] { null });
// Act
var outValue = valueProviderResult.ConvertTo(typeof(int));
// Assert
Assert.Null(outValue);
}
[Fact]
public void ConvertToReturnsNullIfTryingToConvertEmptyArrayToSingleElement()
{
// Arrange
var valueProviderResult = new ValueProviderResult(new int[0], string.Empty, CultureInfo.InvariantCulture);
// Act
var outValue = valueProviderResult.ConvertTo(typeof(int));
// Assert
Assert.Null(outValue);
}
[Theory]
[InlineData("")]
[InlineData(" \t \r\n ")]
public void ConvertToReturnsNullIfTrimmedValueIsEmptyString(object value)
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: value);
// Act
var outValue = valueProviderResult.ConvertTo(typeof(int));
// Assert
Assert.Null(outValue);
}
[Fact]
public void ConvertToReturnsNullIfTrimmedValueIsEmptyString()
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: null);
// Act
var outValue = valueProviderResult.ConvertTo(typeof(int[]));
// Assert
Assert.Null(outValue);
}
[Fact]
public void ConvertToReturnsValueIfArrayElementIsIntegerAndDestinationTypeIsEnum()
{
// Arrange
var result = new ValueProviderResult(rawValue: new object[] { 1 });
// Act
var outValue = result.ConvertTo(typeof(IntEnum));
// Assert
Assert.Equal(outValue, IntEnum.Value1);
}
[Theory]
[InlineData(1, typeof(IntEnum), IntEnum.Value1)]
[InlineData(1L, typeof(LongEnum), LongEnum.Value1)]
[InlineData(long.MaxValue, typeof(LongEnum), LongEnum.MaxValue)]
[InlineData(1U, typeof(UnsignedIntEnum), UnsignedIntEnum.Value1)]
[InlineData(1UL, typeof(IntEnum), IntEnum.Value1)]
[InlineData((byte)1, typeof(ByteEnum), ByteEnum.Value1)]
[InlineData(byte.MaxValue, typeof(ByteEnum), ByteEnum.MaxValue)]
[InlineData((sbyte)1, typeof(ByteEnum), ByteEnum.Value1)]
[InlineData((short)1, typeof(IntEnum), IntEnum.Value1)]
[InlineData((ushort)1, typeof(IntEnum), IntEnum.Value1)]
[InlineData(int.MaxValue, typeof(IntEnum?), IntEnum.MaxValue)]
[InlineData(null, typeof(IntEnum?), null)]
[InlineData(1L, typeof(LongEnum?), LongEnum.Value1)]
[InlineData(null, typeof(LongEnum?), null)]
[InlineData(uint.MaxValue, typeof(UnsignedIntEnum?), UnsignedIntEnum.MaxValue)]
[InlineData((byte)1, typeof(ByteEnum?), ByteEnum.Value1)]
[InlineData(null, typeof(ByteEnum?), null)]
[InlineData((ushort)1, typeof(LongEnum?), LongEnum.Value1)]
public void ConvertToReturnsValueIfArrayElementIsAnyIntegerTypeAndDestinationTypeIsEnum(
object input,
Type enumType,
object expected)
{
// Arrange
var result = new ValueProviderResult(rawValue: new object[] { input });
// Act
var outValue = result.ConvertTo(enumType);
// Assert
Assert.Equal(expected, outValue);
}
[Fact]
public void ConvertToReturnsValueIfArrayElementIsStringValueAndDestinationTypeIsEnum()
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: new object[] { "1" });
// Act
var outValue = valueProviderResult.ConvertTo(typeof(IntEnum));
// Assert
Assert.Equal(outValue, IntEnum.Value1);
}
[Fact]
public void ConvertToReturnsValueIfArrayElementIsStringKeyAndDestinationTypeIsEnum()
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: new object[] { "Value1" });
// Act
var outValue = valueProviderResult.ConvertTo(typeof(IntEnum));
// Assert
Assert.Equal(outValue, IntEnum.Value1);
}
[Fact]
public void ConvertToReturnsValueIfElementIsStringAndDestinationIsNullableInteger()
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: "12");
// Act
var outValue = valueProviderResult.ConvertTo(typeof(int?));
// Assert
Assert.Equal(12, outValue);
}
[Fact]
public void ConvertToReturnsValueIfElementIsStringAndDestinationIsNullableDouble()
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: "12.5");
// Act
var outValue = valueProviderResult.ConvertTo(typeof(double?));
// Assert
Assert.Equal(12.5, outValue);
}
[Fact]
public void ConvertToReturnsValueIfElementIsDecimalAndDestinationIsNullableInteger()
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: 12M);
// Act
var outValue = valueProviderResult.ConvertTo(typeof(int?));
// Assert
Assert.Equal(12, outValue);
}
[Fact]
public void ConvertToReturnsValueIfElementIsDecimalAndDestinationIsNullableDouble()
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: 12.5M);
// Act
var outValue = valueProviderResult.ConvertTo(typeof(double?));
// Assert
Assert.Equal(12.5, outValue);
}
[Fact]
public void ConvertToReturnsValueIfElementIsDecimalDoubleAndDestinationIsNullableInteger()
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: 12.5M);
// Act
var outValue = valueProviderResult.ConvertTo(typeof(int?));
// Assert
Assert.Equal(12, outValue);
}
[Fact]
public void ConvertToReturnsValueIfElementIsDecimalDoubleAndDestinationIsNullableLong()
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: 12.5M);
// Act
var outValue = valueProviderResult.ConvertTo(typeof(long?));
// Assert
Assert.Equal(12L, outValue);
}
[Fact]
public void ConvertToReturnsValueIfArrayElementInstanceOfDestinationType()
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: new object[] { "some string" });
// Act
var outValue = valueProviderResult.ConvertTo(typeof(string));
// Assert
Assert.Equal("some string", outValue);
}
[Theory]
[InlineData(new object[] { new[] { 1, 0 } })]
[InlineData(new object[] { new[] { "Value1", "Value0" } })]
[InlineData(new object[] { new[] { "Value1", "value0" } })]
public void ConvertTo_ConvertsEnumArrays(object value)
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: value);
// Act
var outValue = valueProviderResult.ConvertTo(typeof(IntEnum[]));
// Assert
var result = Assert.IsType<IntEnum[]>(outValue);
Assert.Equal(2, result.Length); Assert.Equal(2, result.Length);
Assert.Equal(IntEnum.Value1, result[0]); Assert.Null(result.Value);
Assert.Equal(IntEnum.Value0, result[1]); Assert.Equal(new string[] { "Hi", "There" }, result.Values);
} Assert.Equal("Hi", result.FirstValue);
Assert.NotEqual(ValueProviderResult.None, result);
[Theory] Assert.Equal("Hi,There", (string)result);
[InlineData(new object[] { new[] { 1, 2 }, new[] { FlagsEnum.Value1, FlagsEnum.Value2 } })] Assert.Equal(new string[] { "Hi", "There" }, (string[])result);
[InlineData(new object[] { new[] { "Value1", "Value2" }, new[] { FlagsEnum.Value1, FlagsEnum.Value2 } })]
[InlineData(new object[] { new[] { 5, 2 }, new[] { FlagsEnum.Value1 | FlagsEnum.Value4, FlagsEnum.Value2 } })]
public void ConvertTo_ConvertsFlagsEnumArrays(object value, FlagsEnum[] expected)
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: value);
// Act
var outValue = valueProviderResult.ConvertTo(typeof(FlagsEnum[]));
// Assert
var result = Assert.IsType<FlagsEnum[]>(outValue);
Assert.Equal(2, result.Length);
Assert.Equal(expected[0], result[0]);
Assert.Equal(expected[1], result[1]);
} }
[Fact] [Fact]
public void ConvertToReturnsValueIfInstanceOfDestinationType() public void Enumerator_WithString()
{ {
// Arrange // Arrange
var original = new[] { "some string" }; var result = new ValueProviderResult("Hi There");
var valueProviderResult = new ValueProviderResult(rawValue: original);
// Act
var outValue = valueProviderResult.ConvertTo(typeof(string[]));
// Assert
Assert.Same(original, outValue);
}
[Theory]
[InlineData(typeof(int))]
[InlineData(typeof(double?))]
[InlineData(typeof(IntEnum?))]
public void ConvertToThrowsIfConverterThrows(Type destinationType)
{
// Arrange
var valueProviderResult = new ValueProviderResult(rawValue: "this-is-not-a-valid-value");
// Act & Assert // Act & Assert
var ex = Assert.Throws(typeof(FormatException), () => valueProviderResult.ConvertTo(destinationType)); Assert.Equal<string>(new string[] { "Hi There", }, result);
} }
[Fact] [Fact]
public void ConvertToThrowsIfNoConverterExists() public void Enumerator_WithArray()
{ {
// Arrange // Arrange
var valueProviderResult = new ValueProviderResult(rawValue: "x"); var result = new ValueProviderResult(new string[] { "Hi", "There" });
var destinationType = typeof(MyClassWithoutConverter);
// Act & Assert // Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => valueProviderResult.ConvertTo(destinationType)); Assert.Equal<string>(new string[] { "Hi", "There" }, result);
Assert.Equal("The parameter conversion from type 'System.String' to type " +
"'Microsoft.AspNet.Mvc.ModelBinding.ValueProviderResultTest+MyClassWithoutConverter' " +
"failed because no type converter can convert between these types.",
ex.Message);
} }
[Fact] public static TheoryData<ValueProviderResult, ValueProviderResult, bool> EqualsData
public void ConvertToUsesProvidedCulture()
{
// Arrange
var original = "12,5";
var valueProviderResult = new ValueProviderResult(
rawValue: original,
attemptedValue: null,
culture: new CultureInfo("en-GB"));
var frCulture = new CultureInfo("fr-FR");
// Act
var cultureResult = valueProviderResult.ConvertTo(typeof(decimal), frCulture);
// Assert
Assert.Equal(12.5M, cultureResult);
Assert.Throws<FormatException>(() => valueProviderResult.ConvertTo(typeof(decimal)));
}
[Fact]
public void CulturePropertyDefaultsToInvariantCulture()
{
// Arrange
var result = new ValueProviderResult(rawValue: null, attemptedValue: null, culture: null);
// Act & assert
Assert.Same(CultureInfo.InvariantCulture, result.Culture);
}
[Theory]
[MemberData(nameof(IntrinsicConversionData))]
public void ConvertToCanConvertIntrinsics<T>(object initialValue, T expectedValue)
{
// Arrange
var result = new ValueProviderResult(initialValue, string.Empty, CultureInfo.InvariantCulture);
// Act & Assert
Assert.Equal(expectedValue, result.ConvertTo(typeof(T)));
}
public static IEnumerable<object[]> IntrinsicConversionData
{ {
get get
{ {
yield return new object[] { 42, 42L }; return new TheoryData<ValueProviderResult, ValueProviderResult, bool>()
yield return new object[] { 42, (short)42 };
yield return new object[] { 42, (float)42.0 };
yield return new object[] { 42, (double)42.0 };
yield return new object[] { 42M, 42 };
yield return new object[] { 42L, 42 };
yield return new object[] { 42, (byte)42 };
yield return new object[] { (short)42, 42 };
yield return new object[] { (float)42.0, 42 };
yield return new object[] { (double)42.0, 42 };
yield return new object[] { (byte)42, 42 };
yield return new object[] { "2008-01-01", new DateTime(2008, 01, 01) };
yield return new object[] { "00:00:20", TimeSpan.FromSeconds(20) };
yield return new object[]
{ {
"c6687d3a-51f9-4159-8771-a66d2b7d7038", {
Guid.Parse("c6687d3a-51f9-4159-8771-a66d2b7d7038") new ValueProviderResult("Hi"),
new ValueProviderResult("Hi"),
true
},
{
new ValueProviderResult("Hi"),
new ValueProviderResult(new string[] { "Hi"}),
true
},
{
new ValueProviderResult(new string[] { "Hi"}),
new ValueProviderResult("Hi"),
true
},
{
new ValueProviderResult(new string[] { "Hi"}),
new ValueProviderResult(new string[] { "Hi"}),
true
},
{
new ValueProviderResult(new string[] { "Hi", "There"}),
new ValueProviderResult(new string[] { "Hi", "There"}),
true
},
{
new ValueProviderResult("Hi,There"),
new ValueProviderResult(new string[] { "Hi", "There"}),
false
},
{
new ValueProviderResult(new string[] { "Hi", string.Empty }),
new ValueProviderResult(new string[] { "Hi", "There"}),
false
},
{
new ValueProviderResult(new string[] { "Hi", "There" }),
new ValueProviderResult(new string[] { "Hi", "ThEre"}),
false
},
{
new ValueProviderResult(new string[] { "Hi", }),
new ValueProviderResult(new string[] { "Hi", string.Empty }),
false
},
{
new ValueProviderResult(),
new ValueProviderResult((string)null),
true
},
{
new ValueProviderResult(),
new ValueProviderResult("hi"),
false
},
}; };
} }
} }
[Theory] [Theory]
[InlineData(typeof(TimeSpan))] [MemberData(nameof(EqualsData))]
[InlineData(typeof(DateTime))] public void Operator_Equals(ValueProviderResult x, ValueProviderResult y, bool expected)
[InlineData(typeof(DateTimeOffset))]
[InlineData(typeof(Guid))]
[InlineData(typeof(IntEnum))]
public void ConvertTo_Throws_IfValueIsNotStringData(Type destinationType)
{ {
// Arrange // Arrange
var result = new ValueProviderResult( var result = x == y;
new MyClassWithoutConverter(),
string.Empty,
CultureInfo.InvariantCulture);
// Act // Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => result.ConvertTo(destinationType)); Assert.Equal(expected, result);
// Assert
var expectedMessage = string.Format("The parameter conversion from type '{0}' to type '{1}' " +
"failed because no type converter can convert between these types.",
typeof(MyClassWithoutConverter), destinationType);
Assert.Equal(expectedMessage, ex.Message);
}
[Fact]
public void ConvertTo_Throws_IfDestinationTypeIsNotConvertible()
{
// Arrange
var value = "Hello world";
var destinationType = typeof(MyClassWithoutConverter);
var result = new ValueProviderResult(value, string.Empty, CultureInfo.InvariantCulture);
// Act
var ex = Assert.Throws<InvalidOperationException>(() => result.ConvertTo(destinationType));
// Assert
var expectedMessage = string.Format("The parameter conversion from type '{0}' to type '{1}' " +
"failed because no type converter can convert between these types.",
value.GetType(), typeof(MyClassWithoutConverter));
Assert.Equal(expectedMessage, ex.Message);
} }
[Theory] [Theory]
[InlineData(new object[] { 2, FlagsEnum.Value2 })] [MemberData(nameof(EqualsData))]
[InlineData(new object[] { 5, FlagsEnum.Value1 | FlagsEnum.Value4 })] public void Operator_NotEquals(ValueProviderResult x, ValueProviderResult y, bool expected)
[InlineData(new object[] { 15, FlagsEnum.Value1 | FlagsEnum.Value2 | FlagsEnum.Value4 | FlagsEnum.Value8 })]
[InlineData(new object[] { 16, (FlagsEnum)16 })]
[InlineData(new object[] { 0, (FlagsEnum)0 })]
[InlineData(new object[] { null, (FlagsEnum)0 })]
[InlineData(new object[] { "Value1,Value2", (FlagsEnum)3 })]
[InlineData(new object[] { "Value1,Value2,value4, value8", (FlagsEnum)15 })]
public void ConvertTo_ConvertsEnumFlags(object value, object expected)
{ {
// Arrange // Arrange
var valueProviderResult = new ValueProviderResult(rawValue: value); var result = x != y;
// Act // Act & Assert
var outValue = (FlagsEnum)valueProviderResult.ConvertTo(typeof(FlagsEnum)); Assert.NotEqual(expected, result);
// Assert
Assert.Equal(expected, outValue);
}
private class MyClassWithoutConverter
{
}
private enum IntEnum
{
Value0 = 0,
Value1 = 1,
MaxValue = int.MaxValue
}
private enum LongEnum : long
{
Value0 = 0L,
Value1 = 1L,
MaxValue = long.MaxValue
}
private enum UnsignedIntEnum : uint
{
Value0 = 0U,
Value1 = 1U,
MaxValue = uint.MaxValue
}
private enum ByteEnum : byte
{
Value0 = 0,
Value1 = 1,
MaxValue = byte.MaxValue
}
[Flags]
public enum FlagsEnum
{
Value1 = 1,
Value2 = 2,
Value4 = 4,
Value8 = 8
} }
} }
} }

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModelAsync_ValueProviderContainPrefix_Succeeds() public async Task BindModelAsync_ValueProviderContainPrefix_Succeeds()
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "someName[0]", "42" }, { "someName[0]", "42" },
{ "someName[1]", "84" }, { "someName[1]", "84" },
@ -138,7 +138,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModelAsync_ModelMetadataReadOnly_ReturnsNull(int[] model) public async Task BindModelAsync_ModelMetadataReadOnly_ReturnsNull(int[] model)
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "someName[0]", "42" }, { "someName[0]", "42" },
{ "someName[1]", "84" }, { "someName[1]", "84" },
@ -161,7 +161,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
// Arrange // Arrange
var arrayLength = model.Length; var arrayLength = model.Length;
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "someName[0]", "42" }, { "someName[0]", "42" },
{ "someName[1]", "84" }, { "someName[1]", "84" },
@ -196,7 +196,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
.Returns(async (ModelBindingContext mbc) => .Returns(async (ModelBindingContext mbc) =>
{ {
var value = await mbc.ValueProvider.GetValueAsync(mbc.ModelName); var value = await mbc.ValueProvider.GetValueAsync(mbc.ModelName);
if (value != null) if (value != ValueProviderResult.None)
{ {
var model = value.ConvertTo(mbc.ModelType); var model = value.ConvertTo(mbc.ModelType);
return new ModelBindingResult(model, key: null, isModelSet: true); return new ModelBindingResult(model, key: null, isModelSet: true);

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModelSetsModelToNullOnNullOrEmptyString(string value) public async Task BindModelSetsModelToNullOnNullOrEmptyString(string value)
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider() var valueProvider = new SimpleValueProvider()
{ {
{ "foo", value } { "foo", value }
}; };
@ -36,15 +36,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var modelState = Assert.Single(bindingContext.ModelState); var modelState = Assert.Single(bindingContext.ModelState);
Assert.Equal("foo", modelState.Key); Assert.Equal("foo", modelState.Key);
Assert.NotNull(modelState.Value.Value); Assert.Equal(string.Empty, modelState.Value.RawValue);
Assert.Equal(value, modelState.Value.Value.RawValue);
} }
[Fact] [Fact]
public async Task BindModel() public async Task BindModel()
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider() var valueProvider = new SimpleValueProvider()
{ {
{ "foo", "Fys1" } { "foo", "Fys1" }
}; };
@ -67,7 +66,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
// Arrange // Arrange
var expected = "The value '\"Fys1\"' is not valid for foo."; var expected = "The value '\"Fys1\"' is not valid for foo.";
var valueProvider = new SimpleHttpValueProvider() var valueProvider = new SimpleValueProvider()
{ {
{ "foo", "\"Fys1\"" } { "foo", "\"Fys1\"" }
}; };
@ -89,7 +88,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_ReturnsWithIsModelSetFalse_WhenValueNotFound() public async Task BindModel_ReturnsWithIsModelSetFalse_WhenValueNotFound()
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider() var valueProvider = new SimpleValueProvider()
{ {
{ "someName", "" } { "someName", "" }
}; };

View File

@ -53,7 +53,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
ModelMetadata = metadataProvider.GetMetadataForType(modelType), ModelMetadata = metadataProvider.GetMetadataForType(modelType),
ModelName = "someName", ModelName = "someName",
ValueProvider = new SimpleHttpValueProvider(), ValueProvider = new SimpleValueProvider(),
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {
ModelBinder = new CancellationTokenModelBinder(), ModelBinder = new CancellationTokenModelBinder(),

View File

@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindComplexCollectionFromIndexes_FiniteIndexes() public async Task BindComplexCollectionFromIndexes_FiniteIndexes()
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "someName[foo]", "42" }, { "someName[foo]", "42" },
{ "someName[baz]", "200" } { "someName[baz]", "200" }
@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindComplexCollectionFromIndexes_InfiniteIndexes() public async Task BindComplexCollectionFromIndexes_InfiniteIndexes()
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "someName[0]", "42" }, { "someName[0]", "42" },
{ "someName[1]", "100" }, { "someName[1]", "100" },
@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_ComplexCollection_Succeeds(bool isReadOnly) public async Task BindModel_ComplexCollection_Succeeds(bool isReadOnly)
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "someName.index", new[] { "foo", "bar", "baz" } }, { "someName.index", new[] { "foo", "bar", "baz" } },
{ "someName[foo]", "42" }, { "someName[foo]", "42" },
@ -100,7 +100,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_ComplexCollection_BindingContextModelNonNull_Succeeds(bool isReadOnly) public async Task BindModel_ComplexCollection_BindingContextModelNonNull_Succeeds(bool isReadOnly)
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "someName.index", new[] { "foo", "bar", "baz" } }, { "someName.index", new[] { "foo", "bar", "baz" } },
{ "someName[foo]", "42" }, { "someName[foo]", "42" },
@ -132,7 +132,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_SimpleCollection_Succeeds(bool isReadOnly) public async Task BindModel_SimpleCollection_Succeeds(bool isReadOnly)
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "someName", new[] { "42", "100", "200" } } { "someName", new[] { "42", "100", "200" } }
}; };
@ -149,8 +149,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var list = Assert.IsAssignableFrom<IList<int>>(result.Model); var list = Assert.IsAssignableFrom<IList<int>>(result.Model);
Assert.Equal(new[] { 42, 100, 200 }, list.ToArray()); Assert.Equal(new[] { 42, 100, 200 }, list.ToArray());
Assert.True(modelState.IsValid);
} }
[Theory] [Theory]
@ -159,7 +157,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_SimpleCollection_BindingContextModelNonNull_Succeeds(bool isReadOnly) public async Task BindModel_SimpleCollection_BindingContextModelNonNull_Succeeds(bool isReadOnly)
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "someName", new[] { "42", "100", "200" } } { "someName", new[] { "42", "100", "200" } }
}; };
@ -178,8 +176,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
Assert.Same(list, result.Model); Assert.Same(list, result.Model);
Assert.Equal(new[] { 42, 100, 200 }, list.ToArray()); Assert.Equal(new[] { 42, 100, 200 }, list.ToArray());
Assert.True(modelState.IsValid);
} }
[Fact] [Fact]
@ -187,7 +183,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
// Arrange // Arrange
var binder = new CollectionModelBinder<int>(); var binder = new CollectionModelBinder<int>();
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "someName", null }, { "someName", null },
}; };
@ -205,8 +201,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var model = Assert.IsType<List<int>>(result.Model); var model = Assert.IsType<List<int>>(result.Model);
Assert.Empty(model); Assert.Empty(model);
Assert.True(modelState.IsValid);
} }
#endif #endif
@ -225,7 +219,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
}; };
// Act // Act
var boundCollection = await binder.BindSimpleCollection(context, rawValue: new object[0], culture: null); var boundCollection = await binder.BindSimpleCollection(context, new ValueProviderResult(new string[0]));
// Assert // Assert
Assert.NotNull(boundCollection.Model); Assert.NotNull(boundCollection.Model);
@ -392,7 +386,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
// Arrange // Arrange
var culture = new CultureInfo("fr-FR"); var culture = new CultureInfo("fr-FR");
var bindingContext = GetModelBindingContext(new SimpleHttpValueProvider()); var bindingContext = GetModelBindingContext(new SimpleValueProvider());
ModelValidationNode childValidationNode = null; ModelValidationNode childValidationNode = null;
Mock.Get<IModelBinder>(bindingContext.OperationBindingContext.ModelBinder) Mock.Get<IModelBinder>(bindingContext.OperationBindingContext.ModelBinder)
.Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
@ -405,7 +399,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var modelBinder = new CollectionModelBinder<int>(); var modelBinder = new CollectionModelBinder<int>();
// Act // Act
var boundCollection = await modelBinder.BindSimpleCollection(bindingContext, new int[1], culture); var boundCollection = await modelBinder.BindSimpleCollection(
bindingContext,
new ValueProviderResult(new string[] { "0" }));
// Assert // Assert
Assert.Equal(new[] { 42 }, boundCollection.Model.ToArray()); Assert.Equal(new[] { 42 }, boundCollection.Model.ToArray());
@ -442,11 +438,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
.Returns(async (ModelBindingContext mbc) => .Returns(async (ModelBindingContext mbc) =>
{ {
var value = await mbc.ValueProvider.GetValueAsync(mbc.ModelName); var value = await mbc.ValueProvider.GetValueAsync(mbc.ModelName);
if (value != null) if (value != ValueProviderResult.None)
{ {
var model = value.ConvertTo(mbc.ModelType); var model = value.ConvertTo(mbc.ModelType);
var modelValidationNode = new ModelValidationNode(mbc.ModelName, mbc.ModelMetadata, model); var modelValidationNode = new ModelValidationNode(mbc.ModelName, mbc.ModelMetadata, model);
return new ModelBindingResult(model, mbc.ModelName, true, modelValidationNode); return new ModelBindingResult(model, mbc.ModelName, model != null, modelValidationNode);
} }
return null; return null;

View File

@ -24,7 +24,7 @@ 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(),
ValueProvider = new SimpleHttpValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someName", "dummyValue" } { "someName", "dummyValue" }
}, },
@ -71,7 +71,7 @@ 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(),
ValueProvider = new SimpleHttpValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
@ -121,7 +121,7 @@ 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(),
ValueProvider = new SimpleHttpValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
@ -155,7 +155,7 @@ 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(),
ValueProvider = new SimpleHttpValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
@ -201,7 +201,7 @@ 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(),
ValueProvider = new SimpleHttpValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
@ -238,7 +238,7 @@ 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(),
ValueProvider = new SimpleHttpValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
@ -276,7 +276,7 @@ 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(),
ValueProvider = new SimpleHttpValueProvider ValueProvider = new SimpleValueProvider
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
@ -357,7 +357,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
// Arrange // Arrange
var binder = CreateBinderWithDefaults(); var binder = CreateBinderWithDefaults();
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "firstName", "firstName-value"}, { "firstName", "firstName-value"},
{ "lastName", "lastName-value"} { "lastName", "lastName-value"}
@ -400,7 +400,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
// Arrange // Arrange
var binder = CreateBinderWithDefaults(); var binder = CreateBinderWithDefaults();
var valueProvider = new SimpleHttpValueProvider var valueProvider = new SimpleValueProvider
{ {
{ "firstName", "firstName-value"}, { "firstName", "firstName-value"},
{ "lastName", "lastName-value"}, { "lastName", "lastName-value"},
@ -436,7 +436,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_DoesNotAddAValidationNode_IfModelIsNotSet() public async Task BindModel_DoesNotAddAValidationNode_IfModelIsNotSet()
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider(); var valueProvider = new SimpleValueProvider();
var mockBinder = new Mock<IModelBinder>(); var mockBinder = new Mock<IModelBinder>();
mockBinder mockBinder
.Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
@ -465,7 +465,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
.Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(Task.FromResult<ModelBindingResult>(null)); .Returns(Task.FromResult<ModelBindingResult>(null));
var binder = CreateCompositeBinder(mockBinder.Object); var binder = CreateCompositeBinder(mockBinder.Object);
var valueProvider = new SimpleHttpValueProvider(); var valueProvider = new SimpleValueProvider();
var bindingContext = CreateBindingContext(binder, valueProvider, typeof(SimplePropertiesModel)); var bindingContext = CreateBindingContext(binder, valueProvider, typeof(SimplePropertiesModel));
// Act // Act
@ -479,7 +479,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_UsesTheValidationNodeOnModelBindingResult_IfPresent() public async Task BindModel_UsesTheValidationNodeOnModelBindingResult_IfPresent()
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider(); var valueProvider = new SimpleValueProvider();
ModelValidationNode validationNode = null; ModelValidationNode validationNode = null;
var mockBinder = new Mock<IModelBinder>(); var mockBinder = new Mock<IModelBinder>();
@ -531,10 +531,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
var binders = new IModelBinder[] var binders = new IModelBinder[]
{ {
new TypeMatchModelBinder(),
new ByteArrayModelBinder(), new ByteArrayModelBinder(),
new GenericModelBinder(), new GenericModelBinder(),
new TypeConverterModelBinder(), new SimpleTypeModelBinder(),
new MutableObjectModelBinder() new MutableObjectModelBinder()
}; };

View File

@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var result = await provider.GetValueAsync("not-test-key"); var result = await provider.GetValueAsync("not-test-key");
// Assert // Assert
Assert.Null(result); Assert.Equal(ValueProviderResult.None, result);
} }
[Fact] [Fact]
@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var result = await provider.GetValueAsync("test-key"); var result = await provider.GetValueAsync("test-key");
// Assert // Assert
Assert.Equal("test-value", result.RawValue); Assert.Equal("test-value", (string)result);
} }
[Fact] [Fact]
@ -58,9 +58,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var result = await provider.GetValueAsync("test-key"); var result = await provider.GetValueAsync("test-key");
// Assert // Assert
Assert.NotNull(result); Assert.Equal(string.Empty, (string)result);
Assert.Null(result.RawValue);
Assert.Null(result.AttemptedValue);
} }
[Theory] [Theory]
@ -103,7 +101,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var result = await valueProvider.GetValueAsync(prefix); var result = await valueProvider.GetValueAsync(prefix);
// Assert // Assert
Assert.Equal(expectedValue, (string)result.AttemptedValue); Assert.Equal(expectedValue, (string)result);
} }
[Fact] [Fact]
@ -121,7 +119,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var result = await valueProvider.GetValueAsync("bar"); var result = await valueProvider.GetValueAsync("bar");
// Assert // Assert
Assert.Null(result); Assert.Equal(ValueProviderResult.None, result);
} }
[Fact] [Fact]

View File

@ -21,7 +21,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_Succeeds(bool isReadOnly) public async Task BindModel_Succeeds(bool isReadOnly)
{ {
// Arrange // Arrange
var bindingContext = GetModelBindingContext(isReadOnly); var values = new Dictionary<string, KeyValuePair<int, string>>()
{
{ "someName[0]", new KeyValuePair<int, string>(42, "forty-two") },
{ "someName[1]", new KeyValuePair<int, string>(84, "eighty-four") },
};
var bindingContext = GetModelBindingContext(isReadOnly, values);
var modelState = bindingContext.ModelState; var modelState = bindingContext.ModelState;
var binder = new DictionaryModelBinder<int, string>(); var binder = new DictionaryModelBinder<int, string>();
@ -43,10 +49,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
[Theory] [Theory]
[InlineData(false)] [InlineData(false)]
[InlineData(true)] [InlineData(true)]
public async Task BindModel_BindingContextModelNonNull_Succeeds(bool isReadOnly) public async Task BindModel_WithExistingModel_Succeeds(bool isReadOnly)
{ {
// Arrange // Arrange
var bindingContext = GetModelBindingContext(isReadOnly); var values = new Dictionary<string, KeyValuePair<int, string>>()
{
{ "someName[0]", new KeyValuePair<int, string>(42, "forty-two") },
{ "someName[1]", new KeyValuePair<int, string>(84, "eighty-four") },
};
var bindingContext = GetModelBindingContext(isReadOnly, values);
var modelState = bindingContext.ModelState; var modelState = bindingContext.ModelState;
var dictionary = new Dictionary<int, string>(); var dictionary = new Dictionary<int, string>();
bindingContext.Model = dictionary; bindingContext.Model = dictionary;
@ -430,8 +442,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
var binders = new IModelBinder[] var binders = new IModelBinder[]
{ {
new TypeConverterModelBinder(), new SimpleTypeModelBinder(),
new TypeMatchModelBinder(),
new MutableObjectModelBinder(), new MutableObjectModelBinder(),
}; };
@ -465,49 +476,51 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
return new TestValueProvider(BindingSource.Form, backingStore); return new TestValueProvider(BindingSource.Form, backingStore);
} }
private static ModelBindingContext GetModelBindingContext(bool isReadOnly) private static ModelBindingContext GetModelBindingContext(
bool isReadOnly,
IDictionary<string, KeyValuePair<int, string>> values)
{ {
var metadataProvider = new TestModelMetadataProvider(); var metadataProvider = new TestModelMetadataProvider();
metadataProvider.ForType<IDictionary<int, string>>().BindingDetails(bd => bd.IsReadOnly = isReadOnly); metadataProvider.ForType<IDictionary<int, string>>().BindingDetails(bd => bd.IsReadOnly = isReadOnly);
var valueProvider = new SimpleHttpValueProvider
var binder = new Mock<IModelBinder>();
binder
.Setup(mb => mb.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns<ModelBindingContext>(mbc =>
{
KeyValuePair<int, string> value;
if (values.TryGetValue(mbc.ModelName, out value))
{
return Task.FromResult(new ModelBindingResult(value, mbc.ModelName, isModelSet: true));
}
else
{
return Task.FromResult<ModelBindingResult>(null);
}
});
var valueProvider = new SimpleValueProvider();
foreach (var kvp in values)
{ {
{ "someName[0]", new KeyValuePair<int, string>(42, "forty-two") }, valueProvider.Add(kvp.Key, string.Empty);
{ "someName[1]", new KeyValuePair<int, string>(84, "eighty-four") }, }
};
var bindingContext = new ModelBindingContext var bindingContext = new ModelBindingContext
{ {
ModelMetadata = metadataProvider.GetMetadataForType(typeof(IDictionary<int, string>)), ModelMetadata = metadataProvider.GetMetadataForType(typeof(IDictionary<int, string>)),
ModelName = "someName", ModelName = "someName",
ValueProvider = valueProvider,
OperationBindingContext = new OperationBindingContext OperationBindingContext = new OperationBindingContext
{ {
ModelBinder = CreateKvpBinder(), ModelBinder = binder.Object,
MetadataProvider = metadataProvider MetadataProvider = metadataProvider,
} ValueProvider = valueProvider,
},
ValueProvider = valueProvider,
}; };
return bindingContext; return bindingContext;
} }
private static IModelBinder CreateKvpBinder()
{
Mock<IModelBinder> mockKvpBinder = new Mock<IModelBinder>();
mockKvpBinder
.Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(async (ModelBindingContext mbc) =>
{
var value = await mbc.ValueProvider.GetValueAsync(mbc.ModelName);
if (value != null)
{
var model = value.ConvertTo(mbc.ModelType);
return new ModelBindingResult(model, key: null, isModelSet: true);
}
return null;
});
return mockKvpBinder.Object;
}
private class ModelWithDictionaryProperties private class ModelWithDictionaryProperties
{ {
// A Dictionary<string, string> instance cannot be assigned to this property. // A Dictionary<string, string> instance cannot be assigned to this property.

View File

@ -19,9 +19,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
// Arrange // Arrange
var culture = new CultureInfo("en-US"); var culture = new CultureInfo("en-US");
var elementalValueProvider = new ElementalValueProvider(elementName, var elementalValueProvider = new ElementalValueProvider(
new object(), elementName,
culture); "hi",
culture);
// Act // Act
var containsPrefix = await elementalValueProvider.ContainsPrefixAsync(prefix); var containsPrefix = await elementalValueProvider.ContainsPrefixAsync(prefix);
@ -39,9 +40,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
// Arrange // Arrange
var culture = new CultureInfo("en-US"); var culture = new CultureInfo("en-US");
var elementalValueProvider = new ElementalValueProvider(elementName, var elementalValueProvider = new ElementalValueProvider(
new object(), elementName,
culture); "hi",
culture);
// Act // Act
var containsPrefix = await elementalValueProvider.ContainsPrefixAsync(prefix); var containsPrefix = await elementalValueProvider.ContainsPrefixAsync(prefix);
@ -51,18 +53,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
} }
[Fact] [Fact]
public async Task GetValueAsync_NameDoesNotMatch_ReturnsNull() public async Task GetValueAsync_NameDoesNotMatch_ReturnsEmptyResult()
{ {
// Arrange // Arrange
var culture = new CultureInfo("fr-FR"); var culture = new CultureInfo("fr-FR");
var rawValue = new DateTime(2001, 1, 2); var valueProvider = new ElementalValueProvider("foo", "hi", culture);
var valueProvider = new ElementalValueProvider("foo", rawValue, culture);
// Act // Act
var vpResult = await valueProvider.GetValueAsync("bar"); var result = await valueProvider.GetValueAsync("bar");
// Assert // Assert
Assert.Null(vpResult); Assert.Equal(ValueProviderResult.None, result);
} }
[Theory] [Theory]
@ -73,17 +74,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
// Arrange // Arrange
var culture = new CultureInfo("fr-FR"); var culture = new CultureInfo("fr-FR");
var rawValue = new DateTime(2001, 1, 2); var valueProvider = new ElementalValueProvider("foo", "hi", culture);
var valueProvider = new ElementalValueProvider("foo", rawValue, culture);
// Act // Act
var vpResult = await valueProvider.GetValueAsync(name); var result = await valueProvider.GetValueAsync(name);
// Assert // Assert
Assert.NotNull(vpResult); Assert.NotNull(result);
Assert.Equal(rawValue, vpResult.RawValue); Assert.Equal("hi", (string)result);
Assert.Equal("02/01/2001 00:00:00", vpResult.AttemptedValue); Assert.Equal(culture, result.Culture);
Assert.Equal(culture, vpResult.Culture);
} }
} }
} }

View File

@ -167,8 +167,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.Equal("someOtherValue", result.RawValue); Assert.Equal("someOtherValue", (string)result);
Assert.Equal("someOtherValue", result.AttemptedValue);
Assert.Equal(culture, result.Culture); Assert.Equal(culture, result.Culture);
} }
@ -184,8 +183,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Assert // Assert
Assert.NotNull(result); Assert.NotNull(result);
Assert.Equal(new[] { "someValue1", "someValue2" }, (IList<string>)result.RawValue); Assert.Equal(new[] { "someValue1", "someValue2" }, result.Values);
Assert.Equal("someValue1,someValue2", result.AttemptedValue); Assert.Equal("someValue1,someValue2", (string)result);
Assert.Equal(culture, result.Culture); Assert.Equal(culture, result.Culture);
} }
@ -202,7 +201,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var result = await valueProvider.GetValueAsync(key); var result = await valueProvider.GetValueAsync(key);
// Assert // Assert
Assert.Null(result); Assert.Equal(ValueProviderResult.None, result);
} }
[Fact] [Fact]
@ -220,8 +219,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var result = await valueProvider.GetValueAsync("key"); var result = await valueProvider.GetValueAsync("key");
// Assert // Assert
Assert.Equal(new[] { null, null, "value" }, result.RawValue as IEnumerable<string>); Assert.Equal(new[] { null, null, "value" }, result.Values);
Assert.Equal(",,value", result.AttemptedValue); Assert.Equal(",,value", (string)result);
} }
[Fact] [Fact]
@ -234,7 +233,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var result = await valueProvider.GetValueAsync("prefix"); var result = await valueProvider.GetValueAsync("prefix");
// Assert // Assert
Assert.Null(result); Assert.Equal(ValueProviderResult.None, result);
} }
[Fact] [Fact]

View File

@ -110,10 +110,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var result = await valueProvider.GetValueAsync(key); var result = await valueProvider.GetValueAsync(key);
// Assert // Assert
Assert.NotNull(result); Assert.Equal("found", (string)result);
Assert.NotNull(result.RawValue);
var value = Assert.IsType<string>(result.RawValue);
Assert.Equal("found", value);
} }
private static ValueProviderFactoryContext CreateContext( private static ValueProviderFactoryContext CreateContext(

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_MissingKey_ReturnsResult_AndAddsModelValidationError() public async Task BindModel_MissingKey_ReturnsResult_AndAddsModelValidationError()
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider(); var valueProvider = new SimpleValueProvider();
// Create string binder to create the value but not the key. // Create string binder to create the value but not the key.
var bindingContext = GetBindingContext(valueProvider, CreateStringBinder()); var bindingContext = GetBindingContext(valueProvider, CreateStringBinder());
@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_MissingValue_ReturnsResult_AndAddsModelValidationError() public async Task BindModel_MissingValue_ReturnsResult_AndAddsModelValidationError()
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider(); var valueProvider = new SimpleValueProvider();
// Create int binder to create the value but not the key. // Create int binder to create the value but not the key.
var bindingContext = GetBindingContext(valueProvider, CreateIntBinder()); var bindingContext = GetBindingContext(valueProvider, CreateIntBinder());
@ -64,7 +64,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public async Task BindModel_MissingKeyAndMissingValue_DoNotAddModelStateError() public async Task BindModel_MissingKeyAndMissingValue_DoNotAddModelStateError()
{ {
// Arrange // Arrange
var valueProvider = new SimpleHttpValueProvider(); var valueProvider = new SimpleValueProvider();
// Create int binder to create the value but not the key. // Create int binder to create the value but not the key.
var bindingContext = GetBindingContext(valueProvider); var bindingContext = GetBindingContext(valueProvider);
@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
// Arrange // Arrange
var innerBinder = new CompositeModelBinder(new[] { CreateStringBinder(), CreateIntBinder() }); var innerBinder = new CompositeModelBinder(new[] { CreateStringBinder(), CreateIntBinder() });
var valueProvider = new SimpleHttpValueProvider(); var valueProvider = new SimpleValueProvider();
var bindingContext = GetBindingContext(valueProvider, innerBinder); var bindingContext = GetBindingContext(valueProvider, innerBinder);
var binder = new KeyValuePairModelBinder<int, string>(); var binder = new KeyValuePairModelBinder<int, string>();
@ -134,7 +134,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
Assert.Equal("someName.key", context.ModelName); Assert.Equal("someName.key", context.ModelName);
return Task.FromResult(innerResult); return Task.FromResult(innerResult);
}); });
var bindingContext = GetBindingContext(new SimpleHttpValueProvider(), innerBinder.Object); var bindingContext = GetBindingContext(new SimpleValueProvider(), innerBinder.Object);
var binder = new KeyValuePairModelBinder<int, string>(); var binder = new KeyValuePairModelBinder<int, string>();
var modelValidationNodeList = new List<ModelValidationNode>(); var modelValidationNodeList = new List<ModelValidationNode>();
@ -238,7 +238,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
HttpContext = new DefaultHttpContext(), HttpContext = new DefaultHttpContext(),
MetadataProvider = new TestModelMetadataProvider(), MetadataProvider = new TestModelMetadataProvider(),
ModelBinder = new TypeMatchModelBinder(), ModelBinder = new SimpleTypeModelBinder(),
} }
}; };

View File

@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)), ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)),
ModelName = "theName", ModelName = "theName",
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
ValueProvider = new SimpleHttpValueProvider() ValueProvider = new SimpleValueProvider()
}; };
var metadataProvider = new TestModelMetadataProvider(); var metadataProvider = new TestModelMetadataProvider();

View File

@ -9,7 +9,7 @@ using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding.Test namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
public class TypeConverterModelBinderTest public class SimpleTypeModelBinderTest
{ {
[Theory] [Theory]
[InlineData(typeof(object))] [InlineData(typeof(object))]
@ -19,12 +19,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(destinationType); var bindingContext = GetBindingContext(destinationType);
bindingContext.ValueProvider = new SimpleHttpValueProvider bindingContext.ValueProvider = new SimpleValueProvider
{ {
{ "theModelName", "some-value" } { "theModelName", "some-value" }
}; };
var binder = new TypeConverterModelBinder(); var binder = new SimpleTypeModelBinder();
// Act // Act
var retVal = await binder.BindModelAsync(bindingContext); var retVal = await binder.BindModelAsync(bindingContext);
@ -53,12 +53,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
// Arrange // Arrange
var bindingContext = GetBindingContext(destinationType); var bindingContext = GetBindingContext(destinationType);
bindingContext.ValueProvider = new SimpleHttpValueProvider bindingContext.ValueProvider = new SimpleValueProvider
{ {
{ "theModelName", "some-value" } { "theModelName", "some-value" }
}; };
var binder = new TypeConverterModelBinder(); var binder = new SimpleTypeModelBinder();
// Act // Act
var retVal = await binder.BindModelAsync(bindingContext); var retVal = await binder.BindModelAsync(bindingContext);
@ -79,11 +79,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(destinationType); var bindingContext = GetBindingContext(destinationType);
bindingContext.ValueProvider = new SimpleHttpValueProvider bindingContext.ValueProvider = new SimpleValueProvider
{ {
{ "theModelName", string.Empty } { "theModelName", string.Empty }
}; };
var binder = new TypeConverterModelBinder(); var binder = new SimpleTypeModelBinder();
// Act // Act
var result = await binder.BindModelAsync(bindingContext); var result = await binder.BindModelAsync(bindingContext);
@ -104,19 +104,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
// Arrange // Arrange
var message = "The value 'not an integer' is not valid for theModelName."; var message = "The value 'not an integer' is not valid for theModelName.";
var bindingContext = GetBindingContext(typeof(int)); var bindingContext = GetBindingContext(typeof(int));
bindingContext.ValueProvider = new SimpleHttpValueProvider bindingContext.ValueProvider = new SimpleValueProvider
{ {
{ "theModelName", "not an integer" } { "theModelName", "not an integer" }
}; };
var binder = new TypeConverterModelBinder(); var binder = new SimpleTypeModelBinder();
// Act // Act
var retVal = await binder.BindModelAsync(bindingContext); var result = await binder.BindModelAsync(bindingContext);
// Assert // Assert
Assert.NotNull(retVal); Assert.NotNull(result);
Assert.Null(retVal.Model); Assert.Null(result.Model);
Assert.False(bindingContext.ModelState.IsValid); Assert.False(bindingContext.ModelState.IsValid);
var error = Assert.Single(bindingContext.ModelState["theModelName"].Errors); var error = Assert.Single(bindingContext.ModelState["theModelName"].Errors);
Assert.Equal(message, error.ErrorMessage); Assert.Equal(message, error.ErrorMessage);
@ -127,7 +127,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(typeof(int)); var bindingContext = GetBindingContext(typeof(int));
var binder = new TypeConverterModelBinder(); var binder = new SimpleTypeModelBinder();
// Act // Act
var retVal = await binder.BindModelAsync(bindingContext); var retVal = await binder.BindModelAsync(bindingContext);
@ -142,12 +142,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(typeof(string)); var bindingContext = GetBindingContext(typeof(string));
bindingContext.ValueProvider = new SimpleHttpValueProvider bindingContext.ValueProvider = new SimpleValueProvider
{ {
{ "theModelName", string.Empty } { "theModelName", string.Empty }
}; };
var binder = new TypeConverterModelBinder(); var binder = new SimpleTypeModelBinder();
// Act // Act
var retVal = await binder.BindModelAsync(bindingContext); var retVal = await binder.BindModelAsync(bindingContext);
@ -163,12 +163,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
// Arrange // Arrange
var bindingContext = GetBindingContext(typeof(int)); var bindingContext = GetBindingContext(typeof(int));
bindingContext.ValueProvider = new SimpleHttpValueProvider bindingContext.ValueProvider = new SimpleValueProvider
{ {
{ "theModelName", "42" } { "theModelName", "42" }
}; };
var binder = new TypeConverterModelBinder(); var binder = new SimpleTypeModelBinder();
// Act // Act
var retVal = await binder.BindModelAsync(bindingContext); var retVal = await binder.BindModelAsync(bindingContext);
@ -185,7 +185,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(modelType), ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(modelType),
ModelName = "theModelName", ModelName = "theModelName",
ValueProvider = new SimpleHttpValueProvider() // empty ValueProvider = new SimpleValueProvider() // empty
}; };
} }

View File

@ -8,16 +8,16 @@ using System.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.ModelBinding.Test namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
public sealed class SimpleHttpValueProvider : Dictionary<string, object>, IValueProvider public sealed class SimpleValueProvider : Dictionary<string, object>, IValueProvider
{ {
private readonly CultureInfo _culture; private readonly CultureInfo _culture;
public SimpleHttpValueProvider() public SimpleValueProvider()
: this(null) : this(null)
{ {
} }
public SimpleHttpValueProvider(CultureInfo culture) public SimpleValueProvider(CultureInfo culture)
: base(StringComparer.OrdinalIgnoreCase) : base(StringComparer.OrdinalIgnoreCase)
{ {
_culture = culture ?? CultureInfo.InvariantCulture; _culture = culture ?? CultureInfo.InvariantCulture;
@ -59,11 +59,28 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
public Task<ValueProviderResult> GetValueAsync(string key) public Task<ValueProviderResult> GetValueAsync(string key)
{ {
ValueProviderResult result = null; ValueProviderResult result = ValueProviderResult.None;
object rawValue; object rawValue;
if (TryGetValue(key, out rawValue)) if (TryGetValue(key, out rawValue))
{ {
result = new ValueProviderResult(rawValue, Convert.ToString(rawValue, _culture), _culture); if (rawValue != null && rawValue.GetType().IsArray)
{
var array = (Array)rawValue;
var stringValues = new string[array.Length];
for (var i = 0; i < array.Length; i++)
{
stringValues[i] = array.GetValue(i) as string ?? Convert.ToString(array.GetValue(i), _culture);
}
result = new ValueProviderResult(stringValues, _culture);
}
else
{
var stringValue = rawValue as string ?? Convert.ToString(rawValue, _culture) ?? string.Empty;
result = new ValueProviderResult(stringValue, _culture);
}
} }
return Task.FromResult(result); return Task.FromResult(result);

View File

@ -1,121 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{
public class TypeMatchModelBinderTest
{
[Fact]
public async Task BindModel_InvalidValueProviderResult_ReturnsNull()
{
// Arrange
var bindingContext = GetBindingContext();
bindingContext.ValueProvider = new SimpleHttpValueProvider
{
{ "theModelName", "not an integer" }
};
var binder = new TypeMatchModelBinder();
var modelState = bindingContext.ModelState;
// Act
var result = await binder.BindModelAsync(bindingContext);
// Assert
Assert.Null(result);
Assert.Empty(modelState.Keys);
Assert.True(modelState.IsValid);
}
[Fact]
public async Task BindModel_ValidValueProviderResult_ReturnsNotNull()
{
// Arrange
var bindingContext = GetBindingContext();
bindingContext.ValueProvider = new SimpleHttpValueProvider
{
{ "theModelName", 42 }
};
var binder = new TypeMatchModelBinder();
var modelState = bindingContext.ModelState;
// Act
var result = await binder.BindModelAsync(bindingContext);
// Assert
Assert.NotNull(result);
Assert.True(result.IsModelSet);
Assert.Equal(42, result.Model);
var key = Assert.Single(modelState.Keys);
Assert.Equal("theModelName", key);
Assert.Equal("42", modelState[key].Value.AttemptedValue);
Assert.Equal(42, modelState[key].Value.RawValue);
}
[Fact]
public async Task GetCompatibleValueProviderResult_ValueProviderResultRawValueIncorrect_ReturnsNull()
{
// Arrange
var bindingContext = GetBindingContext();
bindingContext.ValueProvider = new SimpleHttpValueProvider
{
{ "theModelName", "not an integer" }
};
// Act
var vpResult = await TypeMatchModelBinder.GetCompatibleValueProviderResult(bindingContext);
// Assert
Assert.Null(vpResult); // Raw value is the wrong type
}
[Fact]
public async Task GetCompatibleValueProviderResult_ValueProviderResultValid_ReturnsValueProviderResult()
{
// Arrange
var bindingContext = GetBindingContext();
bindingContext.ValueProvider = new SimpleHttpValueProvider
{
{ "theModelName", 42 }
};
// Act
var vpResult = await TypeMatchModelBinder.GetCompatibleValueProviderResult(bindingContext);
// Assert
Assert.NotNull(vpResult);
}
[Fact]
public async Task GetCompatibleValueProviderResult_ValueProviderReturnsNull_ReturnsNull()
{
// Arrange
var bindingContext = GetBindingContext();
bindingContext.ValueProvider = new SimpleHttpValueProvider();
// Act
var vpResult = await TypeMatchModelBinder.GetCompatibleValueProviderResult(bindingContext);
// Assert
Assert.Null(vpResult); // No key matched
}
private static ModelBindingContext GetBindingContext()
{
return GetBindingContext(typeof(int));
}
private static ModelBindingContext GetBindingContext(Type modelType)
{
return new ModelBindingContext
{
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(modelType),
ModelName = "theModelName"
};
}
}
}

View File

@ -495,8 +495,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
var validationContext = testValidationContext.ModelValidationContext; var validationContext = testValidationContext.ModelValidationContext;
// Set the value on model state as a model binder would. // Set the value on model state as a model binder would.
var valueProviderResult = new ValueProviderResult(rawValue: "password"); validationContext.ModelState.SetModelValue("user.Password", new string[] { "password" }, "password");
validationContext.ModelState.SetModelValue("user.Password", valueProviderResult);
var validator = new DefaultObjectValidator( var validator = new DefaultObjectValidator(
testValidationContext.ExcludeFilters, testValidationContext.ExcludeFilters,
testValidationContext.ModelMetadataProvider); testValidationContext.ModelMetadataProvider);
@ -517,7 +516,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
Assert.Equal("user.Password", entry.Key); Assert.Equal("user.Password", entry.Key);
Assert.Empty(entry.Value.Errors); Assert.Empty(entry.Value.Errors);
Assert.Equal(entry.Value.ValidationState, ModelValidationState.Skipped); Assert.Equal(entry.Value.ValidationState, ModelValidationState.Skipped);
Assert.Same(valueProviderResult, entry.Value.Value); Assert.Equal(new string[] { "password" }, entry.Value.RawValue);
Assert.Same("password", entry.Value.AttemptedValue);
} }
private class Person2 private class Person2

View File

@ -5,6 +5,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
@ -68,7 +69,7 @@ namespace Microsoft.AspNet.Mvc.Test
var expectedMessage = PlatformNormalizer.NormalizeContent("The MyProperty field is required."); var expectedMessage = PlatformNormalizer.NormalizeContent("The MyProperty field is required.");
var binders = new IModelBinder[] var binders = new IModelBinder[]
{ {
new TypeConverterModelBinder(), new SimpleTypeModelBinder(),
new MutableObjectModelBinder() new MutableObjectModelBinder()
}; };
@ -107,7 +108,7 @@ namespace Microsoft.AspNet.Mvc.Test
// Arrange // Arrange
var binders = new IModelBinder[] var binders = new IModelBinder[]
{ {
new TypeConverterModelBinder(), new SimpleTypeModelBinder(),
new MutableObjectModelBinder() new MutableObjectModelBinder()
}; };
@ -181,7 +182,7 @@ namespace Microsoft.AspNet.Mvc.Test
// Arrange // Arrange
var binders = new IModelBinder[] var binders = new IModelBinder[]
{ {
new TypeConverterModelBinder(), new SimpleTypeModelBinder(),
new MutableObjectModelBinder() new MutableObjectModelBinder()
}; };
@ -270,7 +271,7 @@ namespace Microsoft.AspNet.Mvc.Test
// Arrange // Arrange
var binders = new IModelBinder[] var binders = new IModelBinder[]
{ {
new TypeConverterModelBinder(), new SimpleTypeModelBinder(),
new MutableObjectModelBinder() new MutableObjectModelBinder()
}; };
@ -322,7 +323,7 @@ namespace Microsoft.AspNet.Mvc.Test
// Arrange // Arrange
var binders = new IModelBinder[] var binders = new IModelBinder[]
{ {
new TypeConverterModelBinder(), new SimpleTypeModelBinder(),
new MutableObjectModelBinder() new MutableObjectModelBinder()
}; };
@ -528,7 +529,7 @@ namespace Microsoft.AspNet.Mvc.Test
// Arrange // Arrange
var binders = new IModelBinder[] var binders = new IModelBinder[]
{ {
new TypeConverterModelBinder(), new SimpleTypeModelBinder(),
new MutableObjectModelBinder() new MutableObjectModelBinder()
}; };
@ -619,7 +620,7 @@ namespace Microsoft.AspNet.Mvc.Test
// Arrange // Arrange
var binders = new IModelBinder[] var binders = new IModelBinder[]
{ {
new TypeConverterModelBinder(), new SimpleTypeModelBinder(),
new MutableObjectModelBinder() new MutableObjectModelBinder()
}; };
@ -876,6 +877,514 @@ namespace Microsoft.AspNet.Mvc.Test
public string Name { get; set; } public string Name { get; set; }
public Address Address { get; set; } public Address Address { get; set; }
} }
[Fact]
public void ConvertTo_ReturnsNullForReferenceTypes_WhenValueIsNull()
{
var convertedValue = ModelBindingHelper.ConvertTo(null, typeof(string));
Assert.Null(convertedValue);
}
[Fact]
public void ConvertTo_ReturnsDefaultForValueTypes_WhenValueIsNull()
{
var convertedValue = ModelBindingHelper.ConvertTo(null, typeof(int));
Assert.Equal(0, convertedValue);
}
[Fact]
public void ConvertToCanConvertArraysToSingleElements()
{
// Arrange
var value = new int[] { 1, 20, 42 };
// Act
var converted = ModelBindingHelper.ConvertTo(value, typeof(string));
// Assert
Assert.Equal("1", converted);
}
[Fact]
public void ConvertToCanConvertSingleElementsToArrays()
{
// Arrange
var value = 42;
// Act
var converted = ModelBindingHelper.ConvertTo<string[]>(value);
// Assert
Assert.NotNull(converted);
var result = Assert.Single(converted);
Assert.Equal("42", result);
}
[Fact]
public void ConvertToCanConvertSingleElementsToSingleElements()
{
// Arrange
// Act
var converted = ModelBindingHelper.ConvertTo<string>(42);
// Assert
Assert.NotNull(converted);
Assert.Equal("42", converted);
}
[Fact]
public void ConvertingNullStringToNullableIntReturnsNull()
{
// Arrange
// Act
var returned = ModelBindingHelper.ConvertTo<int?>(null);
// Assert
Assert.Equal(returned, null);
}
[Fact]
public void ConvertingWhiteSpaceStringToNullableIntReturnsNull()
{
// Arrange
var original = " ";
// Act
var returned = ModelBindingHelper.ConvertTo<int?>(original);
// Assert
Assert.Equal(returned, null);
}
[Fact]
public void ConvertToReturnsNullIfArrayElementValueIsNull()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(new string[] { null }, typeof(int));
// Assert
Assert.Null(outValue);
}
[Fact]
public void ConvertToReturnsNullIfTryingToConvertEmptyArrayToSingleElement()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(new int[0], typeof(int));
// Assert
Assert.Null(outValue);
}
[Theory]
[InlineData("")]
[InlineData(" \t \r\n ")]
public void ConvertToReturnsNullIfTrimmedValueIsEmptyString(object value)
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(value, typeof(int));
// Assert
Assert.Null(outValue);
}
[Fact]
public void ConvertToReturnsNullIfTrimmedValueIsEmptyString()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(null, typeof(int[]));
// Assert
Assert.Null(outValue);
}
[Fact]
public void ConvertToReturnsValueIfArrayElementIsIntegerAndDestinationTypeIsEnum()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(new object[] { 1 }, typeof(IntEnum));
// Assert
Assert.Equal(outValue, IntEnum.Value1);
}
[Theory]
[InlineData(1, typeof(IntEnum), IntEnum.Value1)]
[InlineData(1L, typeof(LongEnum), LongEnum.Value1)]
[InlineData(long.MaxValue, typeof(LongEnum), LongEnum.MaxValue)]
[InlineData(1U, typeof(UnsignedIntEnum), UnsignedIntEnum.Value1)]
[InlineData(1UL, typeof(IntEnum), IntEnum.Value1)]
[InlineData((byte)1, typeof(ByteEnum), ByteEnum.Value1)]
[InlineData(byte.MaxValue, typeof(ByteEnum), ByteEnum.MaxValue)]
[InlineData((sbyte)1, typeof(ByteEnum), ByteEnum.Value1)]
[InlineData((short)1, typeof(IntEnum), IntEnum.Value1)]
[InlineData((ushort)1, typeof(IntEnum), IntEnum.Value1)]
[InlineData(int.MaxValue, typeof(IntEnum?), IntEnum.MaxValue)]
[InlineData(null, typeof(IntEnum?), null)]
[InlineData(1L, typeof(LongEnum?), LongEnum.Value1)]
[InlineData(null, typeof(LongEnum?), null)]
[InlineData(uint.MaxValue, typeof(UnsignedIntEnum?), UnsignedIntEnum.MaxValue)]
[InlineData((byte)1, typeof(ByteEnum?), ByteEnum.Value1)]
[InlineData(null, typeof(ByteEnum?), null)]
[InlineData((ushort)1, typeof(LongEnum?), LongEnum.Value1)]
public void ConvertToReturnsValueIfArrayElementIsAnyIntegerTypeAndDestinationTypeIsEnum(
object input,
Type enumType,
object expected)
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(new object[] { input }, enumType);
// Assert
Assert.Equal(expected, outValue);
}
[Fact]
public void ConvertToReturnsValueIfArrayElementIsStringValueAndDestinationTypeIsEnum()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(new object[] { "1" }, typeof(IntEnum));
// Assert
Assert.Equal(outValue, IntEnum.Value1);
}
[Fact]
public void ConvertToReturnsValueIfArrayElementIsStringKeyAndDestinationTypeIsEnum()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(new object[] { "Value1" }, typeof(IntEnum));
// Assert
Assert.Equal(outValue, IntEnum.Value1);
}
[Fact]
public void ConvertToReturnsValueIfElementIsStringAndDestinationIsNullableInteger()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo("12", typeof(int?));
// Assert
Assert.Equal(12, outValue);
}
[Fact]
public void ConvertToReturnsValueIfElementIsStringAndDestinationIsNullableDouble()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo("12.5", typeof(double?));
// Assert
Assert.Equal(12.5, outValue);
}
[Fact]
public void ConvertToReturnsValueIfElementIsDecimalAndDestinationIsNullableInteger()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(12M, typeof(int?));
// Assert
Assert.Equal(12, outValue);
}
[Fact]
public void ConvertToReturnsValueIfElementIsDecimalAndDestinationIsNullableDouble()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(12.5M, typeof(double?));
// Assert
Assert.Equal(12.5, outValue);
}
[Fact]
public void ConvertToReturnsValueIfElementIsDecimalDoubleAndDestinationIsNullableInteger()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(12M, typeof(int?));
// Assert
Assert.Equal(12, outValue);
}
[Fact]
public void ConvertToReturnsValueIfElementIsDecimalDoubleAndDestinationIsNullableLong()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(12M, typeof(long?));
// Assert
Assert.Equal(12L, outValue);
}
[Fact]
public void ConvertToReturnsValueIfArrayElementInstanceOfDestinationType()
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(new object[] { "some string" }, typeof(string));
// Assert
Assert.Equal("some string", outValue);
}
[Theory]
[InlineData(new object[] { new[] { 1, 0 } })]
[InlineData(new object[] { new[] { "Value1", "Value0" } })]
[InlineData(new object[] { new[] { "Value1", "value0" } })]
public void ConvertTo_ConvertsEnumArrays(object value)
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(value, typeof(IntEnum[]));
// Assert
var result = Assert.IsType<IntEnum[]>(outValue);
Assert.Equal(2, result.Length);
Assert.Equal(IntEnum.Value1, result[0]);
Assert.Equal(IntEnum.Value0, result[1]);
}
[Theory]
[InlineData(new object[] { new[] { 1, 2 }, new[] { FlagsEnum.Value1, FlagsEnum.Value2 } })]
[InlineData(new object[] { new[] { "Value1", "Value2" }, new[] { FlagsEnum.Value1, FlagsEnum.Value2 } })]
[InlineData(new object[] { new[] { 5, 2 }, new[] { FlagsEnum.Value1 | FlagsEnum.Value4, FlagsEnum.Value2 } })]
public void ConvertTo_ConvertsFlagsEnumArrays(object value, FlagsEnum[] expected)
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo(value, typeof(FlagsEnum[]));
// Assert
var result = Assert.IsType<FlagsEnum[]>(outValue);
Assert.Equal(2, result.Length);
Assert.Equal(expected[0], result[0]);
Assert.Equal(expected[1], result[1]);
}
[Fact]
public void ConvertToReturnsValueIfInstanceOfDestinationType()
{
// Arrange
var original = new[] { "some string" };
// Act
var outValue = ModelBindingHelper.ConvertTo(original, typeof(string[]));
// Assert
Assert.Same(original, outValue);
}
[Theory]
[InlineData(typeof(int))]
[InlineData(typeof(double?))]
[InlineData(typeof(IntEnum?))]
public void ConvertToThrowsIfConverterThrows(Type destinationType)
{
// Arrange
// Act & Assert
var ex = Assert.Throws<FormatException>(
() => ModelBindingHelper.ConvertTo("this-is-not-a-valid-value", destinationType));
}
[Fact]
public void ConvertToThrowsIfNoConverterExists()
{
// Arrange
var destinationType = typeof(MyClassWithoutConverter);
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(
() => ModelBindingHelper.ConvertTo("x", destinationType));
Assert.Equal("The parameter conversion from type 'System.String' to type " +
$"'{typeof(MyClassWithoutConverter).FullName}' " +
"failed because no type converter can convert between these types.",
ex.Message);
}
[Fact]
public void ConvertToUsesProvidedCulture()
{
// Arrange
// Act
var cultureResult = ModelBindingHelper.ConvertTo("12,5", typeof(decimal), new CultureInfo("fr-FR"));
// Assert
Assert.Equal(12.5M, cultureResult);
Assert.Throws<FormatException>(
() => ModelBindingHelper.ConvertTo("12,5", typeof(decimal), new CultureInfo("en-GB")));
}
[Theory]
[MemberData(nameof(IntrinsicConversionData))]
public void ConvertToCanConvertIntrinsics<T>(object initialValue, T expectedValue)
{
// Arrange
// Act & Assert
Assert.Equal(expectedValue, ModelBindingHelper.ConvertTo(initialValue, typeof(T)));
}
public static IEnumerable<object[]> IntrinsicConversionData
{
get
{
yield return new object[] { 42, 42L };
yield return new object[] { 42, (short)42 };
yield return new object[] { 42, (float)42.0 };
yield return new object[] { 42, (double)42.0 };
yield return new object[] { 42M, 42 };
yield return new object[] { 42L, 42 };
yield return new object[] { 42, (byte)42 };
yield return new object[] { (short)42, 42 };
yield return new object[] { (float)42.0, 42 };
yield return new object[] { (double)42.0, 42 };
yield return new object[] { (byte)42, 42 };
yield return new object[] { "2008-01-01", new DateTime(2008, 01, 01) };
yield return new object[] { "00:00:20", TimeSpan.FromSeconds(20) };
yield return new object[]
{
"c6687d3a-51f9-4159-8771-a66d2b7d7038",
Guid.Parse("c6687d3a-51f9-4159-8771-a66d2b7d7038")
};
}
}
[Theory]
[InlineData(typeof(TimeSpan))]
[InlineData(typeof(DateTime))]
[InlineData(typeof(DateTimeOffset))]
[InlineData(typeof(Guid))]
[InlineData(typeof(IntEnum))]
public void ConvertTo_Throws_IfValueIsNotStringData(Type destinationType)
{
// Arrange
// Act
var ex = Assert.Throws<InvalidOperationException>(
() => ModelBindingHelper.ConvertTo(new MyClassWithoutConverter(), destinationType));
// Assert
var expectedMessage = string.Format("The parameter conversion from type '{0}' to type '{1}' " +
"failed because no type converter can convert between these types.",
typeof(MyClassWithoutConverter), destinationType);
Assert.Equal(expectedMessage, ex.Message);
}
[Fact]
public void ConvertTo_Throws_IfDestinationTypeIsNotConvertible()
{
// Arrange
var value = "Hello world";
var destinationType = typeof(MyClassWithoutConverter);
// Act
var ex = Assert.Throws<InvalidOperationException>(
() => ModelBindingHelper.ConvertTo(value, destinationType));
// Assert
var expectedMessage = string.Format("The parameter conversion from type '{0}' to type '{1}' " +
"failed because no type converter can convert between these types.",
value.GetType(), typeof(MyClassWithoutConverter));
Assert.Equal(expectedMessage, ex.Message);
}
[Theory]
[InlineData(new object[] { 2, FlagsEnum.Value2 })]
[InlineData(new object[] { 5, FlagsEnum.Value1 | FlagsEnum.Value4 })]
[InlineData(new object[] { 15, FlagsEnum.Value1 | FlagsEnum.Value2 | FlagsEnum.Value4 | FlagsEnum.Value8 })]
[InlineData(new object[] { 16, (FlagsEnum)16 })]
[InlineData(new object[] { 0, (FlagsEnum)0 })]
[InlineData(new object[] { null, (FlagsEnum)0 })]
[InlineData(new object[] { "Value1,Value2", (FlagsEnum)3 })]
[InlineData(new object[] { "Value1,Value2,value4, value8", (FlagsEnum)15 })]
public void ConvertTo_ConvertsEnumFlags(object value, object expected)
{
// Arrange
// Act
var outValue = ModelBindingHelper.ConvertTo<FlagsEnum>(value);
// Assert
Assert.Equal(expected, outValue);
}
private class MyClassWithoutConverter
{
}
private enum IntEnum
{
Value0 = 0,
Value1 = 1,
MaxValue = int.MaxValue
}
private enum LongEnum : long
{
Value0 = 0L,
Value1 = 1L,
MaxValue = long.MaxValue
}
private enum UnsignedIntEnum : uint
{
Value0 = 0U,
Value1 = 1U,
MaxValue = uint.MaxValue
}
private enum ByteEnum : byte
{
Value0 = 0,
Value1 = 1,
MaxValue = byte.MaxValue
}
[Flags]
public enum FlagsEnum
{
Value1 = 1,
Value2 = 2,
Value4 = 4,
Value8 = 8
}
} }
} }
#endif #endif

View File

@ -72,10 +72,10 @@ namespace Microsoft.AspNet.Mvc
var modelState = new ModelStateDictionary(); var modelState = new ModelStateDictionary();
modelState.Add( modelState.Add(
"key1", "key1",
new ModelState() { Value = new ValueProviderResult("foo", "foo", CultureInfo.InvariantCulture) }); new ModelState());
modelState.Add( modelState.Add(
"key2", "key2",
new ModelState() { Value = new ValueProviderResult("bar", "bar", CultureInfo.InvariantCulture) }); new ModelState());
// Act // Act
var serializableError = new SerializableError(modelState); var serializableError = new SerializableError(modelState);

View File

@ -2086,13 +2086,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert // Assert
var result = await ReadValue<UserWithAddress>(response); var result = await ReadValue<UserWithAddress>(response);
Assert.Empty(result.Addresses);
// Though posted content did not contain any valid Addresses, it is bound as a single-element List
// containing null. Slightly odd behavior is specific to this unusual error case: CollectionModelBinder
// attempted to bind a comma-separated string as a collection and Address lacks a from-string conversion.
// MutableObjectModelBinder does not create model when value providers have no data (unless at top level).
var address = Assert.Single(result.Addresses);
Assert.Null(address);
} }
[Fact] [Fact]
@ -2153,12 +2147,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert // Assert
var result = await ReadValue<PeopleModel>(response); var result = await ReadValue<PeopleModel>(response);
// Though posted content did not contain any valid People, it is bound as a single-element List Assert.Empty(result.People);
// containing null. Slightly odd behavior is specific to this unusual error case: CollectionModelBinder
// attempted to bind a comma-separated string as a collection and Address lacks a from-string conversion.
// MutableObjectModelBinder does not create model when value providers have no data (unless at top level).
var person = Assert.Single(result.People);
Assert.Null(person);
} }
[Theory] [Theory]

View File

@ -65,9 +65,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(1, modelState.Keys.Count); Assert.Equal(1, modelState.Keys.Count);
var key = Assert.Single(modelState.Keys, k => k == "Address[0].Street"); var key = Assert.Single(modelState.Keys, k => k == "Address[0].Street");
Assert.NotNull(modelState[key].Value); Assert.Equal("SomeStreet", modelState[key].AttemptedValue);
Assert.Equal("SomeStreet", modelState[key].Value.AttemptedValue); Assert.Equal("SomeStreet", modelState[key].RawValue);
Assert.Equal("SomeStreet", modelState[key].Value.RawValue);
Assert.Empty(modelState[key].Errors); Assert.Empty(modelState[key].Errors);
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
} }
@ -116,7 +115,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state); Assert.NotNull(state);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
Assert.Equal("SomeStreet", state.Value.RawValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.AttemptedValue);
} }
private class Person4 private class Person4
@ -161,9 +161,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(1, modelState.Keys.Count); Assert.Equal(1, modelState.Keys.Count);
var key = Assert.Single(modelState.Keys, k => k == "Address[0].Street"); var key = Assert.Single(modelState.Keys, k => k == "Address[0].Street");
Assert.NotNull(modelState[key].Value); Assert.Equal("SomeStreet", modelState[key].AttemptedValue);
Assert.Equal("SomeStreet", modelState[key].Value.AttemptedValue); Assert.Equal("SomeStreet", modelState[key].RawValue);
Assert.Equal("SomeStreet", modelState[key].Value.RawValue);
Assert.Empty(modelState[key].Errors); Assert.Empty(modelState[key].Errors);
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
} }
@ -250,9 +249,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(1, modelState.Keys.Count); Assert.Equal(1, modelState.Keys.Count);
var key = Assert.Single(modelState.Keys, k => k == "prefix.Address[0].Street"); var key = Assert.Single(modelState.Keys, k => k == "prefix.Address[0].Street");
Assert.NotNull(modelState[key].Value); Assert.Equal("SomeStreet", modelState[key].AttemptedValue);
Assert.Equal("SomeStreet", modelState[key].Value.AttemptedValue); Assert.Equal("SomeStreet", modelState[key].RawValue);
Assert.Equal("SomeStreet", modelState[key].Value.RawValue);
Assert.Empty(modelState[key].Errors); Assert.Empty(modelState[key].Errors);
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
} }
@ -300,7 +298,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state); Assert.NotNull(state);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
Assert.Equal("SomeStreet", state.Value.RawValue); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.RawValue);
} }
[Fact] [Fact]
@ -343,9 +342,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(1, modelState.Keys.Count); Assert.Equal(1, modelState.Keys.Count);
var key = Assert.Single(modelState.Keys, k => k == "prefix.Address[0].Street"); var key = Assert.Single(modelState.Keys, k => k == "prefix.Address[0].Street");
Assert.NotNull(modelState[key].Value); Assert.Equal("SomeStreet", modelState[key].AttemptedValue);
Assert.Equal("SomeStreet", modelState[key].Value.AttemptedValue); Assert.Equal("SomeStreet", modelState[key].RawValue);
Assert.Equal("SomeStreet", modelState[key].Value.RawValue);
Assert.Empty(modelState[key].Errors); Assert.Empty(modelState[key].Errors);
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
} }

View File

@ -44,12 +44,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0]").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1]").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -89,12 +89,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0]").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1]").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -130,12 +130,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "[0]").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "[1]").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -208,12 +208,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Name").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1].Name").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1].Name").Value;
Assert.Equal("lang", entry.Value.AttemptedValue); Assert.Equal("lang", entry.AttemptedValue);
Assert.Equal("lang", entry.Value.RawValue); Assert.Equal("lang", entry.RawValue);
} }
[Fact] [Fact]
@ -254,12 +254,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0].Name").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0].Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1].Name").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1].Name").Value;
Assert.Equal("lang", entry.Value.AttemptedValue); Assert.Equal("lang", entry.AttemptedValue);
Assert.Equal("lang", entry.Value.RawValue); Assert.Equal("lang", entry.RawValue);
} }
[Fact] [Fact]
@ -296,12 +296,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "[0].Name").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "[0].Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "[1].Name").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "[1].Name").Value;
Assert.Equal("lang", entry.Value.AttemptedValue); Assert.Equal("lang", entry.AttemptedValue);
Assert.Equal("lang", entry.Value.RawValue); Assert.Equal("lang", entry.RawValue);
} }
[Fact] [Fact]

View File

@ -190,7 +190,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var key = Assert.Single(modelState.Keys); var key = Assert.Single(modelState.Keys);
Assert.Equal("CustomParameter", key); Assert.Equal("CustomParameter", key);
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
Assert.NotNull(modelState[key].Value); // Value is set by test model binder, no need to validate it. Assert.NotNull(modelState[key].RawValue); // Value is set by test model binder, no need to validate it.
} }
private class Person private class Person
@ -239,7 +239,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(1, modelState.Keys.Count); Assert.Equal(1, modelState.Keys.Count);
var key = Assert.Single(modelState.Keys, k => k == "Parameter1.Address.Street"); var key = Assert.Single(modelState.Keys, k => k == "Parameter1.Address.Street");
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
Assert.NotNull(modelState[key].Value); // Value is set by test model binder, no need to validate it. Assert.NotNull(modelState[key].RawValue); // Value is set by test model binder, no need to validate it.
} }
[Fact] [Fact]
@ -279,7 +279,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(1, modelState.Keys.Count); Assert.Equal(1, modelState.Keys.Count);
var key = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address.Street"); var key = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address.Street");
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
Assert.NotNull(modelState[key].Value); // Value is set by test model binder, no need to validate it. Assert.NotNull(modelState[key].RawValue); // Value is set by test model binder, no need to validate it.
} }
private class AddressModelBinder : IModelBinder private class AddressModelBinder : IModelBinder
@ -294,11 +294,9 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var address = new Address() { Street = "SomeStreet" }; var address = new Address() { Street = "SomeStreet" };
bindingContext.ModelState.SetModelValue( bindingContext.ModelState.SetModelValue(
ModelNames.CreatePropertyModelName(bindingContext.ModelName, "Street"), ModelNames.CreatePropertyModelName(bindingContext.ModelName, "Street"),
new ValueProviderResult( new string[] { address.Street },
address.Street, address.Street);
address.Street,
CultureInfo.CurrentCulture));
var validationNode = new ModelValidationNode( var validationNode = new ModelValidationNode(
bindingContext.ModelName, bindingContext.ModelName,
@ -319,7 +317,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var model = "Success"; var model = "Success";
bindingContext.ModelState.SetModelValue( bindingContext.ModelState.SetModelValue(
bindingContext.ModelName, bindingContext.ModelName,
new ValueProviderResult(model, model, CultureInfo.CurrentCulture)); new string[] { model },
model);
var modelValidationNode = new ModelValidationNode( var modelValidationNode = new ModelValidationNode(
bindingContext.ModelName, bindingContext.ModelName,

View File

@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Empty(entry.Key); Assert.Empty(entry.Key);
Assert.Null(entry.Value.Value.RawValue); Assert.Null(entry.Value.RawValue);
} }
private class Person4 private class Person4
@ -112,7 +112,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
public int Address { get; set; } public int Address { get; set; }
} }
[Fact] [Fact(Skip = "#2722 validation error from formatter is recorded with the wrong key.")]
public async Task FromBodyAndRequiredOnValueTypeProperty_EmptyBody_JsonFormatterAddsModelStateError() public async Task FromBodyAndRequiredOnValueTypeProperty_EmptyBody_JsonFormatterAddsModelStateError()
{ {
// Arrange // Arrange
@ -146,7 +146,9 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal(string.Empty, entry.Key); Assert.Equal("CustomParameter.Address", entry.Key);
Assert.Null(entry.Value.AttemptedValue);
Assert.Same(boundPerson, entry.Value.RawValue);
var error = Assert.Single(entry.Value.Errors); var error = Assert.Single(entry.Value.Errors);
Assert.NotNull(error.Exception); Assert.NotNull(error.Exception);

View File

@ -65,8 +65,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(queryStringKey, entry.Key); Assert.Equal(queryStringKey, entry.Key);
Assert.Empty(entry.Value.Errors); Assert.Empty(entry.Value.Errors);
Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState); Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState);
Assert.Equal(value, entry.Value.Value.AttemptedValue); Assert.Equal(value, entry.Value.AttemptedValue);
Assert.Equal(value, entry.Value.Value.RawValue); Assert.Equal(value, entry.Value.RawValue);
} }
[Fact] [Fact]
@ -146,8 +146,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("CustomParameter", entry.Key); Assert.Equal("CustomParameter", entry.Key);
Assert.Empty(entry.Value.Errors); Assert.Empty(entry.Value.Errors);
Assert.Equal(value, entry.Value.Value.AttemptedValue); Assert.Equal(value, entry.Value.AttemptedValue);
Assert.Equal(value, entry.Value.Value.RawValue); Assert.Equal(value, entry.Value.RawValue);
} }
} }
} }

View File

@ -51,12 +51,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0]").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1]").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -96,12 +96,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0]").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1]").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -137,12 +137,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "[0]").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "[1]").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -215,12 +215,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Id").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1].Id").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -261,12 +261,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0].Id").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1].Id").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -303,12 +303,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "[0].Id").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "[1].Id").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -386,21 +386,21 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Id").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1].Id").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Name").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Name").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage); Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1].Name").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[1].Name").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
error = Assert.Single(entry.Errors); error = Assert.Single(entry.Errors);
Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage); Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage);
@ -446,19 +446,19 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0].Id").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1].Id").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0].Name").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[0].Name").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1].Name").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "prefix[1].Name").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
} }
@ -498,19 +498,19 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "[0].Id").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "[0].Id").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "[1].Id").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "[1].Id").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "[0].Name").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "[0].Name").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
entry = Assert.Single(modelState, kvp => kvp.Key == "[1].Name").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "[1].Name").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
} }
@ -595,12 +595,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(0, modelState.ErrorCount); Assert.Equal(0, modelState.ErrorCount);
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "Addresses[Key1].Street").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "Addresses[Key1].Street").Value;
Assert.Equal("Street1", entry.Value.AttemptedValue); Assert.Equal("Street1", entry.AttemptedValue);
Assert.Equal("Street1", entry.Value.RawValue); Assert.Equal("Street1", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "Addresses[Key2].Street").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "Addresses[Key2].Street").Value;
Assert.Equal("Street2", entry.Value.AttemptedValue); Assert.Equal("Street2", entry.AttemptedValue);
Assert.Equal("Street2", entry.Value.RawValue); Assert.Equal("Street2", entry.RawValue);
} }
private class Person5 private class Person5

View File

@ -45,12 +45,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Key").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.RawValue); Assert.Equal("key0", entry.RawValue);
entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Value").Value; entry = Assert.Single(modelState, kvp => kvp.Key == "parameter[0].Value").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Fact] [Fact]
@ -87,8 +87,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var kvp = Assert.Single(modelState); var kvp = Assert.Single(modelState);
Assert.Equal("parameter[key0]", kvp.Key); Assert.Equal("parameter[key0]", kvp.Key);
var entry = kvp.Value; var entry = kvp.Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Theory] [Theory]

View File

@ -71,7 +71,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(2, modelState.Count); Assert.Equal(2, modelState.Count);
Assert.Single(modelState.Keys, k => k == "Address.Zip"); Assert.Single(modelState.Keys, k => k == "Address.Zip");
var key = Assert.Single(modelState.Keys, k => k == "Address.File"); var key = Assert.Single(modelState.Keys, k => k == "Address.File");
Assert.NotNull(modelState[key].Value); Assert.Null(modelState[key].RawValue);
Assert.Empty(modelState[key].Errors); Assert.Empty(modelState[key].Errors);
Assert.Equal(ModelValidationState.Skipped, modelState[key].ValidationState); Assert.Equal(ModelValidationState.Skipped, modelState[key].ValidationState);
} }
@ -122,8 +122,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("CustomParameter", entry.Key); Assert.Equal("CustomParameter", entry.Key);
Assert.Empty(entry.Value.Errors); Assert.Empty(entry.Value.Errors);
Assert.Equal(ModelValidationState.Skipped, entry.Value.ValidationState); Assert.Equal(ModelValidationState.Skipped, entry.Value.ValidationState);
Assert.Null(entry.Value.Value.AttemptedValue); Assert.Null(entry.Value.AttemptedValue);
Assert.Equal(file, entry.Value.Value.RawValue); Assert.Null(entry.Value.RawValue);
} }
[Fact] [Fact]

View File

@ -276,12 +276,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter[0][0].Key").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter[0][0].Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.RawValue); Assert.Equal("key0", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter[0][0].Value").Value; entry = Assert.Single(modelState, e => e.Key == "parameter[0][0].Value").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
// This is part of a random sampling of scenarios where a GenericModelBinder is used // This is part of a random sampling of scenarios where a GenericModelBinder is used
@ -322,12 +322,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "[0][0].Key").Value; var entry = Assert.Single(modelState, e => e.Key == "[0][0].Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.RawValue); Assert.Equal("key0", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "[0][0].Value").Value; entry = Assert.Single(modelState, e => e.Key == "[0][0].Value").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
// This is part of a random sampling of scenarios where a GenericModelBinder is used // This is part of a random sampling of scenarios where a GenericModelBinder is used
@ -403,12 +403,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter[0].Key").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter[0].Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.RawValue); Assert.Equal("key0", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter[0].Value").Value; entry = Assert.Single(modelState, e => e.Key == "parameter[0].Value").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
// This is part of a random sampling of scenarios where a GenericModelBinder is used // This is part of a random sampling of scenarios where a GenericModelBinder is used
@ -448,12 +448,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "[0].Key").Value; var entry = Assert.Single(modelState, e => e.Key == "[0].Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.RawValue); Assert.Equal("key0", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "[0].Value").Value; entry = Assert.Single(modelState, e => e.Key == "[0].Value").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
// This is part of a random sampling of scenarios where a GenericModelBinder is used // This is part of a random sampling of scenarios where a GenericModelBinder is used
@ -530,16 +530,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter[0].Key").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter[0].Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.RawValue); Assert.Equal("key0", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter[0].Value[0]").Value; entry = Assert.Single(modelState, e => e.Key == "parameter[0].Value[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter[0].Value[1]").Value; entry = Assert.Single(modelState, e => e.Key == "parameter[0].Value[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
// This is part of a random sampling of scenarios where a GenericModelBinder is used // This is part of a random sampling of scenarios where a GenericModelBinder is used
@ -579,16 +579,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "[0].Key").Value; var entry = Assert.Single(modelState, e => e.Key == "[0].Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.RawValue); Assert.Equal("key0", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "[0].Value[0]").Value; entry = Assert.Single(modelState, e => e.Key == "[0].Value[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "[0].Value[1]").Value; entry = Assert.Single(modelState, e => e.Key == "[0].Value[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
// This is part of a random sampling of scenarios where a GenericModelBinder is used // This is part of a random sampling of scenarios where a GenericModelBinder is used

View File

@ -109,8 +109,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("prefix.Address.Header", entry.Key); Assert.Equal("prefix.Address.Header", entry.Key);
Assert.Empty(entry.Value.Errors); Assert.Empty(entry.Value.Errors);
Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState); Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState);
Assert.Equal("someValue", entry.Value.Value.AttemptedValue); Assert.Equal("someValue", entry.Value.AttemptedValue);
Assert.Equal("someValue", entry.Value.Value.RawValue); Assert.Equal(new string[] { "someValue" }, entry.Value.RawValue);
} }
// The scenario is interesting as we to bind the top level model we fallback to empty prefix, // The scenario is interesting as we to bind the top level model we fallback to empty prefix,
@ -152,8 +152,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("Address.Header", entry.Key); Assert.Equal("Address.Header", entry.Key);
Assert.Empty(entry.Value.Errors); Assert.Empty(entry.Value.Errors);
Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState); Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState);
Assert.Equal("someValue", entry.Value.Value.AttemptedValue); Assert.Equal("someValue", entry.Value.AttemptedValue);
Assert.Equal("someValue", entry.Value.Value.RawValue); Assert.Equal(new string[] { "someValue" }, entry.Value.RawValue);
} }
[Theory] [Theory]
@ -162,9 +162,18 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
public async Task BindParameterFromHeader_WithData_WithPrefix_ModelGetsBound(Type modelType, string value) public async Task BindParameterFromHeader_WithData_WithPrefix_ModelGetsBound(Type modelType, string value)
{ {
// Arrange // Arrange
var expectedValue = modelType == typeof(string) ? object expectedValue;
(object)value : object expectedRawValue;
(object)value.Split(',').Select(v => v.Trim()).ToArray(); if (modelType == typeof(string))
{
expectedValue = value;
expectedRawValue = new string[] { value };
}
else
{
expectedValue = value.Split(',').Select(v => v.Trim()).ToArray();
expectedRawValue = expectedValue;
}
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor var parameter = new ParameterDescriptor
@ -204,8 +213,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("CustomParameter", entry.Key); Assert.Equal("CustomParameter", entry.Key);
Assert.Empty(entry.Value.Errors); Assert.Empty(entry.Value.Errors);
Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState); Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState);
Assert.Equal(value, entry.Value.Value.AttemptedValue); Assert.Equal(value, entry.Value.AttemptedValue);
Assert.Equal(expectedValue, entry.Value.Value.RawValue); Assert.Equal(expectedRawValue, entry.Value.RawValue);
} }
} }
} }

View File

@ -45,12 +45,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
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.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.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.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Fact] [Fact]
@ -90,12 +90,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
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.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.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.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Fact] [Fact]
@ -131,12 +131,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "Key").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.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.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Fact] [Fact]
@ -210,12 +210,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
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.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.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.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal(model.Value.Id.ToString(), entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Fact] [Fact]
@ -256,12 +256,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
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.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.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.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Fact] [Fact]
@ -298,12 +298,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, kvp => kvp.Key == "Key").Value; var entry = Assert.Single(modelState, kvp => kvp.Key == "Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.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.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Fact] [Fact]

View File

@ -82,12 +82,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Address").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Address").Value;
Assert.Null(entry.Value.AttemptedValue); // ModelState entries for body don't include original text. Assert.Null(entry.AttemptedValue); // ModelState entries for body don't include original text.
Assert.Same(model.Customer.Address, entry.Value.RawValue); Assert.Same(model.Customer.Address, entry.RawValue);
} }
[Fact] [Fact]
@ -128,12 +128,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "Customer.Address").Value; entry = Assert.Single(modelState, e => e.Key == "Customer.Address").Value;
Assert.Null(entry.Value.AttemptedValue); // ModelState entries for body don't include original text. Assert.Null(entry.AttemptedValue); // ModelState entries for body don't include original text.
Assert.Same(model.Customer.Address, entry.Value.RawValue); Assert.Same(model.Customer.Address, entry.RawValue);
} }
[Fact] [Fact]
@ -173,11 +173,11 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Address").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Address").Value;
Assert.Null(entry.Value.AttemptedValue); Assert.Null(entry.AttemptedValue);
Assert.Null(entry.Value.RawValue); Assert.Null(entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
} }
// We don't provide enough data in this test for the 'Person' model to be created. So even though there is // We don't provide enough data in this test for the 'Person' model to be created. So even though there is
@ -218,8 +218,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
// We don't provide enough data in this test for the 'Person' model to be created. So even though there is // We don't provide enough data in this test for the 'Person' model to be created. So even though there is
@ -310,8 +310,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
} }
[Fact] [Fact]
@ -350,8 +350,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
} }
// We don't provide enough data in this test for the 'Person' model to be created. So even though there is // We don't provide enough data in this test for the 'Person' model to be created. So even though there is
@ -392,8 +392,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
// We don't provide enough data in this test for the 'Person' model to be created. So even though there is // We don't provide enough data in this test for the 'Person' model to be created. So even though there is
@ -484,12 +484,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Token").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Token").Value;
Assert.Equal(ByteArrayEncoded, entry.Value.AttemptedValue); Assert.Equal(ByteArrayEncoded, entry.AttemptedValue);
Assert.Equal(ByteArrayEncoded, entry.Value.RawValue); Assert.Equal(ByteArrayEncoded, entry.RawValue);
} }
[Fact] [Fact]
@ -528,12 +528,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "Customer.Token").Value; entry = Assert.Single(modelState, e => e.Key == "Customer.Token").Value;
Assert.Equal(ByteArrayEncoded, entry.Value.AttemptedValue); Assert.Equal(ByteArrayEncoded, entry.AttemptedValue);
Assert.Equal(ByteArrayEncoded, entry.Value.RawValue); Assert.Equal(ByteArrayEncoded, entry.RawValue);
} }
[Fact] [Fact]
@ -572,8 +572,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
} }
private class Order4 private class Order4
@ -627,12 +627,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Documents").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Documents").Value;
Assert.Null(entry.Value.AttemptedValue); // FormFile entries for body don't include original text. Assert.Null(entry.AttemptedValue); // FormFile entries for body don't include original text.
Assert.Same(model.Customer.Documents, entry.Value.RawValue); Assert.Null(entry.RawValue);
} }
[Fact] [Fact]
@ -672,12 +672,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "Customer.Documents").Value; entry = Assert.Single(modelState, e => e.Key == "Customer.Documents").Value;
Assert.Null(entry.Value.AttemptedValue); // FormFile entries for body don't include original text. Assert.Null(entry.AttemptedValue); // FormFile entries don't include the model.
Assert.Same(model.Customer.Documents, entry.Value.RawValue); Assert.Null(entry.RawValue);
} }
[Fact] [Fact]
@ -718,13 +718,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Documents").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Documents").Value;
Assert.Null(entry.Value.AttemptedValue); Assert.Null(entry.AttemptedValue); // FormFile entries don't include the model.
var documents = Assert.IsAssignableFrom<IEnumerable<IFormFile>>(entry.Value.RawValue); Assert.Null(entry.RawValue);
Assert.Empty(documents);
entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
} }
// We don't provide enough data in this test for the 'Person' model to be created. So even though there are // We don't provide enough data in this test for the 'Person' model to be created. So even though there are
@ -765,8 +764,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
// We don't provide enough data in this test for the 'Person' model to be created. So even though there is // We don't provide enough data in this test for the 'Person' model to be created. So even though there is
@ -849,16 +848,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[0]").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[1]").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -897,16 +896,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Name").Value; var entry = Assert.Single(modelState, e => e.Key == "Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "ProductIds[0]").Value; entry = Assert.Single(modelState, e => e.Key == "ProductIds[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "ProductIds[1]").Value; entry = Assert.Single(modelState, e => e.Key == "ProductIds[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -944,8 +943,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
} }
[Fact] [Fact]
@ -1026,16 +1025,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[0]").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[1]").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -1074,16 +1073,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Name").Value; var entry = Assert.Single(modelState, e => e.Key == "Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "ProductIds[0]").Value; entry = Assert.Single(modelState, e => e.Key == "ProductIds[0]").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "ProductIds[1]").Value; entry = Assert.Single(modelState, e => e.Key == "ProductIds[1]").Value;
Assert.Equal("11", entry.Value.AttemptedValue); Assert.Equal("11", entry.AttemptedValue);
Assert.Equal("11", entry.Value.RawValue); Assert.Equal("11", entry.RawValue);
} }
[Fact] [Fact]
@ -1121,8 +1120,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
} }
[Fact] [Fact]
@ -1203,16 +1202,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[0].Key").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[0].Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.RawValue); Assert.Equal("key0", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[0].Value").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.ProductIds[0].Value").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Fact] [Fact]
@ -1251,16 +1250,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Name").Value; var entry = Assert.Single(modelState, e => e.Key == "Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "ProductIds[0].Key").Value; entry = Assert.Single(modelState, e => e.Key == "ProductIds[0].Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.RawValue); Assert.Equal("key0", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "ProductIds[0].Value").Value; entry = Assert.Single(modelState, e => e.Key == "ProductIds[0].Value").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Fact] [Fact]
@ -1298,8 +1297,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
} }
[Fact] [Fact]
@ -1380,16 +1379,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId.Key").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId.Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.RawValue); Assert.Equal("key0", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId.Value").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId.Value").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Fact] [Fact]
@ -1428,16 +1427,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Name").Value; var entry = Assert.Single(modelState, e => e.Key == "Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "ProductId.Key").Value; entry = Assert.Single(modelState, e => e.Key == "ProductId.Key").Value;
Assert.Equal("key0", entry.Value.AttemptedValue); Assert.Equal("key0", entry.AttemptedValue);
Assert.Equal("key0", entry.Value.RawValue); Assert.Equal("key0", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "ProductId.Value").Value; entry = Assert.Single(modelState, e => e.Key == "ProductId.Value").Value;
Assert.Equal("10", entry.Value.AttemptedValue); Assert.Equal("10", entry.AttemptedValue);
Assert.Equal("10", entry.Value.RawValue); Assert.Equal("10", entry.RawValue);
} }
[Fact] [Fact]
@ -1475,8 +1474,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
} }
[Fact] [Fact]
@ -1568,8 +1567,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Customer.Address").Value; var entry = Assert.Single(modelState, e => e.Key == "Customer.Address").Value;
Assert.Null(entry.Value.AttemptedValue); Assert.Null(entry.AttemptedValue);
Assert.Same(model.Customer.Address, entry.Value.RawValue); Assert.Same(model.Customer.Address, entry.RawValue);
} }
private class Order10 private class Order10
@ -1616,7 +1615,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Customer").Value; var entry = Assert.Single(modelState, e => e.Key == "Customer").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
var error = Assert.Single(modelState["Customer"].Errors); var error = Assert.Single(modelState["Customer"].Errors);
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);
} }
@ -1670,12 +1670,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Id").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Id").Value;
Assert.NotNull(entry.Value); Assert.Equal("123", entry.RawValue);
Assert.Equal("123", entry.Value.RawValue); Assert.Equal("123", entry.AttemptedValue);
Assert.Equal("123", entry.Value.AttemptedValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
var error = Assert.Single(modelState["parameter.Customer.Name"].Errors); var error = Assert.Single(modelState["parameter.Customer.Name"].Errors);
Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage); Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage);
} }
@ -1716,12 +1716,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Customer.Id").Value; var entry = Assert.Single(modelState, e => e.Key == "Customer.Id").Value;
Assert.NotNull(entry.Value); Assert.Equal("123", entry.RawValue);
Assert.Equal("123", entry.Value.RawValue); Assert.Equal("123", entry.AttemptedValue);
Assert.Equal("123", entry.Value.AttemptedValue);
entry = Assert.Single(modelState, e => e.Key == "Customer.Name").Value; entry = Assert.Single(modelState, e => e.Key == "Customer.Name").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
var error = Assert.Single(modelState["Customer.Name"].Errors); var error = Assert.Single(modelState["Customer.Name"].Errors);
Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage); Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage);
} }
@ -1766,12 +1766,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "customParameter.Customer.Id").Value; var entry = Assert.Single(modelState, e => e.Key == "customParameter.Customer.Id").Value;
Assert.NotNull(entry.Value); Assert.Equal("123", entry.RawValue);
Assert.Equal("123", entry.Value.RawValue); Assert.Equal("123", entry.AttemptedValue);
Assert.Equal("123", entry.Value.AttemptedValue);
entry = Assert.Single(modelState, e => e.Key == "customParameter.Customer.Name").Value; entry = Assert.Single(modelState, e => e.Key == "customParameter.Customer.Name").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
var error = Assert.Single(modelState["customParameter.Customer.Name"].Errors); var error = Assert.Single(modelState["customParameter.Customer.Name"].Errors);
Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage); Assert.Equal("A value for the 'Name' property was not provided.", error.ErrorMessage);
} }
@ -1816,7 +1816,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "ProductName").Value; var entry = Assert.Single(modelState, e => e.Key == "ProductName").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
var error = Assert.Single(modelState["ProductName"].Errors); var error = Assert.Single(modelState["ProductName"].Errors);
Assert.Equal("A value for the 'ProductName' property was not provided.", error.ErrorMessage); Assert.Equal("A value for the 'ProductName' property was not provided.", error.ErrorMessage);
} }
@ -1859,7 +1860,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "customParameter.ProductName").Value; var entry = Assert.Single(modelState, e => e.Key == "customParameter.ProductName").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
var error = Assert.Single(modelState["customParameter.ProductName"].Errors); var error = Assert.Single(modelState["customParameter.ProductName"].Errors);
Assert.Equal("A value for the 'ProductName' property was not provided.", error.ErrorMessage); Assert.Equal("A value for the 'ProductName' property was not provided.", error.ErrorMessage);
} }
@ -1898,9 +1900,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "ProductName").Value; var entry = Assert.Single(modelState, e => e.Key == "ProductName").Value;
Assert.NotNull(entry.Value); Assert.Equal("abc", entry.RawValue);
Assert.Equal("abc", entry.Value.RawValue); Assert.Equal("abc", entry.AttemptedValue);
Assert.Equal("abc", entry.Value.AttemptedValue);
} }
private class Order13 private class Order13
@ -1943,7 +1944,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "OrderIds").Value; var entry = Assert.Single(modelState, e => e.Key == "OrderIds").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
var error = Assert.Single(modelState["OrderIds"].Errors); var error = Assert.Single(modelState["OrderIds"].Errors);
Assert.Equal("A value for the 'OrderIds' property was not provided.", error.ErrorMessage); Assert.Equal("A value for the 'OrderIds' property was not provided.", error.ErrorMessage);
} }
@ -1986,7 +1988,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "customParameter.OrderIds").Value; var entry = Assert.Single(modelState, e => e.Key == "customParameter.OrderIds").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
var error = Assert.Single(modelState["customParameter.OrderIds"].Errors); var error = Assert.Single(modelState["customParameter.OrderIds"].Errors);
Assert.Equal("A value for the 'OrderIds' property was not provided.", error.ErrorMessage); Assert.Equal("A value for the 'OrderIds' property was not provided.", error.ErrorMessage);
} }
@ -2025,9 +2028,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "OrderIds[0]").Value; var entry = Assert.Single(modelState, e => e.Key == "OrderIds[0]").Value;
Assert.NotNull(entry.Value); Assert.Equal("123", entry.RawValue);
Assert.Equal("123", entry.Value.RawValue); Assert.Equal("123", entry.AttemptedValue);
Assert.Equal("123", entry.Value.AttemptedValue);
} }
private class Order14 private class Order14
@ -2072,8 +2074,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId").Value;
Assert.Equal(string.Empty, entry.Value.AttemptedValue); Assert.Equal(string.Empty, entry.AttemptedValue);
Assert.Equal(string.Empty, entry.Value.RawValue); Assert.Equal(string.Empty, entry.RawValue);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
Assert.Equal("The value '' is invalid.", error.ErrorMessage); Assert.Equal("The value '' is invalid.", error.ErrorMessage);

View File

@ -13,7 +13,7 @@ using Xunit;
namespace Microsoft.AspNet.Mvc.IntegrationTests namespace Microsoft.AspNet.Mvc.IntegrationTests
{ {
public class TypeConverterModelBinderIntegrationTest public class SimpleTypeModelBinderIntegrationTest
{ {
[Fact] [Fact]
public async Task BindProperty_WithData_WithPrefix_GetsBound() public async Task BindProperty_WithData_WithPrefix_GetsBound()
@ -58,10 +58,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(1, modelState.Keys.Count); Assert.Equal(1, modelState.Keys.Count);
var key = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address.Zip"); var key = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address.Zip");
Assert.NotNull(modelState[key].Value); Assert.Equal("1", modelState[key].AttemptedValue);
Assert.Equal("1", modelState[key].Value.AttemptedValue); Assert.Equal("1", modelState[key].RawValue);
Assert.Equal("1", modelState[key].Value.RawValue);
Assert.NotNull(modelState[key].Value);
Assert.Empty(modelState[key].Errors); Assert.Empty(modelState[key].Errors);
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
} }
@ -105,10 +103,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(1, modelState.Keys.Count); Assert.Equal(1, modelState.Keys.Count);
var key = Assert.Single(modelState.Keys, k => k == "Address.Zip"); var key = Assert.Single(modelState.Keys, k => k == "Address.Zip");
Assert.NotNull(modelState[key].Value); Assert.Equal("1", modelState[key].AttemptedValue);
Assert.Equal("1", modelState[key].Value.AttemptedValue); Assert.Equal("1", modelState[key].RawValue);
Assert.Equal("1", modelState[key].Value.RawValue);
Assert.NotNull(modelState[key].Value);
Assert.Empty(modelState[key].Errors); Assert.Empty(modelState[key].Errors);
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
} }
@ -152,13 +148,56 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(1, modelState.Keys.Count); Assert.Equal(1, modelState.Keys.Count);
var key = Assert.Single(modelState.Keys); var key = Assert.Single(modelState.Keys);
Assert.Equal("Parameter1", key); Assert.Equal("Parameter1", key);
Assert.NotNull(modelState[key].Value); Assert.Equal("someValue", modelState[key].AttemptedValue);
Assert.Equal("someValue", modelState[key].Value.AttemptedValue); Assert.Equal("someValue", modelState[key].RawValue);
Assert.Equal("someValue", modelState[key].Value.RawValue);
Assert.Empty(modelState[key].Errors); Assert.Empty(modelState[key].Errors);
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
} }
[Fact]
public async Task BindParameter_WithMultipleValues_GetsBoundToFirstValue()
{
// Arrange
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "Parameter1",
BindingInfo = new BindingInfo(),
ParameterType = typeof(string)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
{
request.QueryString = new QueryString("?Parameter1=someValue&Parameter1=otherValue");
});
var modelState = new ModelStateDictionary();
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
// ModelBindingResult
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
// Model
var model = Assert.IsType<string>(modelBindingResult.Model);
Assert.Equal("someValue", model);
// ModelState
Assert.True(modelState.IsValid);
Assert.Equal(1, modelState.Keys.Count);
var key = Assert.Single(modelState.Keys);
Assert.Equal("Parameter1", key);
Assert.Equal("someValue,otherValue", modelState[key].AttemptedValue);
Assert.Equal(new string[] { "someValue", "otherValue" }, modelState[key].RawValue);
Assert.Empty(modelState[key].Errors);
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
}
[Fact] [Fact]
public async Task BindParameter_NonConvertableValue_GetsError() public async Task BindParameter_NonConvertableValue_GetsError()
@ -201,9 +240,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("Parameter1", key); Assert.Equal("Parameter1", key);
var entry = modelState[key]; var entry = modelState[key];
Assert.NotNull(entry.Value); Assert.Equal("abcd", entry.RawValue);
Assert.Equal("abcd", entry.Value.AttemptedValue); Assert.Equal("abcd", entry.AttemptedValue);
Assert.Equal("abcd", entry.Value.RawValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
@ -247,8 +285,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var key = Assert.Single(modelState.Keys); var key = Assert.Single(modelState.Keys);
Assert.Equal("Parameter1", key); Assert.Equal("Parameter1", key);
Assert.Equal(string.Empty, modelState[key].Value.AttemptedValue); Assert.Equal(string.Empty, modelState[key].AttemptedValue);
Assert.Equal(string.Empty, modelState[key].Value.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(error.ErrorMessage, "The value '' is invalid.", StringComparer.Ordinal);
Assert.Null(error.Exception); Assert.Null(error.Exception);
@ -292,8 +330,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var key = Assert.Single(modelState.Keys); var key = Assert.Single(modelState.Keys);
Assert.Equal("Parameter1", key); Assert.Equal("Parameter1", key);
Assert.Equal(string.Empty, modelState[key].Value.AttemptedValue); Assert.Equal(string.Empty, modelState[key].AttemptedValue);
Assert.Equal(string.Empty, modelState[key].Value.RawValue); Assert.Equal(new string[] { string.Empty }, modelState[key].RawValue);
Assert.Empty(modelState[key].Errors); Assert.Empty(modelState[key].Errors);
} }
@ -393,10 +431,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.NotNull(entry); Assert.NotNull(entry);
Assert.Empty(entry.Errors); Assert.Empty(entry.Errors);
Assert.Equal(ModelValidationState.Valid, entry.ValidationState); Assert.Equal(ModelValidationState.Valid, entry.ValidationState);
var result = entry.Value; Assert.Equal("line 1,line 2", entry.AttemptedValue);
Assert.NotNull(result); Assert.Equal(new[] { "line 1", "line 2" }, entry.RawValue);
Assert.Equal("line 1,line 2", result.AttemptedValue);
Assert.Equal(new[] { "line 1", "line 2" }, result.RawValue);
} }
private class Person private class Person

View File

@ -53,9 +53,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("Street", entry.Key); Assert.Equal("Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -88,9 +87,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("Street", entry.Key); Assert.Equal("Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -199,9 +197,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("Address.Street", entry.Key); Assert.Equal("Address.Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -241,9 +238,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("Address[0].Street", entry.Key); Assert.Equal("Address[0].Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -283,9 +279,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("Address[0].Street", entry.Key); Assert.Equal("Address[0].Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -345,9 +340,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("Address[0].Street", entry.Key); Assert.Equal("Address[0].Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -387,7 +381,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state); Assert.NotNull(state);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
Assert.Equal("SomeStreet", state.Value.RawValue); Assert.Equal("SomeStreet", state.RawValue);
} }
private class Person4 private class Person4
@ -425,9 +419,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("Address[0].Street", entry.Key); Assert.Equal("Address[0].Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -474,9 +467,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("Address[0].Street", entry.Key); Assert.Equal("Address[0].Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -550,9 +542,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("prefix.Street", entry.Key); Assert.Equal("prefix.Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -585,9 +576,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("prefix.Street", entry.Key); Assert.Equal("prefix.Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -689,9 +679,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("prefix.Address.Street", entry.Key); Assert.Equal("prefix.Address.Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -726,9 +715,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("prefix.Address[0].Street", entry.Key); Assert.Equal("prefix.Address[0].Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -768,9 +756,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("prefix.Address[0].Street", entry.Key); Assert.Equal("prefix.Address[0].Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -820,9 +807,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("prefix.Address[0].Street", entry.Key); Assert.Equal("prefix.Address[0].Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -857,7 +843,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state); Assert.NotNull(state);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
Assert.Equal("SomeStreet", state.Value.RawValue); Assert.Equal("SomeStreet", state.RawValue);
} }
[Fact] [Fact]
@ -890,9 +876,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("prefix.Address[0].Street", entry.Key); Assert.Equal("prefix.Address[0].Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }
@ -939,9 +924,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState); var entry = Assert.Single(modelState);
Assert.Equal("prefix.Address[0].Street", entry.Key); Assert.Equal("prefix.Address[0].Street", entry.Key);
var state = entry.Value; var state = entry.Value;
Assert.NotNull(state.Value); Assert.Equal("SomeStreet", state.AttemptedValue);
Assert.Equal("SomeStreet", state.Value.AttemptedValue); Assert.Equal("SomeStreet", state.RawValue);
Assert.Equal("SomeStreet", state.Value.RawValue);
Assert.Empty(state.Errors); Assert.Empty(state.Errors);
Assert.Equal(ModelValidationState.Valid, state.ValidationState); Assert.Equal(ModelValidationState.Valid, state.ValidationState);
} }

View File

@ -53,8 +53,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.CustomerName").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.CustomerName").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
Assert.Empty(entry.Errors); Assert.Empty(entry.Errors);
} }
@ -91,7 +91,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "CustomerName").Value; var entry = Assert.Single(modelState, e => e.Key == "CustomerName").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
@ -143,8 +144,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
Assert.Empty(entry.Errors); Assert.Empty(entry.Errors);
} }
@ -181,7 +182,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Customer").Value; var entry = Assert.Single(modelState, e => e.Key == "Customer").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
@ -235,8 +237,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
Assert.Empty(entry.Errors); Assert.Empty(entry.Errors);
} }
@ -276,7 +278,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
@ -328,8 +331,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Items[0].ItemId").Value; var entry = Assert.Single(modelState, e => e.Key == "Items[0].ItemId").Value;
Assert.Equal("17", entry.Value.AttemptedValue); Assert.Equal("17", entry.AttemptedValue);
Assert.Equal("17", entry.Value.RawValue); Assert.Equal("17", entry.RawValue);
Assert.Empty(entry.Errors); Assert.Empty(entry.Errors);
} }
@ -367,7 +370,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "Items").Value; var entry = Assert.Single(modelState, e => e.Key == "Items").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
@ -415,8 +419,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter[0].ProductId").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter[0].ProductId").Value;
Assert.Equal("17", entry.Value.AttemptedValue); Assert.Equal("17", entry.AttemptedValue);
Assert.Equal("17", entry.Value.RawValue); Assert.Equal("17", entry.RawValue);
Assert.Empty(entry.Errors); Assert.Empty(entry.Errors);
} }
@ -456,7 +460,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter[0].ProductId").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter[0].ProductId").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
@ -502,8 +507,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
Assert.Empty(entry.Errors); Assert.Empty(entry.Errors);
} }
@ -540,8 +545,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Name").Value;
Assert.Equal("billybob", entry.Value.AttemptedValue); Assert.Equal("billybob", entry.AttemptedValue);
Assert.Equal("billybob", entry.Value.RawValue); Assert.Equal("billybob", entry.RawValue);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
Assert.Equal("Too Long.", error.ErrorMessage); Assert.Equal("Too Long.", error.ErrorMessage);
@ -592,8 +597,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
Assert.Empty(entry.Errors); Assert.Empty(entry.Errors);
} }
@ -630,8 +635,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("billybob", entry.Value.AttemptedValue); Assert.Equal("billybob", entry.AttemptedValue);
Assert.Equal("billybob", entry.Value.RawValue); Assert.Equal("billybob", entry.RawValue);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
Assert.Equal("Too Long.", error.ErrorMessage); Assert.Equal("Too Long.", error.ErrorMessage);
@ -730,8 +735,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
Assert.Empty(entry.Errors); Assert.Empty(entry.Errors);
} }
@ -768,11 +773,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
Assert.Equal("billybob", entry.Value.AttemptedValue); Assert.Equal("billybob", entry.AttemptedValue);
Assert.Equal("billybob", entry.Value.RawValue); Assert.Equal("billybob", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.Customer").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.Customer").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
Assert.Equal("Invalid Person.", error.ErrorMessage); Assert.Equal("Invalid Person.", error.ErrorMessage);
@ -838,8 +844,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Products[0].Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Products[0].Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
Assert.Empty(entry.Errors); Assert.Empty(entry.Errors);
} }
@ -876,11 +882,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter.Products[0].Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter.Products[0].Name").Value;
Assert.Equal("billybob", entry.Value.AttemptedValue); Assert.Equal("billybob", entry.AttemptedValue);
Assert.Equal("billybob", entry.Value.RawValue); Assert.Equal("billybob", entry.RawValue);
entry = Assert.Single(modelState, e => e.Key == "parameter.Products").Value; entry = Assert.Single(modelState, e => e.Key == "parameter.Products").Value;
Assert.Null(entry.Value); Assert.Null(entry.RawValue);
Assert.Null(entry.AttemptedValue);
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState); Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
@ -927,8 +934,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter[0].Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter[0].Name").Value;
Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.AttemptedValue);
Assert.Equal("bill", entry.Value.RawValue); Assert.Equal("bill", entry.RawValue);
Assert.Empty(entry.Errors); Assert.Empty(entry.Errors);
} }
@ -965,8 +972,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.False(modelState.IsValid); Assert.False(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "parameter[0].Name").Value; var entry = Assert.Single(modelState, e => e.Key == "parameter[0].Name").Value;
Assert.Equal("billybob", entry.Value.AttemptedValue); Assert.Equal("billybob", entry.AttemptedValue);
Assert.Equal("billybob", entry.Value.RawValue); Assert.Equal("billybob", entry.RawValue);
var error = Assert.Single(entry.Errors); var error = Assert.Single(entry.Errors);
Assert.Equal("Too Long.", error.ErrorMessage); Assert.Equal("Too Long.", error.ErrorMessage);
@ -1070,23 +1077,23 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.True(modelState.IsValid); Assert.True(modelState.IsValid);
var entry = Assert.Single(modelState, e => e.Key == "HomeAddress.Country.Name").Value; var entry = Assert.Single(modelState, e => e.Key == "HomeAddress.Country.Name").Value;
Assert.Equal("US", entry.Value.AttemptedValue); Assert.Equal("US", entry.AttemptedValue);
Assert.Equal("US", entry.Value.RawValue); Assert.Equal("US", entry.RawValue);
Assert.Equal(ModelValidationState.Skipped, entry.ValidationState); Assert.Equal(ModelValidationState.Skipped, entry.ValidationState);
entry = Assert.Single(modelState, e => e.Key == "ShippingAddresses[0].Zip").Value; entry = Assert.Single(modelState, e => e.Key == "ShippingAddresses[0].Zip").Value;
Assert.Equal("45", entry.Value.AttemptedValue); Assert.Equal("45", entry.AttemptedValue);
Assert.Equal("45", entry.Value.RawValue); Assert.Equal("45", entry.RawValue);
Assert.Equal(ModelValidationState.Skipped, entry.ValidationState); Assert.Equal(ModelValidationState.Skipped, entry.ValidationState);
entry = Assert.Single(modelState, e => e.Key == "HomeAddress.Zip").Value; entry = Assert.Single(modelState, e => e.Key == "HomeAddress.Zip").Value;
Assert.Equal("46", entry.Value.AttemptedValue); Assert.Equal("46", entry.AttemptedValue);
Assert.Equal("46", entry.Value.RawValue); Assert.Equal("46", entry.RawValue);
Assert.Equal(ModelValidationState.Skipped, entry.ValidationState); Assert.Equal(ModelValidationState.Skipped, entry.ValidationState);
entry = Assert.Single(modelState, e => e.Key == "OfficeAddress").Value; entry = Assert.Single(modelState, e => e.Key == "OfficeAddress").Value;
Assert.Null(entry.Value.AttemptedValue); Assert.Null(entry.AttemptedValue);
var address = Assert.IsType<Address>(entry.Value.RawValue); var address = Assert.IsType<Address>(entry.RawValue);
Assert.Equal(47, address.Zip); Assert.Equal(47, address.Zip);
// Address itself is not excluded from validation. // Address itself is not excluded from validation.

View File

@ -39,13 +39,12 @@ namespace Microsoft.AspNet.Mvc
// Assert // Assert
var i = 0; var i = 0;
Assert.Equal(12, options.ModelBinders.Count); Assert.Equal(11, options.ModelBinders.Count);
Assert.IsType(typeof(BinderTypeBasedModelBinder), options.ModelBinders[i++]); Assert.IsType(typeof(BinderTypeBasedModelBinder), options.ModelBinders[i++]);
Assert.IsType(typeof(ServicesModelBinder), options.ModelBinders[i++]); Assert.IsType(typeof(ServicesModelBinder), options.ModelBinders[i++]);
Assert.IsType(typeof(BodyModelBinder), options.ModelBinders[i++]); Assert.IsType(typeof(BodyModelBinder), options.ModelBinders[i++]);
Assert.IsType(typeof(HeaderModelBinder), options.ModelBinders[i++]); Assert.IsType(typeof(HeaderModelBinder), options.ModelBinders[i++]);
Assert.IsType(typeof(TypeConverterModelBinder), options.ModelBinders[i++]); Assert.IsType(typeof(SimpleTypeModelBinder), options.ModelBinders[i++]);
Assert.IsType(typeof(TypeMatchModelBinder), options.ModelBinders[i++]);
Assert.IsType(typeof(CancellationTokenModelBinder), options.ModelBinders[i++]); Assert.IsType(typeof(CancellationTokenModelBinder), options.ModelBinders[i++]);
Assert.IsType(typeof(ByteArrayModelBinder), options.ModelBinders[i++]); Assert.IsType(typeof(ByteArrayModelBinder), options.ModelBinders[i++]);
Assert.IsType(typeof(FormFileModelBinder), options.ModelBinders[i++]); Assert.IsType(typeof(FormFileModelBinder), options.ModelBinders[i++]);

View File

@ -216,17 +216,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
} }
// rawValue, allowMultiple -> expected current values // rawValue, allowMultiple -> expected current values
public static TheoryData<object, bool, IReadOnlyCollection<string>> GetCurrentValues_StringAndCollectionData public static TheoryData<string[], bool, IReadOnlyCollection<string>> GetCurrentValues_CollectionData
{ {
get get
{ {
return new TheoryData<object, bool, IReadOnlyCollection<string>> return new TheoryData<string[], bool, IReadOnlyCollection<string>>
{ {
// ModelStateDictionary converts single values to arrays and visa-versa. // ModelStateDictionary converts arrays to single values if needed.
{ string.Empty, false, new [] { string.Empty } },
{ string.Empty, true, new [] { string.Empty } },
{ "some string", false, new [] { "some string" } },
{ "some string", true, new [] { "some string" } },
{ new [] { "some string" }, false, new [] { "some string" } }, { new [] { "some string" }, false, new [] { "some string" } },
{ new [] { "some string" }, true, new [] { "some string" } }, { new [] { "some string" }, true, new [] { "some string" } },
{ new [] { "some string", "some other string" }, false, new [] { "some string" } }, { new [] { "some string", "some other string" }, false, new [] { "some string" } },
@ -261,9 +257,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
} }
[Theory] [Theory]
[MemberData(nameof(GetCurrentValues_StringAndCollectionData))] [MemberData(nameof(GetCurrentValues_CollectionData))]
public void GetCurrentValues_WithModelStateEntryAndViewData_ReturnsModelStateEntry( public void GetCurrentValues_WithModelStateEntryAndViewData_ReturnsModelStateEntry(
object rawValue, string[] rawValue,
bool allowMultiple, bool allowMultiple,
IReadOnlyCollection<string> expected) IReadOnlyCollection<string> expected)
{ {
@ -274,10 +270,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
var viewContext = GetViewContext<Model>(model, metadataProvider); var viewContext = GetViewContext<Model>(model, metadataProvider);
viewContext.ViewData[nameof(Model.Name)] = "ignored ViewData value"; viewContext.ViewData[nameof(Model.Name)] = "ignored ViewData value";
viewContext.ModelState.SetModelValue(nameof(Model.Name), rawValue, attemptedValue: null);
var valueProviderResult = new ValueProviderResult(rawValue);
viewContext.ModelState.SetModelValue(nameof(Model.Name), valueProviderResult);
// Act // Act
var result = htmlGenerator.GetCurrentValues( var result = htmlGenerator.GetCurrentValues(
@ -292,9 +285,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
} }
[Theory] [Theory]
[MemberData(nameof(GetCurrentValues_StringAndCollectionData))] [MemberData(nameof(GetCurrentValues_CollectionData))]
public void GetCurrentValues_WithModelStateEntryModelExplorerAndViewData_ReturnsModelStateEntry( public void GetCurrentValues_WithModelStateEntryModelExplorerAndViewData_ReturnsModelStateEntry(
object rawValue, string[] rawValue,
bool allowMultiple, bool allowMultiple,
IReadOnlyCollection<string> expected) IReadOnlyCollection<string> expected)
{ {
@ -305,12 +298,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
var viewContext = GetViewContext<Model>(model, metadataProvider); var viewContext = GetViewContext<Model>(model, metadataProvider);
viewContext.ViewData[nameof(Model.Name)] = "ignored ViewData value"; viewContext.ViewData[nameof(Model.Name)] = "ignored ViewData value";
viewContext.ModelState.SetModelValue(nameof(Model.Name), rawValue, attemptedValue: null);
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(string), "ignored model value"); var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(string), "ignored model value");
var valueProviderResult = new ValueProviderResult(rawValue);
viewContext.ModelState.SetModelValue(nameof(Model.Name), valueProviderResult);
// Act // Act
var result = htmlGenerator.GetCurrentValues( var result = htmlGenerator.GetCurrentValues(
viewContext, viewContext,
@ -324,11 +315,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
} }
// rawValue -> expected current values // rawValue -> expected current values
public static TheoryData<string, string[]> GetCurrentValues_StringData public static TheoryData<string[], string[]> GetCurrentValues_StringData
{ {
get get
{ {
return new TheoryData<string, string[]> return new TheoryData<string[], string[]>
{ {
// 1. If given a ModelExplorer, GetCurrentValues does not use ViewData even if expression result is // 1. If given a ModelExplorer, GetCurrentValues does not use ViewData even if expression result is
// null. // null.
@ -336,8 +327,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
// if entry is null. // if entry is null.
// 3. Otherwise, GetCurrentValue does not fall back anywhere else even if ViewData.Model is null. // 3. Otherwise, GetCurrentValue does not fall back anywhere else even if ViewData.Model is null.
{ null, null }, { null, null },
{ string.Empty, new [] { string.Empty } }, { new string[] { string.Empty }, new [] { string.Empty } },
{ "some string", new [] { "some string" } }, { new string[] { "some string" }, new [] { "some string" } },
}; };
} }
} }
@ -345,7 +336,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
[Theory] [Theory]
[MemberData(nameof(GetCurrentValues_StringData))] [MemberData(nameof(GetCurrentValues_StringData))]
public void GetCurrentValues_WithModelExplorerAndViewData_ReturnsExpressionResult( public void GetCurrentValues_WithModelExplorerAndViewData_ReturnsExpressionResult(
string rawValue, string[] rawValue,
IReadOnlyCollection<string> expected) IReadOnlyCollection<string> expected)
{ {
// Arrange // Arrange
@ -355,12 +346,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
var viewContext = GetViewContext<Model>(model, metadataProvider); var viewContext = GetViewContext<Model>(model, metadataProvider);
viewContext.ViewData[nameof(Model.Name)] = "ignored ViewData value"; viewContext.ViewData[nameof(Model.Name)] = "ignored ViewData value";
viewContext.ModelState.SetModelValue(nameof(Model.Name), rawValue, attemptedValue: null);
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(string), rawValue); var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(string), rawValue);
var valueProviderResult = new ValueProviderResult(rawValue: null);
viewContext.ModelState.SetModelValue(nameof(Model.Name), valueProviderResult);
// Act // Act
var result = htmlGenerator.GetCurrentValues( var result = htmlGenerator.GetCurrentValues(
viewContext, viewContext,
@ -375,7 +364,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
[Theory] [Theory]
[MemberData(nameof(GetCurrentValues_StringData))] [MemberData(nameof(GetCurrentValues_StringData))]
public void GetCurrentValues_WithViewData_ReturnsViewDataEntry( public void GetCurrentValues_WithViewData_ReturnsViewDataEntry(
object rawValue, string[] rawValue,
IReadOnlyCollection<string> expected) IReadOnlyCollection<string> expected)
{ {
// Arrange // Arrange
@ -385,9 +374,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
var viewContext = GetViewContext<Model>(model, metadataProvider); var viewContext = GetViewContext<Model>(model, metadataProvider);
viewContext.ViewData[nameof(Model.Name)] = rawValue; viewContext.ViewData[nameof(Model.Name)] = rawValue;
viewContext.ModelState.SetModelValue(nameof(Model.Name), rawValue, attemptedValue: null);
var valueProviderResult = new ValueProviderResult(rawValue: null);
viewContext.ModelState.SetModelValue(nameof(Model.Name), valueProviderResult);
// Act // Act
var result = htmlGenerator.GetCurrentValues( var result = htmlGenerator.GetCurrentValues(
@ -402,17 +389,15 @@ namespace Microsoft.AspNet.Mvc.Rendering
[Theory] [Theory]
[MemberData(nameof(GetCurrentValues_StringData))] [MemberData(nameof(GetCurrentValues_StringData))]
public void GetCurrentValues_WithModel_ReturnsModel(string rawValue, IReadOnlyCollection<string> expected) public void GetCurrentValues_WithModel_ReturnsModel(string[] rawValue, IReadOnlyCollection<string> expected)
{ {
// Arrange // Arrange
var metadataProvider = new TestModelMetadataProvider(); var metadataProvider = new TestModelMetadataProvider();
var htmlGenerator = GetGenerator(metadataProvider); var htmlGenerator = GetGenerator(metadataProvider);
var model = new Model { Name = rawValue }; var model = new Model { Name = rawValue?[0] };
var viewContext = GetViewContext<Model>(model, metadataProvider); var viewContext = GetViewContext<Model>(model, metadataProvider);
viewContext.ModelState.SetModelValue(nameof(Model.Name), rawValue, attemptedValue: null);
var valueProviderResult = new ValueProviderResult(rawValue: null);
viewContext.ModelState.SetModelValue(nameof(Model.Name), valueProviderResult);
// Act // Act
var result = htmlGenerator.GetCurrentValues( var result = htmlGenerator.GetCurrentValues(
@ -467,13 +452,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
var viewContext = GetViewContext<Model>(model, metadataProvider); var viewContext = GetViewContext<Model>(model, metadataProvider);
viewContext.ViewData[nameof(Model.Collection)] = new[] { "ignored ViewData value" }; viewContext.ViewData[nameof(Model.Collection)] = new[] { "ignored ViewData value" };
viewContext.ModelState.SetModelValue(nameof(Model.Collection), rawValue, attemptedValue: null);
var modelExplorer = var modelExplorer =
metadataProvider.GetModelExplorerForType(typeof(List<string>), new List<string>(rawValue)); metadataProvider.GetModelExplorerForType(typeof(List<string>), new List<string>(rawValue));
var valueProviderResult = new ValueProviderResult(rawValue: null);
viewContext.ModelState.SetModelValue(nameof(Model.Collection), valueProviderResult);
// Act // Act
var result = htmlGenerator.GetCurrentValues( var result = htmlGenerator.GetCurrentValues(
viewContext, viewContext,
@ -488,7 +471,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
[Theory] [Theory]
[MemberData(nameof(GetCurrentValues_StringCollectionData))] [MemberData(nameof(GetCurrentValues_StringCollectionData))]
public void GetCurrentValues_CollectionWithViewData_ReturnsViewDataEntry( public void GetCurrentValues_CollectionWithViewData_ReturnsViewDataEntry(
object[] rawValue, string[] rawValue,
IReadOnlyCollection<string> expected) IReadOnlyCollection<string> expected)
{ {
// Arrange // Arrange
@ -498,9 +481,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
var viewContext = GetViewContext<Model>(model, metadataProvider); var viewContext = GetViewContext<Model>(model, metadataProvider);
viewContext.ViewData[nameof(Model.Collection)] = rawValue; viewContext.ViewData[nameof(Model.Collection)] = rawValue;
viewContext.ModelState.SetModelValue(nameof(Model.Collection), rawValue, attemptedValue: null);
var valueProviderResult = new ValueProviderResult(rawValue: null);
viewContext.ModelState.SetModelValue(nameof(Model.Collection), valueProviderResult);
// Act // Act
var result = htmlGenerator.GetCurrentValues( var result = htmlGenerator.GetCurrentValues(
@ -526,9 +507,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
model.Collection.AddRange(rawValue); model.Collection.AddRange(rawValue);
var viewContext = GetViewContext<Model>(model, metadataProvider); var viewContext = GetViewContext<Model>(model, metadataProvider);
viewContext.ModelState.SetModelValue(
var valueProviderResult = new ValueProviderResult(rawValue: null); nameof(Model.Collection),
viewContext.ModelState.SetModelValue(nameof(Model.Collection), valueProviderResult); rawValue,
attemptedValue: null);
// Act // Act
var result = htmlGenerator.GetCurrentValues( var result = htmlGenerator.GetCurrentValues(
@ -637,9 +619,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
var htmlGenerator = GetGenerator(metadataProvider); var htmlGenerator = GetGenerator(metadataProvider);
var viewContext = GetViewContext<Model>(model: null, metadataProvider: metadataProvider); var viewContext = GetViewContext<Model>(model: null, metadataProvider: metadataProvider);
viewContext.ModelState.SetModelValue(
var valueProviderResult = new ValueProviderResult(rawValue); propertyName,
viewContext.ModelState.SetModelValue(propertyName, valueProviderResult); new string[] { rawValue.ToString() },
attemptedValue: null);
// Act // Act
var result = htmlGenerator.GetCurrentValues( var result = htmlGenerator.GetCurrentValues(

View File

@ -134,9 +134,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
@"<input data-val=""HtmlEncode[[true]]"" data-val-required=""HtmlEncode[[The Boolean field is required.]]"" " + @"<input data-val=""HtmlEncode[[true]]"" data-val-required=""HtmlEncode[[The Boolean field is required.]]"" " +
@"id=""HtmlEncode[[Property1]]"" name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" />" + @"id=""HtmlEncode[[Property1]]"" name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[checkbox]]"" value=""HtmlEncode[[true]]"" />" +
@"<input name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />"); @"<input name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />");
var valueProviderResult = new ValueProviderResult("false", "false", CultureInfo.InvariantCulture);
var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData()); var helper = DefaultTemplatesUtilities.GetHtmlHelper(GetTestModelViewData());
helper.ViewData.ModelState.SetModelValue("Property1", valueProviderResult); helper.ViewData.ModelState.SetModelValue("Property1", new string[] { "false" }, "false");
// Act // Act
var html = helper.CheckBox("Property1", isChecked: null, htmlAttributes: null); var html = helper.CheckBox("Property1", isChecked: null, htmlAttributes: null);
@ -438,8 +438,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
@"<input name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />"); @"<input name=""HtmlEncode[[Property1]]"" type=""HtmlEncode[[hidden]]"" value=""HtmlEncode[[false]]"" />");
var viewData = GetTestModelViewData(); var viewData = GetTestModelViewData();
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData); var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
var valueProviderResult = new ValueProviderResult("false", "false", CultureInfo.InvariantCulture); viewData.ModelState.SetModelValue("Property1", new string[] { "false" }, "false");
viewData.ModelState.SetModelValue("Property1", valueProviderResult);
// Act // Act
var html = helper.CheckBoxFor(m => m.Property1, htmlAttributes: null); var html = helper.CheckBoxFor(m => m.Property1, htmlAttributes: null);
@ -533,9 +532,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
var viewData = GetTestModelViewData(); var viewData = GetTestModelViewData();
var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData); var helper = DefaultTemplatesUtilities.GetHtmlHelper(viewData);
var valueProviderResult = viewData.ModelState.SetModelValue("Property1", new string[] { attemptedValue }, attemptedValue);
new ValueProviderResult(attemptedValue, attemptedValue, CultureInfo.InvariantCulture);
viewData.ModelState.SetModelValue("Property1", valueProviderResult);
// Act // Act
var html = helper.CheckBoxFor(m => m.Property1, htmlAttributes: null); var html = helper.CheckBoxFor(m => m.Property1, htmlAttributes: null);

View File

@ -261,10 +261,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
viewData.TemplateInfo.HtmlFieldPrefix = "FieldPrefix"; viewData.TemplateInfo.HtmlFieldPrefix = "FieldPrefix";
var modelState = new ModelState(); var modelState = new ModelState();
modelState.Value = new ValueProviderResult( modelState.RawValue = new string[] { "Attempted name value" };
rawValue: new string[] { "Attempted name value" }, modelState.AttemptedValue = "Attempted name value";
attemptedValue: "Attempted name value",
culture: CultureInfo.InvariantCulture);
viewData.ModelState["FieldPrefix.Name"] = modelState; viewData.ModelState["FieldPrefix.Name"] = modelState;
// Act // Act
@ -288,10 +286,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
viewData.TemplateInfo.HtmlFieldPrefix = "FieldPrefix"; viewData.TemplateInfo.HtmlFieldPrefix = "FieldPrefix";
var modelState = new ModelState(); var modelState = new ModelState();
modelState.Value = new ValueProviderResult( modelState.RawValue = new string[] { "Attempted name value" };
rawValue: new string[] { "Attempted name value" }, modelState.AttemptedValue = "Attempted name value";
attemptedValue: "Attempted name value",
culture: CultureInfo.InvariantCulture);
viewData.ModelState["FieldPrefix.Name"] = modelState; viewData.ModelState["FieldPrefix.Name"] = modelState;
// Act // Act

View File

@ -874,7 +874,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
{ {
return new ModelState return new ModelState
{ {
Value = new ValueProviderResult(value, value, CultureInfo.InvariantCulture) RawValue = new string[] { value },
AttemptedValue = value,
}; };
} }

View File

@ -371,7 +371,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
{ {
return new ModelState return new ModelState
{ {
Value = new ValueProviderResult(value, value, CultureInfo.InvariantCulture) RawValue = new string[] { value },
AttemptedValue = value,
}; };
} }

View File

@ -410,18 +410,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
// Arrange // Arrange
var expectedHtml = GetExpectedSelectElement(SelectSources.ModelStateEntry, allowMultiple: false); var expectedHtml = GetExpectedSelectElement(SelectSources.ModelStateEntry, allowMultiple: false);
var entryResult = new ValueProviderResult(
SelectSources.ModelStateEntry,
SelectSources.ModelStateEntry.ToString(),
culture: null);
var entryResultWithPrefix = new ValueProviderResult(
SelectSources.ModelStateEntryWithPrefix,
SelectSources.ModelStateEntryWithPrefix.ToString(),
culture: null);
var modelState = new ModelStateDictionary var modelState = new ModelStateDictionary
{ {
["Property1"] = new ModelState { Value = entryResult }, ["Property1"] = new ModelState
["Prefix.Property1"] = new ModelState { Value = entryResultWithPrefix }, {
RawValue = new string[] { SelectSources.ModelStateEntry.ToString() },
AttemptedValue = SelectSources.ModelStateEntry.ToString()
},
["Prefix.Property1"] = new ModelState
{
RawValue = new string[] { SelectSources.ModelStateEntryWithPrefix.ToString() },
AttemptedValue = SelectSources.ModelStateEntryWithPrefix.ToString()
},
}; };
var provider = TestModelMetadataProvider.CreateDefaultProvider(); var provider = TestModelMetadataProvider.CreateDefaultProvider();
@ -451,18 +451,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
SelectSources.ModelStateEntryWithPrefix, SelectSources.ModelStateEntryWithPrefix,
allowMultiple: false); allowMultiple: false);
var entryResult = new ValueProviderResult(
SelectSources.ModelStateEntry,
SelectSources.ModelStateEntry.ToString(),
culture: null);
var entryResultWithPrefix = new ValueProviderResult(
SelectSources.ModelStateEntryWithPrefix,
SelectSources.ModelStateEntryWithPrefix.ToString(),
culture: null);
var modelState = new ModelStateDictionary var modelState = new ModelStateDictionary
{ {
["Property1"] = new ModelState { Value = entryResult }, ["Property1"] = new ModelState
["Prefix.Property1"] = new ModelState { Value = entryResultWithPrefix }, {
RawValue = new string[] { SelectSources.ModelStateEntry.ToString() },
AttemptedValue = SelectSources.ModelStateEntry.ToString()
},
["Prefix.Property1"] = new ModelState
{
RawValue = new string[] { SelectSources.ModelStateEntryWithPrefix.ToString() },
AttemptedValue = SelectSources.ModelStateEntryWithPrefix.ToString()
},
}; };
var provider = TestModelMetadataProvider.CreateDefaultProvider(); var provider = TestModelMetadataProvider.CreateDefaultProvider();
@ -821,18 +821,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
// Arrange // Arrange
var expectedHtml = GetExpectedSelectElement(SelectSources.ModelStateEntry, allowMultiple: true); var expectedHtml = GetExpectedSelectElement(SelectSources.ModelStateEntry, allowMultiple: true);
var entryResult = new ValueProviderResult(
SelectSources.ModelStateEntry,
SelectSources.ModelStateEntry.ToString(),
culture: null);
var entryResultWithPrefix = new ValueProviderResult(
SelectSources.ModelStateEntryWithPrefix,
SelectSources.ModelStateEntryWithPrefix.ToString(),
culture: null);
var modelState = new ModelStateDictionary var modelState = new ModelStateDictionary
{ {
["Property1"] = new ModelState { Value = entryResult }, ["Property1"] = new ModelState
["Prefix.Property1"] = new ModelState { Value = entryResultWithPrefix }, {
RawValue = new string[] { SelectSources.ModelStateEntry.ToString() },
AttemptedValue = SelectSources.ModelStateEntry.ToString()
},
["Prefix.Property1"] = new ModelState
{
RawValue = new string[] { SelectSources.ModelStateEntryWithPrefix.ToString() },
AttemptedValue = SelectSources.ModelStateEntryWithPrefix.ToString()
},
}; };
var provider = TestModelMetadataProvider.CreateDefaultProvider(); var provider = TestModelMetadataProvider.CreateDefaultProvider();
@ -862,18 +862,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
SelectSources.ModelStateEntryWithPrefix, SelectSources.ModelStateEntryWithPrefix,
allowMultiple: true); allowMultiple: true);
var entryResult = new ValueProviderResult(
SelectSources.ModelStateEntry,
SelectSources.ModelStateEntry.ToString(),
culture: null);
var entryResultWithPrefix = new ValueProviderResult(
SelectSources.ModelStateEntryWithPrefix,
SelectSources.ModelStateEntryWithPrefix.ToString(),
culture: null);
var modelState = new ModelStateDictionary var modelState = new ModelStateDictionary
{ {
["Property1"] = new ModelState { Value = entryResult }, ["Property1"] = new ModelState
["Prefix.Property1"] = new ModelState { Value = entryResultWithPrefix }, {
RawValue = new string[] { SelectSources.ModelStateEntry.ToString() },
AttemptedValue = SelectSources.ModelStateEntry.ToString()
},
["Prefix.Property1"] = new ModelState
{
RawValue = new string[] { SelectSources.ModelStateEntryWithPrefix.ToString() },
AttemptedValue = SelectSources.ModelStateEntryWithPrefix.ToString()
},
}; };
var provider = TestModelMetadataProvider.CreateDefaultProvider(); var provider = TestModelMetadataProvider.CreateDefaultProvider();

View File

@ -164,17 +164,13 @@ namespace Microsoft.AspNet.Mvc.Core
viewData.TemplateInfo.HtmlFieldPrefix = "FieldPrefix"; viewData.TemplateInfo.HtmlFieldPrefix = "FieldPrefix";
var modelState = new ModelState(); var modelState = new ModelState();
modelState.Value = new ValueProviderResult( modelState.AttemptedValue = "StringPropertyAttemptedValue";
rawValue: new string[] { "StringPropertyRawValue" }, modelState.RawValue = new string[] { "StringPropertyRawValue" };
attemptedValue: "StringPropertyAttemptedValue",
culture: CultureInfo.InvariantCulture);
viewData.ModelState["FieldPrefix.StringProperty"] = modelState; viewData.ModelState["FieldPrefix.StringProperty"] = modelState;
modelState = new ModelState(); modelState = new ModelState();
modelState.Value = new ValueProviderResult( modelState.AttemptedValue = "ModelAttemptedValue";
rawValue: new string[] { "ModelRawValue" }, modelState.RawValue = new string[] { "ModelRawValue" };
attemptedValue: "ModelAttemptedValue",
culture: CultureInfo.InvariantCulture);
viewData.ModelState["FieldPrefix"] = modelState; viewData.ModelState["FieldPrefix"] = modelState;
// Act & Assert // Act & Assert
@ -225,10 +221,8 @@ namespace Microsoft.AspNet.Mvc.Core
viewData["StringProperty"] = "ViewDataValue <\"\">"; viewData["StringProperty"] = "ViewDataValue <\"\">";
var modelState = new ModelState(); var modelState = new ModelState();
modelState.Value = new ValueProviderResult( modelState.AttemptedValue = "ObjectPropertyAttemptedValue <\"\">";
rawValue: new string[] { "ObjectPropertyRawValue <\"\">" }, modelState.RawValue = new string[] { "ObjectPropertyRawValue <\"\">" };
attemptedValue: "ObjectPropertyAttemptedValue <\"\">",
culture: CultureInfo.InvariantCulture);
viewData.ModelState["ObjectProperty"] = modelState; viewData.ModelState["ObjectProperty"] = modelState;
// Act & Assert // Act & Assert

View File

@ -99,7 +99,7 @@ namespace ModelBindingWebSite.Controllers
bindingContext.ModelName + "." + "productId"; bindingContext.ModelName + "." + "productId";
var value = await bindingContext.ValueProvider.GetValueAsync(key); var value = await bindingContext.ValueProvider.GetValueAsync(key);
model.ProductId = (int)value.ConvertTo(typeof(int)); model.ProductId = value.ConvertTo<int>();
var validationNode = var validationNode =
new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value); new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value);

View File

@ -218,7 +218,7 @@ namespace ModelBindingWebSite.Controllers
public Task<ValueProviderResult> GetValueAsync(string key) public Task<ValueProviderResult> GetValueAsync(string key)
{ {
return Task.FromResult<ValueProviderResult>(null); return Task.FromResult<ValueProviderResult>(ValueProviderResult.None);
} }
} }
} }

View File

@ -31,7 +31,7 @@ namespace ValueProvidersWebSite
public Task<ValueProviderResult> GetValueAsync(string key) public Task<ValueProviderResult> GetValueAsync(string key)
{ {
var value = "custom-value-provider-value"; var value = "custom-value-provider-value";
var result = new ValueProviderResult(value, value, CultureInfo.CurrentCulture); var result = new ValueProviderResult(value, CultureInfo.CurrentCulture);
return Task.FromResult(result); return Task.FromResult(result);
} }
} }