diff --git a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs b/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs index 162fe105c7..04f6dcf1ba 100644 --- a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs +++ b/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs @@ -12,45 +12,83 @@ using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding { + /// + /// Result of an operation. + /// public class ValueProviderResult { private static readonly CultureInfo _staticCulture = CultureInfo.InvariantCulture; - private CultureInfo _instanceCulture; - // default constructor so that subclassed types can set the properties themselves - protected ValueProviderResult() + /// + /// Instantiates a new instance of the class with given + /// . Initializes to + /// . + /// + /// The value of the new instance. + public ValueProviderResult(object rawValue) + : this(rawValue, attemptedValue: null, culture: _staticCulture) { } + /// + /// Instantiates a new instance of the class with given + /// , , and . + /// + /// The value of the new instance. + /// The value of the new instance. + /// The value of the new instance. public ValueProviderResult(object rawValue, string attemptedValue, CultureInfo culture) { RawValue = rawValue; AttemptedValue = attemptedValue; - Culture = culture; + Culture = culture ?? _staticCulture; } - public string AttemptedValue { get; protected set; } + /// + /// conversion of . + /// + /// + /// Used in helpers that generate <textarea> elements as well as some error messages. + /// + public string AttemptedValue { get; } - public CultureInfo Culture - { - get - { - if (_instanceCulture == null) - { - _instanceCulture = _staticCulture; - } - return _instanceCulture; - } - protected set { _instanceCulture = value; } - } + /// + /// to use in or + /// if passed is null. + /// + public CultureInfo Culture { get; } - public object RawValue { get; protected set; } + /// + /// The provided . + /// + public object RawValue { get; } + /// + /// Converts to the given . Uses for + /// operations. + /// + /// The target of the conversion. + /// + /// converted to the given . null if the conversion fails. + /// public object ConvertTo(Type type) { return ConvertTo(type, culture: null); } + /// + /// Converts to the given using the given + /// . + /// + /// The target of the conversion. + /// + /// The to use for operations. Uses + /// if this parameter is null. + /// + /// + /// converted to the given using the given + /// . null if the conversion fails. + /// public virtual object ConvertTo([NotNull] Type type, CultureInfo culture) { var value = RawValue; diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/BodyModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/BodyModelBinder.cs index e7775f01bb..3261747428 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/BodyModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/BodyModelBinder.cs @@ -66,6 +66,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return new ModelBindingResult(modelBindingKey); } + var valueProviderResult = new ValueProviderResult(rawValue: model); + bindingContext.ModelState.SetModelValue(modelBindingKey, valueProviderResult); var validationNode = new ModelValidationNode(modelBindingKey, bindingContext.ModelMetadata, model) { diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/ByteArrayModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/ByteArrayModelBinder.cs index 8c8a6af4fd..17cd3d5845 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/ByteArrayModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/ByteArrayModelBinder.cs @@ -21,17 +21,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return null; } - var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName); - // Check for missing data case 1: There was no element containing this data. + var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName); if (valueProviderResult == null) { return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false); } - var value = valueProviderResult.AttemptedValue; + bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); // Check for missing data case 2: There was an element but it was left blank. + var value = valueProviderResult.AttemptedValue; if (string.IsNullOrEmpty(value)) { return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false); diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormCollectionModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormCollectionModelBinder.cs index 4c37b27c40..84eaa8f2d0 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormCollectionModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormCollectionModelBinder.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return null; } - object model = null; + object model; var request = bindingContext.OperationBindingContext.HttpContext.Request; if (request.HasFormContentType) { @@ -36,8 +36,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding } else { - var formValuesLookup = form.ToDictionary(p => p.Key, - p => p.Value); + var formValuesLookup = form.ToDictionary(p => p.Key, p => p.Value); model = new FormCollection(formValuesLookup, form.Files); } } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormFileModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormFileModelBinder.cs index e11821619d..d5f7edf1f3 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormFileModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormFileModelBinder.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Linq; +#if DNXCORE50 using System.Reflection; +#endif using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.Framework.Internal; @@ -20,33 +22,38 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// public async Task BindModelAsync([NotNull] ModelBindingContext bindingContext) { + object value; if (bindingContext.ModelType == typeof(IFormFile)) { var postedFiles = await GetFormFilesAsync(bindingContext); - var value = postedFiles.FirstOrDefault(); - var validationNode = - new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value); - return new ModelBindingResult( - value, - bindingContext.ModelName, - isModelSet: value != null, - validationNode: validationNode); + value = postedFiles.FirstOrDefault(); } - else if (typeof(IEnumerable).GetTypeInfo().IsAssignableFrom( - bindingContext.ModelType.GetTypeInfo())) + else if (typeof(IEnumerable).IsAssignableFrom(bindingContext.ModelType)) { var postedFiles = await GetFormFilesAsync(bindingContext); - var value = ModelBindingHelper.ConvertValuesToCollectionType(bindingContext.ModelType, postedFiles); - var validationNode = - new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value); - return new ModelBindingResult( - value, - bindingContext.ModelName, - isModelSet: value != null, - validationNode: validationNode); + value = ModelBindingHelper.ConvertValuesToCollectionType(bindingContext.ModelType, postedFiles); + } + else + { + // This binder does not support the requested type. + return null; } - return null; + ModelValidationNode validationNode = null; + if (value != null) + { + validationNode = + new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value); + + var valueProviderResult = new ValueProviderResult(rawValue: value); + bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); + } + + return new ModelBindingResult( + value, + bindingContext.ModelName, + isModelSet: value != null, + validationNode: validationNode); } private async Task> GetFormFilesAsync(ModelBindingContext bindingContext) diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/HeaderModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/HeaderModelBinder.cs index f44fc94e7d..2a253ece64 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/HeaderModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/HeaderModelBinder.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; +using System.Globalization; #if DNXCORE50 using System.Reflection; #endif @@ -59,6 +60,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding bindingContext.ModelName, bindingContext.ModelMetadata, model); + + var attemptedValue = (model as string) ?? request.Headers.Get(headerName); + var valueProviderResult = new ValueProviderResult(model, attemptedValue, CultureInfo.InvariantCulture); + bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); } return Task.FromResult( diff --git a/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ModelStateDictionaryTest.cs b/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ModelStateDictionaryTest.cs index ea5d76fc7a..77bcf18dde 100644 --- a/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ModelStateDictionaryTest.cs +++ b/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ModelStateDictionaryTest.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Globalization; using Microsoft.Framework.Internal; using Xunit; @@ -75,7 +74,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding // Act var exception = Assert.Throws(() => source.MarkFieldSkipped("key")); - + // Assert Assert.Equal( "A field previously marked invalid should not be marked skipped.", @@ -138,7 +137,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding // Act var exception = Assert.Throws(() => source.MarkFieldValid("key")); - + // Assert Assert.Equal( "A field previously marked invalid should not be marked valid.", @@ -278,7 +277,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding // Arrange var validState = new ModelState { - Value = new ValueProviderResult(null, null, null), + Value = new ValueProviderResult(rawValue: null), ValidationState = ModelValidationState.Valid }; var msd = new ModelStateDictionary @@ -317,7 +316,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding // Arrange var validState = new ModelState { - Value = new ValueProviderResult(null, null, null), + Value = new ValueProviderResult(rawValue: null), ValidationState = ModelValidationState.Valid }; var msd = new ModelStateDictionary diff --git a/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ValueProviderResultTest.cs b/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ValueProviderResultTest.cs index 19787a6137..6214865b27 100644 --- a/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ValueProviderResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ValueProviderResultTest.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding [Fact] public void ConvertTo_ReturnsNullForReferenceTypes_WhenValueIsNull() { - var valueProviderResult = new ValueProviderResult(null, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: null); var convertedValue = valueProviderResult.ConvertTo(typeof(string)); @@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding [Fact] public void ConvertTo_ReturnsDefaultForValueTypes_WhenValueIsNull() { - var valueProviderResult = new ValueProviderResult(null, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: null); var convertedValue = valueProviderResult.ConvertTo(typeof(int)); @@ -34,10 +34,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToCanConvertArraysToSingleElements() { // Arrange - var vpr = new ValueProviderResult(new int[] { 1, 20, 42 }, "", CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult( + new int[] { 1, 20, 42 }, + string.Empty, + CultureInfo.InvariantCulture); // Act - var converted = (string)vpr.ConvertTo(typeof(string)); + var converted = (string)valueProviderResult.ConvertTo(typeof(string)); // Assert Assert.Equal("1", converted); @@ -47,10 +50,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToCanConvertSingleElementsToArrays() { // Arrange - var vpr = new ValueProviderResult(42, "", CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(42, string.Empty, CultureInfo.InvariantCulture); // Act - var converted = (string[])vpr.ConvertTo(typeof(string[])); + var converted = (string[])valueProviderResult.ConvertTo(typeof(string[])); // Assert Assert.NotNull(converted); @@ -62,10 +65,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToCanConvertSingleElementsToSingleElements() { // Arrange - var vpr = new ValueProviderResult(42, "", CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(42, string.Empty, CultureInfo.InvariantCulture); // Act - var converted = (string)vpr.ConvertTo(typeof(string)); + var converted = (string)valueProviderResult.ConvertTo(typeof(string)); // Assert Assert.NotNull(converted); @@ -77,10 +80,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding { // Arrange object original = null; - var vpr = new ValueProviderResult(original, "", CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(original, string.Empty, CultureInfo.InvariantCulture); // Act - var returned = (int?)vpr.ConvertTo(typeof(int?)); + var returned = (int?)valueProviderResult.ConvertTo(typeof(int?)); // Assert Assert.Equal(returned, null); @@ -91,10 +94,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding { // Arrange var original = " "; - var vpr = new ValueProviderResult(original, "", CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(original, string.Empty, CultureInfo.InvariantCulture); // Act - var returned = (int?)vpr.ConvertTo(typeof(int?)); + var returned = (int?)valueProviderResult.ConvertTo(typeof(int?)); // Assert Assert.Equal(returned, null); @@ -104,10 +107,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsNullIfArrayElementValueIsNull() { // Arrange - var vpr = new ValueProviderResult(new string[] { null }, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: new string[] { null }); // Act - var outValue = vpr.ConvertTo(typeof(int)); + var outValue = valueProviderResult.ConvertTo(typeof(int)); // Assert Assert.Null(outValue); @@ -117,10 +120,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsNullIfTryingToConvertEmptyArrayToSingleElement() { // Arrange - var vpr = new ValueProviderResult(new int[0], "", CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(new int[0], string.Empty, CultureInfo.InvariantCulture); // Act - var outValue = vpr.ConvertTo(typeof(int)); + var outValue = valueProviderResult.ConvertTo(typeof(int)); // Assert Assert.Null(outValue); @@ -132,10 +135,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsNullIfTrimmedValueIsEmptyString(object value) { // Arrange - var vpr = new ValueProviderResult(value, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: value); // Act - var outValue = vpr.ConvertTo(typeof(int)); + var outValue = valueProviderResult.ConvertTo(typeof(int)); // Assert Assert.Null(outValue); @@ -145,12 +148,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsNullIfTrimmedValueIsEmptyString() { // Arrange - var vpr = new ValueProviderResult(rawValue: null, - attemptedValue: null, - culture: CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: null); // Act - var outValue = vpr.ConvertTo(typeof(int[])); + var outValue = valueProviderResult.ConvertTo(typeof(int[])); // Assert Assert.Null(outValue); @@ -160,7 +161,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsValueIfArrayElementIsIntegerAndDestinationTypeIsEnum() { // Arrange - var result = new ValueProviderResult(new object[] { 1 }, null, CultureInfo.InvariantCulture); + var result = new ValueProviderResult(rawValue: new object[] { 1 }); // Act var outValue = result.ConvertTo(typeof(IntEnum)); @@ -194,7 +195,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding object expected) { // Arrange - var result = new ValueProviderResult(new object[] { input }, null, CultureInfo.InvariantCulture); + var result = new ValueProviderResult(rawValue: new object[] { input }); // Act var outValue = result.ConvertTo(enumType); @@ -207,10 +208,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsValueIfArrayElementIsStringValueAndDestinationTypeIsEnum() { // Arrange - var vpr = new ValueProviderResult(new object[] { "1" }, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: new object[] { "1" }); // Act - var outValue = vpr.ConvertTo(typeof(IntEnum)); + var outValue = valueProviderResult.ConvertTo(typeof(IntEnum)); // Assert Assert.Equal(outValue, IntEnum.Value1); @@ -220,10 +221,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsValueIfArrayElementIsStringKeyAndDestinationTypeIsEnum() { // Arrange - var vpr = new ValueProviderResult(new object[] { "Value1" }, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: new object[] { "Value1" }); // Act - var outValue = vpr.ConvertTo(typeof(IntEnum)); + var outValue = valueProviderResult.ConvertTo(typeof(IntEnum)); // Assert Assert.Equal(outValue, IntEnum.Value1); @@ -233,10 +234,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsValueIfElementIsStringAndDestinationIsNullableInteger() { // Arrange - var vpr = new ValueProviderResult("12", null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: "12"); // Act - var outValue = vpr.ConvertTo(typeof(int?)); + var outValue = valueProviderResult.ConvertTo(typeof(int?)); // Assert Assert.Equal(12, outValue); @@ -246,10 +247,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsValueIfElementIsStringAndDestinationIsNullableDouble() { // Arrange - var vpr = new ValueProviderResult("12.5", null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: "12.5"); // Act - var outValue = vpr.ConvertTo(typeof(double?)); + var outValue = valueProviderResult.ConvertTo(typeof(double?)); // Assert Assert.Equal(12.5, outValue); @@ -259,10 +260,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsValueIfElementIsDecimalAndDestinationIsNullableInteger() { // Arrange - var vpr = new ValueProviderResult(12M, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: 12M); // Act - var outValue = vpr.ConvertTo(typeof(int?)); + var outValue = valueProviderResult.ConvertTo(typeof(int?)); // Assert Assert.Equal(12, outValue); @@ -272,10 +273,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsValueIfElementIsDecimalAndDestinationIsNullableDouble() { // Arrange - var vpr = new ValueProviderResult(12.5M, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: 12.5M); // Act - var outValue = vpr.ConvertTo(typeof(double?)); + var outValue = valueProviderResult.ConvertTo(typeof(double?)); // Assert Assert.Equal(12.5, outValue); @@ -285,10 +286,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsValueIfElementIsDecimalDoubleAndDestinationIsNullableInteger() { // Arrange - var vpr = new ValueProviderResult(12.5M, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: 12.5M); // Act - var outValue = vpr.ConvertTo(typeof(int?)); + var outValue = valueProviderResult.ConvertTo(typeof(int?)); // Assert Assert.Equal(12, outValue); @@ -298,10 +299,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsValueIfElementIsDecimalDoubleAndDestinationIsNullableLong() { // Arrange - var vpr = new ValueProviderResult(12.5M, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: 12.5M); // Act - var outValue = vpr.ConvertTo(typeof(long?)); + var outValue = valueProviderResult.ConvertTo(typeof(long?)); // Assert Assert.Equal(12L, outValue); @@ -311,10 +312,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToReturnsValueIfArrayElementInstanceOfDestinationType() { // Arrange - var vpr = new ValueProviderResult(new object[] { "some string" }, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: new object[] { "some string" }); // Act - var outValue = vpr.ConvertTo(typeof(string)); + var outValue = valueProviderResult.ConvertTo(typeof(string)); // Assert Assert.Equal("some string", outValue); @@ -327,10 +328,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertTo_ConvertsEnumArrays(object value) { // Arrange - var vpr = new ValueProviderResult(value, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: value); // Act - var outValue = vpr.ConvertTo(typeof(IntEnum[])); + var outValue = valueProviderResult.ConvertTo(typeof(IntEnum[])); // Assert var result = Assert.IsType(outValue); @@ -346,10 +347,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertTo_ConvertsFlagsEnumArrays(object value, FlagsEnum[] expected) { // Arrange - var vpr = new ValueProviderResult(value, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: value); // Act - var outValue = vpr.ConvertTo(typeof(FlagsEnum[])); + var outValue = valueProviderResult.ConvertTo(typeof(FlagsEnum[])); // Assert var result = Assert.IsType(outValue); @@ -363,10 +364,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding { // Arrange var original = new[] { "some string" }; - var vpr = new ValueProviderResult(original, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: original); // Act - var outValue = vpr.ConvertTo(typeof(string[])); + var outValue = valueProviderResult.ConvertTo(typeof(string[])); // Assert Assert.Same(original, outValue); @@ -379,21 +380,21 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToThrowsIfConverterThrows(Type destinationType) { // Arrange - var vpr = new ValueProviderResult("this-is-not-a-valid-value", null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: "this-is-not-a-valid-value"); // Act & Assert - var ex = Assert.Throws(typeof(FormatException), () => vpr.ConvertTo(destinationType)); + var ex = Assert.Throws(typeof(FormatException), () => valueProviderResult.ConvertTo(destinationType)); } [Fact] public void ConvertToThrowsIfNoConverterExists() { // Arrange - var vpr = new ValueProviderResult("x", null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: "x"); var destinationType = typeof(MyClassWithoutConverter); // Act & Assert - var ex = Assert.Throws(() => vpr.ConvertTo(destinationType)); + var ex = Assert.Throws(() => valueProviderResult.ConvertTo(destinationType)); 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.", @@ -405,22 +406,25 @@ namespace Microsoft.AspNet.Mvc.ModelBinding { // Arrange var original = "12,5"; - var vpr = new ValueProviderResult(original, null, new CultureInfo("en-GB")); + var valueProviderResult = new ValueProviderResult( + rawValue: original, + attemptedValue: null, + culture: new CultureInfo("en-GB")); var frCulture = new CultureInfo("fr-FR"); // Act - var cultureResult = vpr.ConvertTo(typeof(decimal), frCulture); + var cultureResult = valueProviderResult.ConvertTo(typeof(decimal), frCulture); // Assert Assert.Equal(12.5M, cultureResult); - Assert.Throws(() => vpr.ConvertTo(typeof(decimal))); + Assert.Throws(() => valueProviderResult.ConvertTo(typeof(decimal))); } [Fact] public void CulturePropertyDefaultsToInvariantCulture() { // Arrange - var result = new ValueProviderResult(null, null, null); + var result = new ValueProviderResult(rawValue: null, attemptedValue: null, culture: null); // Act & assert Assert.Same(CultureInfo.InvariantCulture, result.Culture); @@ -431,7 +435,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertToCanConvertIntrinsics(object initialValue, T expectedValue) { // Arrange - var result = new ValueProviderResult(initialValue, "", CultureInfo.InvariantCulture); + var result = new ValueProviderResult(initialValue, string.Empty, CultureInfo.InvariantCulture); // Act & Assert Assert.Equal(expectedValue, result.ConvertTo(typeof(T))); @@ -471,7 +475,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertTo_Throws_IfValueIsNotStringData(Type destinationType) { // Arrange - var result = new ValueProviderResult(new MyClassWithoutConverter(), "", CultureInfo.InvariantCulture); + var result = new ValueProviderResult( + new MyClassWithoutConverter(), + string.Empty, + CultureInfo.InvariantCulture); // Act var ex = Assert.Throws(() => result.ConvertTo(destinationType)); @@ -489,7 +496,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding // Arrange var value = "Hello world"; var destinationType = typeof(MyClassWithoutConverter); - var result = new ValueProviderResult(value, "", CultureInfo.InvariantCulture); + var result = new ValueProviderResult(value, string.Empty, CultureInfo.InvariantCulture); // Act var ex = Assert.Throws(() => result.ConvertTo(destinationType)); @@ -513,10 +520,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public void ConvertTo_ConvertsEnumFlags(object value, object expected) { // Arrange - var vpr = new ValueProviderResult(value, null, CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: value); // Act - var outValue = (FlagsEnum)vpr.ConvertTo(typeof(FlagsEnum)); + var outValue = (FlagsEnum)valueProviderResult.ConvertTo(typeof(FlagsEnum)); // Assert Assert.Equal(expected, outValue); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/BodyModelBinderTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/BodyModelBinderTests.cs index 449a4281cd..646520d35a 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/BodyModelBinderTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/BodyModelBinderTests.cs @@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding // Assert - // Returns true because it understands the metadata type. + // Returns non-null because it understands the metadata type. Assert.NotNull(binderResult); Assert.True(binderResult.IsFatalError); Assert.False(binderResult.IsModelSet); @@ -171,7 +171,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding // Assert - // Returns true because it understands the metadata type. + // Returns non-null because it understands the metadata type. Assert.NotNull(binderResult); Assert.True(binderResult.IsFatalError); Assert.False(binderResult.IsModelSet); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ByteArrayModelBinderTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ByteArrayModelBinderTests.cs index 2a631b32e2..939314bcb3 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ByteArrayModelBinderTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/ByteArrayModelBinderTests.cs @@ -34,7 +34,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test Assert.Equal("foo", binderResult.Key); Assert.Null(binderResult.Model); - Assert.Empty(bindingContext.ModelState); // No submitted value for "foo". + var modelState = Assert.Single(bindingContext.ModelState); + Assert.Equal("foo", modelState.Key); + Assert.NotNull(modelState.Value.Value); + Assert.Equal(value, modelState.Value.Value.RawValue); } [Fact] @@ -64,7 +67,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test // Arrange var expected = TestPlatformHelper.IsMono ? "Invalid length." : - "The supplied value is invalid for foo."; + "The value '\"Fys1\"' is not valid for foo."; var valueProvider = new SimpleHttpValueProvider() { diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/Validation/DefaultObjectValidatorTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/Validation/DefaultObjectValidatorTests.cs index 15eab7b499..7c41f25e48 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/Validation/DefaultObjectValidatorTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/Validation/DefaultObjectValidatorTests.cs @@ -490,9 +490,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation var validationContext = testValidationContext.ModelValidationContext; // Set the value on model state as a model binder would. - validationContext.ModelState.SetModelValue( - "user.Password", - Mock.Of()); + var valueProviderResult = new ValueProviderResult(rawValue: "password"); + validationContext.ModelState.SetModelValue("user.Password", valueProviderResult); var validator = new DefaultObjectValidator( testValidationContext.ExcludeFilters, testValidationContext.ModelMetadataProvider); @@ -513,6 +512,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation Assert.Equal("user.Password", entry.Key); Assert.Empty(entry.Value.Errors); Assert.Equal(entry.Value.ValidationState, ModelValidationState.Skipped); + Assert.Same(valueProviderResult, entry.Value.Value); } private class Person2 @@ -536,7 +536,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation validationContext.ModelState.Add("person.Address", new ModelState()); var validator = new DefaultObjectValidator( - testValidationContext.ExcludeFilters, + testValidationContext.ExcludeFilters, testValidationContext.ModelMetadataProvider); var modelExplorer = testValidationContext.ModelValidationContext.ModelExplorer; var topLevelValidationNode = new ModelValidationNode( diff --git a/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/DefaultHtmlGeneratorTest.cs b/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/DefaultHtmlGeneratorTest.cs index 2774ea21ac..4b988b51be 100644 --- a/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/DefaultHtmlGeneratorTest.cs +++ b/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/DefaultHtmlGeneratorTest.cs @@ -166,10 +166,7 @@ namespace Microsoft.AspNet.Mvc.Rendering viewContext.ViewData[nameof(Model.Name)] = "ignored ViewData value"; - var valueProviderResult = new ValueProviderResult( - rawValue, - attemptedValue: null, - culture: CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue); viewContext.ModelState.SetModelValue(nameof(Model.Name), valueProviderResult); // Act @@ -201,10 +198,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(string), "ignored model value"); - var valueProviderResult = new ValueProviderResult( - rawValue, - attemptedValue: null, - culture: CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue); viewContext.ModelState.SetModelValue(nameof(Model.Name), valueProviderResult); // Act @@ -254,10 +248,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(string), rawValue); - var valueProviderResult = new ValueProviderResult( - rawValue: null, - attemptedValue: null, - culture: CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: null); viewContext.ModelState.SetModelValue(nameof(Model.Name), valueProviderResult); // Act @@ -285,10 +276,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var viewContext = GetViewContext(model, metadataProvider); viewContext.ViewData[nameof(Model.Name)] = rawValue; - var valueProviderResult = new ValueProviderResult( - rawValue: null, - attemptedValue: null, - culture: CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: null); viewContext.ModelState.SetModelValue(nameof(Model.Name), valueProviderResult); // Act @@ -313,10 +301,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var viewContext = GetViewContext(model, metadataProvider); - var valueProviderResult = new ValueProviderResult( - rawValue: null, - attemptedValue: null, - culture: CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: null); viewContext.ModelState.SetModelValue(nameof(Model.Name), valueProviderResult); // Act @@ -376,10 +361,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(List), new List(rawValue)); - var valueProviderResult = new ValueProviderResult( - rawValue: null, - attemptedValue: null, - culture: CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: null); viewContext.ModelState.SetModelValue(nameof(Model.Collection), valueProviderResult); // Act @@ -407,10 +389,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var viewContext = GetViewContext(model, metadataProvider); viewContext.ViewData[nameof(Model.Collection)] = rawValue; - var valueProviderResult = new ValueProviderResult( - rawValue: null, - attemptedValue: null, - culture: CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: null); viewContext.ModelState.SetModelValue(nameof(Model.Collection), valueProviderResult); // Act @@ -438,10 +417,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var viewContext = GetViewContext(model, metadataProvider); - var valueProviderResult = new ValueProviderResult( - rawValue: null, - attemptedValue: null, - culture: CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue: null); viewContext.ModelState.SetModelValue(nameof(Model.Collection), valueProviderResult); // Act @@ -552,10 +528,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = GetGenerator(metadataProvider); var viewContext = GetViewContext(model: null, metadataProvider: metadataProvider); - var valueProviderResult = new ValueProviderResult( - rawValue, - attemptedValue: null, - culture: CultureInfo.InvariantCulture); + var valueProviderResult = new ValueProviderResult(rawValue); viewContext.ModelState.SetModelValue(propertyName, valueProviderResult); // Act diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/BodyValidationIntegrationTests.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/BodyValidationIntegrationTests.cs index 458de1dfe0..5555ce3e15 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/BodyValidationIntegrationTests.cs +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/BodyValidationIntegrationTests.cs @@ -3,12 +3,9 @@ using System.ComponentModel.DataAnnotations; using System.IO; -using System.Linq; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.ModelBinding; -using Microsoft.Framework.DependencyInjection; using Xunit; namespace Microsoft.AspNet.Mvc.IntegrationTests @@ -71,10 +68,10 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests { // Arrange var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); - var parameter = new ParameterDescriptor() + var parameter = new ParameterDescriptor { Name = "Parameter1", - BindingInfo = new BindingInfo() + BindingInfo = new BindingInfo { BinderModelName = "CustomParameter", BindingSource = BindingSource.Body @@ -99,8 +96,11 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.NotNull(modelBindingResult); Assert.True(modelBindingResult.IsModelSet); Assert.Null(modelBindingResult.Model); - Assert.Empty(modelState.Keys); + Assert.True(modelState.IsValid); + var entry = Assert.Single(modelState); + Assert.Empty(entry.Key); + Assert.Null(entry.Value.Value.RawValue); } private class Person4 @@ -111,14 +111,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests } [Fact] - public async Task FromBodyAndRequiredOnValueTypeProperty_EmptyBody_AddsModelStateError() + public async Task FromBodyAndRequiredOnValueTypeProperty_EmptyBody_JsonFormatterAddsModelStateError() { // Arrange var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); - var parameter = new ParameterDescriptor() + var parameter = new ParameterDescriptor { Name = "Parameter1", - BindingInfo = new BindingInfo() + BindingInfo = new BindingInfo { BinderModelName = "CustomParameter", }, @@ -141,16 +141,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.NotNull(modelBindingResult); Assert.True(modelBindingResult.IsModelSet); var boundPerson = Assert.IsType(modelBindingResult.Model); - Assert.NotNull(boundPerson); - Assert.False(modelState.IsValid); - // The error with an empty key is a bug(#2416) in our implementation which does not append the prefix and - // use that along with the path. The expected key here would be CustomParameter.Address. - var key = Assert.Single(modelState.Keys, k => k == ""); - var error = Assert.Single(modelState[""].Errors); - Assert.StartsWith( - "No JSON content found and type 'System.Int32' is not nullable.", - error.Exception.Message); + Assert.False(modelState.IsValid); + var entry = Assert.Single(modelState); + Assert.Equal(string.Empty, entry.Key); + var error = Assert.Single(entry.Value.Errors); + Assert.NotNull(error.Exception); + + // Json.NET currently throws an exception starting with "No JSON content found and type 'System.Int32' is + // not nullable." but do not tie test to a particular Json.NET build. + Assert.NotEmpty(error.Exception.Message); } private class Person2 @@ -167,16 +167,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests public int Zip { get; set; } } - [Theory(Skip = "There should be entries for all model properties which are bound. #2445")] + [Theory] [InlineData("{ \"Zip\" : 123 }")] [InlineData("{}")] public async Task FromBodyOnTopLevelProperty_RequiredOnSubProperty_AddsModelStateError(string inputText) { // Arrange var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); - var parameter = new ParameterDescriptor() + var parameter = new ParameterDescriptor { - BindingInfo = new BindingInfo() + BindingInfo = new BindingInfo { BinderModelName = "CustomParameter", }, @@ -200,14 +200,15 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.True(modelBindingResult.IsModelSet); var boundPerson = Assert.IsType(modelBindingResult.Model); Assert.NotNull(boundPerson); + Assert.False(modelState.IsValid); Assert.Equal(2, modelState.Keys.Count); - var zip = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address.Zip"); - Assert.Equal(ModelValidationState.Valid, modelState[zip].ValidationState); + var address = Assert.Single(modelState, kvp => kvp.Key == "CustomParameter.Address").Value; + Assert.Equal(ModelValidationState.Unvalidated, address.ValidationState); - var street = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address.Street"); - Assert.Equal(ModelValidationState.Invalid, modelState[street].ValidationState); - var error = Assert.Single(modelState[street].Errors); + var street = Assert.Single(modelState, kvp => kvp.Key == "CustomParameter.Address.Street").Value; + Assert.Equal(ModelValidationState.Invalid, street.ValidationState); + var error = Assert.Single(street.Errors); Assert.Equal("The Street field is required.", error.ErrorMessage); } @@ -225,16 +226,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests public int Zip { get; set; } } - [Theory(Skip = "There should be entries for all model properties which are bound. #2445")] + [Theory] [InlineData("{ \"Street\" : \"someStreet\" }")] [InlineData("{}")] - public async Task FromBodyOnProperty_RequiredOnValueTypeSubProperty_AddsModelStateError(string inputText) + public async Task FromBodyOnProperty_Succeeds_IgnoresRequiredOnValueTypeSubProperty(string inputText) { // Arrange var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); - var parameter = new ParameterDescriptor() + var parameter = new ParameterDescriptor { - BindingInfo = new BindingInfo() + BindingInfo = new BindingInfo { BinderModelName = "CustomParameter", }, @@ -255,20 +256,11 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // Assert Assert.NotNull(modelBindingResult); Assert.True(modelBindingResult.IsModelSet); - var boundPerson = Assert.IsType(modelBindingResult.Model); - Assert.NotNull(boundPerson); - Assert.False(modelState.IsValid); - var street = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address.Street"); - Assert.Equal(ModelValidationState.Valid, modelState[street].ValidationState); + Assert.IsType(modelBindingResult.Model); - // The error with an empty key is a bug(#2416) in our implementation which does not append the prefix and - // use that along with the path. The expected key here would be Address. - var zip = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address.Zip"); - Assert.Equal(ModelValidationState.Valid, modelState[zip].ValidationState); - var error = Assert.Single(modelState[""].Errors); - Assert.StartsWith( - "Required property 'Zip' not found in JSON. Path ''", - error.Exception.Message); + Assert.True(modelState.IsValid); + var entry = Assert.Single(modelState); + Assert.Equal("CustomParameter.Address", entry.Key); } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/ByteArrayModelBinderIntegrationTest.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/ByteArrayModelBinderIntegrationTest.cs index 08173274df..79ca9e9651 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/ByteArrayModelBinderIntegrationTest.cs +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/ByteArrayModelBinderIntegrationTest.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests public byte[] Token { get; set; } } - [Theory(Skip = "ModelState.Value not set due to #2445")] + [Theory] [InlineData(true)] [InlineData(false)] public async Task BindProperty_WithData_GetsBound(bool fallBackScenario) @@ -61,19 +61,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // ModelState Assert.True(modelState.IsValid); - Assert.Equal(2, modelState.Keys.Count); - Assert.Single(modelState.Keys, k => k == prefix); - Assert.Single(modelState.Keys, k => k == queryStringKey); - - var key = Assert.Single(modelState.Keys, k => k == queryStringKey + "[0]"); - Assert.NotNull(modelState[key].Value); // should be non null bug #2445. - Assert.Empty(modelState[key].Errors); - Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); - - key = Assert.Single(modelState.Keys, k => k == queryStringKey + "[1]"); - Assert.NotNull(modelState[key].Value); // should be non null bug #2445. - Assert.Empty(modelState[key].Errors); - Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); + var entry = Assert.Single(modelState); + Assert.Equal(queryStringKey, entry.Key); + Assert.Empty(entry.Value.Errors); + Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState); + Assert.Equal(value, entry.Value.Value.AttemptedValue); + Assert.Equal(value, entry.Value.Value.RawValue); } [Fact] @@ -109,19 +102,18 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Empty(modelState.Keys); } - [Fact(Skip = "ModelState.Value not set due to #2445")] + [Fact] public async Task BindParameter_WithData_GetsBound() { // Arrange var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); - var parameter = new ParameterDescriptor() + var parameter = new ParameterDescriptor { Name = "Parameter1", - BindingInfo = new BindingInfo() + BindingInfo = new BindingInfo { BinderModelName = "CustomParameter", }, - ParameterType = typeof(byte[]) }; @@ -151,16 +143,11 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // ModelState Assert.True(modelState.IsValid); - - Assert.Equal(3, modelState.Count); - Assert.Single(modelState.Keys, k => k == "CustomParameter[0]"); - Assert.Single(modelState.Keys, k => k == "CustomParameter[1]"); - var key = Assert.Single(modelState.Keys, k => k == "CustomParameter[2]"); - - Assert.NotNull(modelState[key].Value); - Assert.Equal(value, modelState[key].Value.AttemptedValue); - Assert.Equal(expectedValue, modelState[key].Value.RawValue); - Assert.Empty(modelState[key].Errors); + var entry = Assert.Single(modelState); + Assert.Equal("CustomParameter", entry.Key); + Assert.Empty(entry.Value.Errors); + Assert.Equal(value, entry.Value.Value.AttemptedValue); + Assert.Equal(value, entry.Value.Value.RawValue); } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/FormCollectionModelBindingIntegrationTest.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/FormCollectionModelBindingIntegrationTest.cs index 40cc235f06..b6d10783d1 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/FormCollectionModelBindingIntegrationTest.cs +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/FormCollectionModelBindingIntegrationTest.cs @@ -27,12 +27,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests public FormCollection FileCollection { get; set; } } - [Fact(Skip = "ModelState.Value not set due to #2445")] + [Fact] public async Task BindProperty_WithData_WithEmptyPrefix_GetsBound() { // Arrange var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); - var parameter = new ParameterDescriptor() + var parameter = new ParameterDescriptor { Name = "Parameter1", BindingInfo = new BindingInfo(), @@ -69,12 +69,10 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // ModelState Assert.True(modelState.IsValid); - Assert.Equal(2, modelState.Count); - Assert.Single(modelState.Keys, k => k == "Address.Zip"); - var key = Assert.Single(modelState.Keys, k => k == "Address.File"); - Assert.NotNull(modelState[key].Value); // should be non null bug #2445. - Assert.Empty(modelState[key].Errors); - Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); + var entry = Assert.Single(modelState); + Assert.Equal("Address.Zip", entry.Key); + Assert.Empty(entry.Value.Errors); + Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState); } [Fact] @@ -82,15 +80,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests { // Arrange var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); - var parameter = new ParameterDescriptor() + var parameter = new ParameterDescriptor { Name = "Parameter1", - BindingInfo = new BindingInfo() + BindingInfo = new BindingInfo { // Setting a custom parameter prevents it from falling back to an empty prefix. BinderModelName = "CustomParameter", }, - ParameterType = typeof(FormCollection) }; @@ -113,7 +110,6 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // Model var formCollection = Assert.IsType(modelBindingResult.Model); - Assert.NotNull(formCollection); var file = Assert.Single(formCollection.Files); Assert.NotNull(file); Assert.Equal("form-data; name=CustomParameter; filename=text.txt", file.ContentDisposition); @@ -122,10 +118,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // ModelState Assert.True(modelState.IsValid); - - // Validation should be skipped because we do not validate any parameters and since IFormFile is not - // IValidatableObject, we should have no entries in the model state dictionary. - Assert.Empty(modelState.Keys); + Assert.Empty(modelState); } [Fact] @@ -133,21 +126,18 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests { // Arrange var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); - var parameter = new ParameterDescriptor() + var parameter = new ParameterDescriptor { Name = "Parameter1", - BindingInfo = new BindingInfo() + BindingInfo = new BindingInfo { BinderModelName = "CustomParameter", }, - ParameterType = typeof(FormCollection) }; // No data is passed. - var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => - { - }); + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(); var modelState = new ModelStateDictionary(); @@ -162,7 +152,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // ModelState Assert.True(modelState.IsValid); - Assert.Empty(modelState.Keys); + Assert.Empty(modelState); // FormCollection Assert.Empty(collection); diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/FormFileModelBindingIntegrationTest.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/FormFileModelBindingIntegrationTest.cs index e5059d91bd..f73456d4a7 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/FormFileModelBindingIntegrationTest.cs +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/FormFileModelBindingIntegrationTest.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests public IFormFile File { get; set; } } - [Fact(Skip = "ModelState.Value not set due to #2445")] + [Fact] public async Task BindProperty_WithData_WithEmptyPrefix_GetsBound() { // Arrange @@ -71,7 +71,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Equal(2, modelState.Count); Assert.Single(modelState.Keys, k => k == "Address.Zip"); var key = Assert.Single(modelState.Keys, k => k == "Address.File"); - Assert.NotNull(modelState[key].Value); // should be non null bug #2445. + Assert.NotNull(modelState[key].Value); Assert.Empty(modelState[key].Errors); Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); } @@ -81,15 +81,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests { // Arrange var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); - var parameter = new ParameterDescriptor() + var parameter = new ParameterDescriptor { Name = "Parameter1", - BindingInfo = new BindingInfo() + BindingInfo = new BindingInfo { // Setting a custom parameter prevents it from falling back to an empty prefix. BinderModelName = "CustomParameter", }, - ParameterType = typeof(IFormFile) }; @@ -119,10 +118,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // ModelState Assert.True(modelState.IsValid); - - // Validation should be skipped because we do not validate any parameters and since IFormFile is not - // IValidatableObject, we should have no entries in the model state dictionary. - Assert.Empty(modelState.Keys); + var entry = Assert.Single(modelState); + Assert.Equal("CustomParameter", entry.Key); + Assert.Empty(entry.Value.Errors); + Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState); + Assert.Null(entry.Value.Value.AttemptedValue); + Assert.Equal(file, entry.Value.Value.RawValue); } [Fact] diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/GenericModelBinderIntegrationTest.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/GenericModelBinderIntegrationTest.cs index b1a026d06e..ec625e5f90 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/GenericModelBinderIntegrationTest.cs +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/GenericModelBinderIntegrationTest.cs @@ -18,8 +18,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // This isn't an especially useful scenario - but it exercises what happens when you // try to use a Collection of something that is bound greedily by model-type. // - // In this example we choose IFormCollection - because IFormCollection has a dedicated - // model binder. + // In this example we choose IFormCollection because IFormCollection has a dedicated + // model binder. [Fact] public async Task GenericModelBinder_BindsCollection_ElementTypeFromGreedyModelBinder_WithPrefix_Success() { @@ -47,12 +47,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.True(modelBindingResult.IsModelSet); var model = Assert.IsType>(modelBindingResult.Model); - Assert.Equal(1, model.Count); - Assert.NotNull(model[0]); + var formCollection = Assert.Single(model); + Assert.NotNull(formCollection); - Assert.Equal(0, modelState.Count); Assert.Equal(0, modelState.ErrorCount); Assert.True(modelState.IsValid); + Assert.Empty(modelState); } // This isn't an especially useful scenario - but it exercises what happens when you @@ -86,12 +86,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.True(modelBindingResult.IsModelSet); var model = Assert.IsType>(modelBindingResult.Model); - Assert.Equal(1, model.Count); - Assert.NotNull(model[0]); + var formCollection = Assert.Single(model); + Assert.NotNull(formCollection); - Assert.Equal(0, modelState.Count); Assert.Equal(0, modelState.ErrorCount); Assert.True(modelState.IsValid); + Assert.Empty(modelState); } // This isn't an especially useful scenario - but it exercises what happens when you @@ -217,7 +217,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests ParameterType = typeof(Dictionary[]) }; - var operationContext = ModelBindingTestHelper.GetOperationBindingContext((request) => + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { request.QueryString = new QueryString("?parameter[0][0].Key=key0¶meter[0][0].Value=10"); }); @@ -263,7 +263,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests ParameterType = typeof(Dictionary[]) }; - var operationContext = ModelBindingTestHelper.GetOperationBindingContext((request) => + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { request.QueryString = new QueryString("?[0][0].Key=key0&[0][0].Value=10"); }); @@ -309,7 +309,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests ParameterType = typeof(Dictionary[]) }; - var operationContext = ModelBindingTestHelper.GetOperationBindingContext((request) => + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { request.QueryString = new QueryString("?"); }); @@ -345,7 +345,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests ParameterType = typeof(ICollection>) }; - var operationContext = ModelBindingTestHelper.GetOperationBindingContext((request) => + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { request.QueryString = new QueryString("?parameter[0].Key=key0¶meter[0].Value=10"); }); @@ -390,7 +390,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests ParameterType = typeof(ICollection>) }; - var operationContext = ModelBindingTestHelper.GetOperationBindingContext((request) => + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { request.QueryString = new QueryString("?[0].Key=key0&[0].Value=10"); }); @@ -435,7 +435,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests ParameterType = typeof(Collection>) }; - var operationContext = ModelBindingTestHelper.GetOperationBindingContext((request) => + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { request.QueryString = new QueryString("?"); }); @@ -471,7 +471,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests ParameterType = typeof(Dictionary>) }; - var operationContext = ModelBindingTestHelper.GetOperationBindingContext((request) => + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { request.QueryString = new QueryString( "?parameter[0].Key=key0¶meter[0].Value[0]=10¶meter[0].Value[1]=11"); @@ -521,7 +521,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests ParameterType = typeof(Dictionary>) }; - var operationContext = ModelBindingTestHelper.GetOperationBindingContext((request) => + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { request.QueryString = new QueryString("?[0].Key=key0&[0].Value[0]=10&[0].Value[1]=11"); }); @@ -570,7 +570,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests ParameterType = typeof(Dictionary>) }; - var operationContext = ModelBindingTestHelper.GetOperationBindingContext((request) => + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { request.QueryString = new QueryString("?"); }); diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/HeaderModelBinderIntegrationTest.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/HeaderModelBinderIntegrationTest.cs index 3d92e4a5e0..dcaaa244bc 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/HeaderModelBinderIntegrationTest.cs +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/HeaderModelBinderIntegrationTest.cs @@ -65,7 +65,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Equal("The Street field is required.", error.ErrorMessage); } - [Fact(Skip = "ModelState.Value not set due to #2445")] + [Fact] public async Task BindPropertyFromHeader_WithPrefix_GetsBound() { // Arrange @@ -104,19 +104,17 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // ModelState Assert.True(modelState.IsValid); - Assert.Equal(3, modelState.Count); - Assert.Single(modelState.Keys, k => k == "prefix.Address"); - Assert.Single(modelState.Keys, k => k == "prefix"); - - var key = Assert.Single(modelState.Keys, k => k == "prefix.Address.Header"); - Assert.NotNull(modelState[key].Value); - Assert.Equal("someValue", modelState[key].Value.RawValue); - Assert.Equal("someValue", modelState[key].Value.AttemptedValue); + var entry = Assert.Single(modelState); + Assert.Equal("prefix.Address.Header", entry.Key); + Assert.Empty(entry.Value.Errors); + Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState); + Assert.Equal("someValue", entry.Value.Value.AttemptedValue); + Assert.Equal("someValue", entry.Value.Value.RawValue); } // The scenario is interesting as we to bind the top level model we fallback to empty prefix, // and hence the model state keys have an empty prefix. - [Fact(Skip = "ModelState.Value not set due to #2445.")] + [Fact] public async Task BindPropertyFromHeader_WithData_WithEmptyPrefix_GetsBound() { // Arrange @@ -128,11 +126,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests ParameterType = typeof(Person) }; - // Do not add any headers. - var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { - request.Headers.Add("Header", new[] { "someValue" }); - }); - + var operationContext = ModelBindingTestHelper.GetOperationBindingContext( + request => request.Headers.Add("Header", new[] { "someValue" })); var modelState = new ModelStateDictionary(); // Act @@ -152,27 +147,29 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // ModelState Assert.True(modelState.IsValid); - Assert.Equal(2, modelState.Count); - Assert.Single(modelState.Keys, k => k == "Address"); - var key = Assert.Single(modelState.Keys, k => k == "Address.Header"); - Assert.NotNull(modelState[key].Value); - Assert.Equal("someValue", modelState[key].Value.RawValue); - Assert.Equal("someValue", modelState[key].Value.AttemptedValue); + var entry = Assert.Single(modelState); + Assert.Equal("Address.Header", entry.Key); + Assert.Empty(entry.Value.Errors); + Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState); + Assert.Equal("someValue", entry.Value.Value.AttemptedValue); + Assert.Equal("someValue", entry.Value.Value.RawValue); } - [Theory(Skip = "Greedy Model Binders should add a value in model state #2445.")] + [Theory] [InlineData(typeof(string[]), "value1, value2, value3")] [InlineData(typeof(string), "value")] public async Task BindParameterFromHeader_WithData_WithPrefix_ModelGetsBound(Type modelType, string value) { // Arrange - var expectedValue = value.Split(',').Select(v => v.Trim()); + var expectedValue = modelType == typeof(string) ? + (object)value : + (object)value.Split(',').Select(v => v.Trim()).ToArray(); var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(); - var parameter = new ParameterDescriptor() + var parameter = new ParameterDescriptor { Name = "Parameter1", - BindingInfo = new BindingInfo() + BindingInfo = new BindingInfo { BinderModelName = "CustomParameter", BindingSource = BindingSource.Header @@ -180,7 +177,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests ParameterType = modelType }; - Action action = (r) => r.Headers.Add("CustomParameter", new[] { value }); + Action action = r => r.Headers.Add("CustomParameter", new[] { value }); var operationContext = ModelBindingTestHelper.GetOperationBindingContext(action); // Do not add any headers. @@ -202,12 +199,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // ModelState Assert.True(modelState.IsValid); - var key = Assert.Single(modelState.Keys); - Assert.Equal("CustomParameter", key); - - Assert.NotNull(modelState[key].Value); - Assert.Equal(expectedValue, modelState[key].Value.RawValue); - Assert.Equal(value, modelState[key].Value.AttemptedValue); + var entry = Assert.Single(modelState); + Assert.Equal("CustomParameter", entry.Key); + Assert.Empty(entry.Value.Errors); + Assert.Equal(ModelValidationState.Valid, entry.Value.ValidationState); + Assert.Equal(value, entry.Value.Value.AttemptedValue); + Assert.Equal(expectedValue, entry.Value.Value.RawValue); } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/MutableObjectModelBinderIntegrationTest.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/MutableObjectModelBinderIntegrationTest.cs index 363b1c5009..eb187ba7dd 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/MutableObjectModelBinderIntegrationTest.cs +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/MutableObjectModelBinderIntegrationTest.cs @@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests public string Street { get; set; } } - [Fact(Skip = "ModelState.Value not set due to #2445.")] + [Fact] public async Task MutableObjectModelBinder_BindsNestedPOCO_WithBodyModelBinder_WithPrefix_Success() { // Arrange @@ -85,13 +85,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.Value.RawValue); - // These fail due to #2445 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.Same(model.Customer.Address, entry.Value.RawValue); } - [Fact(Skip = "ModelState.Value not set due to #2445.")] + [Fact] public async Task MutableObjectModelBinder_BindsNestedPOCO_WithBodyModelBinder_WithEmptyPrefix_Success() { // Arrange @@ -132,7 +131,6 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.Value.RawValue); - // These fail due to #2445 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.Same(model.Customer.Address, entry.Value.RawValue); @@ -170,11 +168,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Equal("bill", model.Customer.Name); Assert.Null(model.Customer.Address); - Assert.Equal(1, modelState.Count); + Assert.Equal(2, modelState.Count); Assert.Equal(0, modelState.ErrorCount); 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.Address").Value; + Assert.Null(entry.Value.AttemptedValue); + Assert.Null(entry.Value.RawValue); + entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.Value.RawValue); } @@ -446,7 +447,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests public byte[] Token { get; set; } } - [Fact(Skip = "Greedy model binders should set value. #2445")] + [Fact] public async Task MutableObjectModelBinder_BindsNestedPOCO_WithByteArrayModelBinder_WithPrefix_Success() { // Arrange @@ -478,7 +479,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Equal("bill", model.Customer.Name); Assert.Equal(ByteArrayContent, model.Customer.Token); - Assert.Equal(2, modelState.Count); // This fails due to #2445 + Assert.Equal(2, modelState.Count); Assert.Equal(0, modelState.ErrorCount); Assert.True(modelState.IsValid); @@ -486,13 +487,12 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.Value.RawValue); - // These fail due to #2445 entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Token").Value; Assert.Equal(ByteArrayEncoded, entry.Value.AttemptedValue); Assert.Equal(ByteArrayEncoded, entry.Value.RawValue); } - [Fact(Skip = "Greedy model binders should set value. #2445")] + [Fact] public async Task MutableObjectModelBinder_BindsNestedPOCO_WithByteArrayModelBinder_WithEmptyPrefix_Success() { // Arrange @@ -544,17 +544,13 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests var parameter = new ParameterDescriptor() { Name = "parameter", - ParameterType = typeof(Order1) + ParameterType = typeof(Order3) }; // Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements. var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { request.QueryString = new QueryString("?parameter.Customer.Name=bill"); - - // This is set so that the input formatter does not add an error to model state. - // Thus this prevents addition of an extra error unrelated to the test scenario. - request.ContentType = "application/json"; }); var modelState = new ModelStateDictionary(); @@ -566,10 +562,10 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.NotNull(modelBindingResult); Assert.True(modelBindingResult.IsModelSet); - var model = Assert.IsType(modelBindingResult.Model); + var model = Assert.IsType(modelBindingResult.Model); Assert.NotNull(model.Customer); Assert.Equal("bill", model.Customer.Name); - Assert.Null(model.Customer.Address); + Assert.Null(model.Customer.Token); Assert.Equal(1, modelState.Count); Assert.Equal(0, modelState.ErrorCount); @@ -594,7 +590,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests public IEnumerable Documents { get; set; } } - [Fact(Skip = "Greedy model binders should set value. #2445")] + [Fact] public async Task MutableObjectModelBinder_BindsNestedPOCO_WithFormFileModelBinder_WithPrefix_Success() { // Arrange @@ -626,7 +622,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Equal("bill", model.Customer.Name); Assert.Single(model.Customer.Documents); - Assert.Equal(2, modelState.Count); // This fails due to #2445 + Assert.Equal(2, modelState.Count); Assert.Equal(0, modelState.ErrorCount); Assert.True(modelState.IsValid); @@ -639,7 +635,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Same(model.Customer.Documents, entry.Value.RawValue); } - [Fact(Skip = "Greedy model binders should set value. #2445")] + [Fact] public async Task MutableObjectModelBinder_BindsNestedPOCO_WithFormFileModelBinder_WithEmptyPrefix_Success() { // Arrange @@ -717,11 +713,16 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Equal("bill", model.Customer.Name); Assert.Empty(model.Customer.Documents); - Assert.Equal(1, modelState.Count); + Assert.Equal(2, modelState.Count); Assert.Equal(0, modelState.ErrorCount); 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.Documents").Value; + Assert.Null(entry.Value.AttemptedValue); + var documents = Assert.IsAssignableFrom>(entry.Value.RawValue); + Assert.Empty(documents); + + entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value; Assert.Equal("bill", entry.Value.AttemptedValue); Assert.Equal("bill", entry.Value.RawValue); } @@ -1529,7 +1530,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // If a nested POCO object has all properties bound from a greedy source, then it should be populated // if the top-level object is created. - [Fact(Skip = "ModelState.Value not set due to #2445.")] + [Fact] public async Task MutableObjectModelBinder_BindsNestedPOCO_WithAllGreedyBoundProperties() { // Arrange @@ -1567,7 +1568,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.True(modelState.IsValid); var entry = Assert.Single(modelState, e => e.Key == "Customer.Address").Value; - Assert.Null(entry.Value.AttemptedValue); // This fails due to #2445 + Assert.Null(entry.Value.AttemptedValue); Assert.Same(model.Customer.Address, entry.Value.RawValue); } diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/ValidationIntegrationTests.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/ValidationIntegrationTests.cs index dfccd8d93b..0c5dc8a502 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/ValidationIntegrationTests.cs +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/ValidationIntegrationTests.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Name = "parameter", ParameterType = typeof(Order1) }; - + var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { request.QueryString = new QueryString("?parameter.CustomerName=bill"); @@ -1020,6 +1020,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests private class Address { public int Street { get; set; } + public string State { get; set; } [Range(10000, 99999)] @@ -1032,30 +1033,32 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests { public string Name { get; set; } } + [Fact] public async Task TypeBasedExclusion_ForBodyAndNonBodyBoundModels() { // Arrange - var parameter = new ParameterDescriptor() + var parameter = new ParameterDescriptor { Name = "parameter", ParameterType = typeof(Order11) }; MvcOptions testOptions = null; - var input = "{\"OfficeAddress.Zip\":\"45\"}"; - var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => - { - request.QueryString = - new QueryString("?HomeAddress.Country.Name=US&ShippingAddresses[0].Zip=45&HomeAddress.Zip=46"); - request.Body = new MemoryStream(Encoding.UTF8.GetBytes(input)); - request.ContentType = "application/json"; - }, - options => { - - options.ValidationExcludeFilters.Add(typeof(Address)); - testOptions = options; - }); + var input = "{\"Zip\":\"47\"}"; + var operationContext = ModelBindingTestHelper.GetOperationBindingContext( + request => + { + request.QueryString = + new QueryString("?HomeAddress.Country.Name=US&ShippingAddresses[0].Zip=45&HomeAddress.Zip=46"); + request.Body = new MemoryStream(Encoding.UTF8.GetBytes(input)); + request.ContentType = "application/json"; + }, + options => + { + options.ValidationExcludeFilters.Add(typeof(Address)); + testOptions = options; + }); var argumentBinder = ModelBindingTestHelper.GetArgumentBinder(testOptions); var modelState = new ModelStateDictionary(); @@ -1063,7 +1066,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests // Act var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext); - Assert.Equal(3, modelState.Count); + Assert.Equal(4, modelState.Count); Assert.Equal(0, modelState.ErrorCount); Assert.True(modelState.IsValid); @@ -1081,6 +1084,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests Assert.Equal("46", entry.Value.AttemptedValue); Assert.Equal("46", entry.Value.RawValue); Assert.Equal(ModelValidationState.Skipped, entry.ValidationState); + + entry = Assert.Single(modelState, e => e.Key == "OfficeAddress").Value; + Assert.Null(entry.Value.AttemptedValue); + var address = Assert.IsType
(entry.Value.RawValue); + Assert.Equal(47, address.Zip); + + // Address itself is not excluded from validation. + Assert.Equal(ModelValidationState.Valid, entry.ValidationState); } private static void AssertRequiredError(string key, ModelError error)