Fix #1579 - Bind top-level collections as an empty collection

This change treats 'top-level' collection-type models similarly to
top-level POCO model - namely that they will always be instantiated even
if there's no data to put inside.
This commit is contained in:
Ryan Nowak 2015-05-19 14:32:11 -07:00
parent b64fd7ae39
commit 8f38650d1f
15 changed files with 602 additions and 54 deletions

View File

@ -25,6 +25,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return base.BindModelAsync(bindingContext);
}
protected override object CreateEmptyCollection()
{
return new TElement[0];
}
/// <inheritdoc />
protected override object GetModel(IEnumerable<TElement> newCollection)
{

View File

@ -23,8 +23,31 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
ModelBindingHelper.ValidateBindingContext(bindingContext);
object model;
if (!await bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName))
{
// If this is the fallback case, and we failed to find data as a top-level model, then generate a
// default 'empty' model and return it.
var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;
var hasExplicitAlias = bindingContext.BinderModelName != null;
if (isTopLevelObject && (hasExplicitAlias || bindingContext.ModelName == string.Empty))
{
model = CreateEmptyCollection();
var validationNode = new ModelValidationNode(
bindingContext.ModelName,
bindingContext.ModelMetadata,
model);
return new ModelBindingResult(
model,
bindingContext.ModelName,
isModelSet: true,
validationNode: validationNode);
}
return null;
}
@ -46,7 +69,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
boundCollection = result.Model;
}
var model = bindingContext.Model;
model = bindingContext.Model;
if (model == null)
{
model = GetModel(boundCollection);
@ -64,6 +87,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
validationNode: result?.ValidationNode);
}
// Called when we're creating a default 'empty' model for a top level bind.
protected virtual object CreateEmptyCollection()
{
return new List<TElement>();
}
// Used when the ValueProvider contains the collection to be bound as a single element, e.g. the raw value
// is [ "1", "2" ] and needs to be converted to an int[].
internal async Task<CollectionResult> BindSimpleCollection(
@ -165,8 +194,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var didBind = false;
object boundValue = null;
var modelType = bindingContext.ModelType;
var result =
await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(childBindingContext);
if (result != null && result.IsModelSet)

View File

@ -18,5 +18,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
return newCollection?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
protected override object CreateEmptyCollection()
{
return new Dictionary<TKey, TValue>();
}
}
}

View File

@ -62,8 +62,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
}
else
{
// Caller (GenericModelBinder) was able to resolve a binder type and will create a ModelBindingResult
// that exits current ModelBinding loop.
// If this is the fallback case, and we failed to find data as a top-level model, then generate a
// default 'empty' model and return it.
var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;
var hasExplicitAlias = bindingContext.BinderModelName != null;
if (isTopLevelObject && (hasExplicitAlias || bindingContext.ModelName == string.Empty))
{
var model = new KeyValuePair<TKey, TValue>();
var validationNode = new ModelValidationNode(
bindingContext.ModelName,
bindingContext.ModelMetadata,
model);
return new ModelBindingResult(
model,
bindingContext.ModelName,
isModelSet: true,
validationNode: validationNode);
}
return null;
}
}

View File

@ -2,7 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if DNX451
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Internal;
using Moq;
using Xunit;
@ -35,14 +37,105 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
}
[Fact]
public async Task BindModelAsync_ValueProviderDoesNotContainPrefix_ReturnsNull()
public async Task ArrayModelBinder_DoesNotCreateCollection_ForTopLevelModel_OnFirstPass()
{
// Arrange
var bindingContext = GetBindingContext(new SimpleHttpValueProvider());
var binder = new ArrayModelBinder<int>();
var binder = new ArrayModelBinder<string>();
var context = CreateContext();
context.ModelName = "param";
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string[]));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(bindingContext);
var result = await binder.BindModelAsync(context);
// Assert
Assert.Null(result);
}
[Fact]
public async Task ArrayModelBinder_CreatesEmptyCollection_ForTopLevelModel_OnFallback()
{
// Arrange
var binder = new ArrayModelBinder<string>();
var context = CreateContext();
context.ModelName = string.Empty;
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string[]));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.NotNull(result);
Assert.Empty(Assert.IsType<string[]>(result.Model));
Assert.Equal(string.Empty, result.Key);
Assert.True(result.IsModelSet);
Assert.Same(result.ValidationNode.Model, result.Model);
Assert.Same(result.ValidationNode.Key, result.Key);
Assert.Same(result.ValidationNode.ModelMetadata, context.ModelMetadata);
}
[Fact]
public async Task ArrayModelBinder_CreatesEmptyCollection_ForTopLevelModel_WithExplicitPrefix()
{
// Arrange
var binder = new ArrayModelBinder<string>();
var context = CreateContext();
context.ModelName = "prefix";
context.BinderModelName = "prefix";
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string[]));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.NotNull(result);
Assert.Empty(Assert.IsType<string[]>(result.Model));
Assert.Equal("prefix", result.Key);
Assert.True(result.IsModelSet);
Assert.Same(result.ValidationNode.Model, result.Model);
Assert.Same(result.ValidationNode.Key, result.Key);
Assert.Same(result.ValidationNode.ModelMetadata, context.ModelMetadata);
}
[Theory]
[InlineData("")]
[InlineData("param")]
public async Task ArrayModelBinder_DoesNotCreateCollection_ForNonTopLevelModel(string prefix)
{
// Arrange
var binder = new ArrayModelBinder<string>();
var context = CreateContext();
context.ModelName = ModelNames.CreatePropertyModelName(prefix, "ArrayProperty");
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForProperty(
typeof(ModelWithArrayProperty),
nameof(ModelWithArrayProperty.ArrayProperty));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.Null(result);
@ -155,6 +248,25 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
};
return bindingContext;
}
private static ModelBindingContext CreateContext()
{
var modelBindingContext = new ModelBindingContext()
{
OperationBindingContext = new OperationBindingContext()
{
HttpContext = new DefaultHttpContext(),
MetadataProvider = new TestModelMetadataProvider(),
}
};
return modelBindingContext;
}
private class ModelWithArrayProperty
{
public string[] ArrayProperty { get; set; }
}
}
}
#endif

View File

@ -7,6 +7,7 @@ using System.Globalization;
using System.Linq;
#endif
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Internal;
#if DNX451
using Moq;
#endif
@ -216,6 +217,111 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
Assert.Null(boundCollection);
}
[Fact]
public async Task CollectionModelBinder_DoesNotCreateCollection_ForTopLevelModel_OnFirstPass()
{
// Arrange
var binder = new CollectionModelBinder<string>();
var context = CreateContext();
context.ModelName = "param";
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(List<string>));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.Null(result);
}
[Fact]
public async Task CollectionModelBinder_CreatesEmptyCollection_ForTopLevelModel_OnFallback()
{
// Arrange
var binder = new CollectionModelBinder<string>();
var context = CreateContext();
context.ModelName = string.Empty;
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(List<string>));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.NotNull(result);
Assert.Empty(Assert.IsType<List<string>>(result.Model));
Assert.Equal(string.Empty, result.Key);
Assert.True(result.IsModelSet);
Assert.Same(result.ValidationNode.Model, result.Model);
Assert.Same(result.ValidationNode.Key, result.Key);
Assert.Same(result.ValidationNode.ModelMetadata, context.ModelMetadata);
}
[Fact]
public async Task CollectionModelBinder_CreatesEmptyCollection_ForTopLevelModel_WithExplicitPrefix()
{
// Arrange
var binder = new CollectionModelBinder<string>();
var context = CreateContext();
context.ModelName = "prefix";
context.BinderModelName = "prefix";
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(List<string>));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.NotNull(result);
Assert.Empty(Assert.IsType<List<string>>(result.Model));
Assert.Equal("prefix", result.Key);
Assert.True(result.IsModelSet);
Assert.Same(result.ValidationNode.Model, result.Model);
Assert.Same(result.ValidationNode.Key, result.Key);
Assert.Same(result.ValidationNode.ModelMetadata, context.ModelMetadata);
}
[Theory]
[InlineData("")]
[InlineData("param")]
public async Task CollectionModelBinder_DoesNotCreateCollection_ForNonTopLevelModel(string prefix)
{
// Arrange
var binder = new CollectionModelBinder<string>();
var context = CreateContext();
context.ModelName = ModelNames.CreatePropertyModelName(prefix, "ListProperty");
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForProperty(
typeof(ModelWithListProperty),
nameof(ModelWithListProperty.ListProperty));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.Null(result);
}
#if DNX451
[Fact]
public async Task BindSimpleCollection_SubBindingSucceeds()
@ -284,5 +390,24 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
return mockIntBinder.Object;
}
#endif
private static ModelBindingContext CreateContext()
{
var modelBindingContext = new ModelBindingContext()
{
OperationBindingContext = new OperationBindingContext()
{
HttpContext = new DefaultHttpContext(),
MetadataProvider = new TestModelMetadataProvider(),
}
};
return modelBindingContext;
}
private class ModelWithListProperty
{
public List<string> ListProperty { get; set; }
}
}
}

View File

@ -4,6 +4,7 @@
#if DNX451
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Internal;
using Moq;
using Xunit;
@ -63,6 +64,125 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
Assert.Equal("eighty-four", dictionary[84]);
}
[Fact]
public async Task DictionaryModelBinder_DoesNotCreateCollection_ForTopLevelModel_OnFirstPass()
{
// Arrange
var binder = new DictionaryModelBinder<string, string>();
var context = CreateContext();
context.ModelName = "param";
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(Dictionary<string, string>));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.Null(result);
}
[Fact]
public async Task DictionaryModelBinder_CreatesEmptyCollection_ForTopLevelModel_OnFallback()
{
// Arrange
var binder = new DictionaryModelBinder<string, string>();
var context = CreateContext();
context.ModelName = string.Empty;
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(Dictionary<string, string>));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.NotNull(result);
Assert.Empty(Assert.IsType<Dictionary<string, string>>(result.Model));
Assert.Equal(string.Empty, result.Key);
Assert.True(result.IsModelSet);
Assert.Same(result.ValidationNode.Model, result.Model);
Assert.Same(result.ValidationNode.Key, result.Key);
Assert.Same(result.ValidationNode.ModelMetadata, context.ModelMetadata);
}
[Fact]
public async Task DictionaryModelBinder_CreatesEmptyCollection_ForTopLevelModel_WithExplicitPrefix()
{
// Arrange
var binder = new DictionaryModelBinder<string, string>();
var context = CreateContext();
context.ModelName = "prefix";
context.BinderModelName = "prefix";
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(Dictionary<string, string>));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.NotNull(result);
Assert.Empty(Assert.IsType<Dictionary<string, string>>(result.Model));
Assert.Equal("prefix", result.Key);
Assert.True(result.IsModelSet);
Assert.Same(result.ValidationNode.Model, result.Model);
Assert.Same(result.ValidationNode.Key, result.Key);
Assert.Same(result.ValidationNode.ModelMetadata, context.ModelMetadata);
}
[Theory]
[InlineData("")]
[InlineData("param")]
public async Task DictionaryModelBinder_DoesNotCreateCollection_ForNonTopLevelModel(string prefix)
{
// Arrange
var binder = new DictionaryModelBinder<string, string>();
var context = CreateContext();
context.ModelName = ModelNames.CreatePropertyModelName(prefix, "ListProperty");
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForProperty(
typeof(ModelWithDictionaryProperty),
nameof(ModelWithDictionaryProperty.DictionaryProperty));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.Null(result);
}
private static ModelBindingContext CreateContext()
{
var modelBindingContext = new ModelBindingContext()
{
OperationBindingContext = new OperationBindingContext()
{
HttpContext = new DefaultHttpContext(),
MetadataProvider = new TestModelMetadataProvider(),
}
};
return modelBindingContext;
}
private static ModelBindingContext GetModelBindingContext(bool isReadOnly)
{
var metadataProvider = new TestModelMetadataProvider();
@ -105,6 +225,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
});
return mockKvpBinder.Object;
}
private class ModelWithDictionaryProperty
{
public Dictionary<string, string> DictionaryProperty { get; set; }
}
}
}
#endif

View File

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Moq;
using Xunit;
@ -158,6 +159,126 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
Assert.Empty(bindingContext.ModelState);
}
[Fact]
public async Task KeyValuePairModelBinder_DoesNotCreateCollection_ForTopLevelModel_OnFirstPass()
{
// Arrange
var binder = new KeyValuePairModelBinder<string, string>();
var context = CreateContext();
context.ModelName = "param";
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(KeyValuePair<string, string>));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.Null(result);
}
[Fact]
public async Task KeyValuePairModelBinder_CreatesEmptyCollection_ForTopLevelModel_OnFallback()
{
// Arrange
var binder = new KeyValuePairModelBinder<string, string>();
var context = CreateContext();
context.ModelName = string.Empty;
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(KeyValuePair<string, string>));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.NotNull(result);
Assert.Equal(default(KeyValuePair<string, string>), Assert.IsType<KeyValuePair<string, string>>(result.Model));
Assert.Equal(string.Empty, result.Key);
Assert.True(result.IsModelSet);
Assert.Equal(result.ValidationNode.Model, result.Model);
Assert.Same(result.ValidationNode.Key, result.Key);
Assert.Same(result.ValidationNode.ModelMetadata, context.ModelMetadata);
}
[Fact]
public async Task KeyValuePairModelBinder_CreatesEmptyCollection_ForTopLevelModel_WithExplicitPrefix()
{
// Arrange
var binder = new KeyValuePairModelBinder<string, string>();
var context = CreateContext();
context.ModelName = "prefix";
context.BinderModelName = "prefix";
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(KeyValuePair<string, string>));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.NotNull(result);
Assert.Equal(default(KeyValuePair<string, string>), Assert.IsType<KeyValuePair<string, string>>(result.Model));
Assert.Equal("prefix", result.Key);
Assert.True(result.IsModelSet);
Assert.Equal(result.ValidationNode.Model, result.Model);
Assert.Same(result.ValidationNode.Key, result.Key);
Assert.Same(result.ValidationNode.ModelMetadata, context.ModelMetadata);
}
[Theory]
[InlineData("")]
[InlineData("param")]
public async Task KeyValuePairModelBinder_DoesNotCreateCollection_ForNonTopLevelModel(string prefix)
{
// Arrange
var binder = new KeyValuePairModelBinder<string, string>();
var context = CreateContext();
context.ModelName = ModelNames.CreatePropertyModelName(prefix, "KeyValuePairProperty");
var metadataProvider = context.OperationBindingContext.MetadataProvider;
context.ModelMetadata = metadataProvider.GetMetadataForProperty(
typeof(ModelWithKeyValuePairProperty),
nameof(ModelWithKeyValuePairProperty.KeyValuePairProperty));
context.ValueProvider = new TestValueProvider(new Dictionary<string, object>());
// Act
var result = await binder.BindModelAsync(context);
// Assert
Assert.Null(result);
}
private static ModelBindingContext CreateContext()
{
var modelBindingContext = new ModelBindingContext()
{
OperationBindingContext = new OperationBindingContext()
{
HttpContext = new DefaultHttpContext(),
MetadataProvider = new TestModelMetadataProvider(),
ModelBinder = new TypeMatchModelBinder(),
}
};
return modelBindingContext;
}
private static ModelBindingContext GetBindingContext(
IValueProvider valueProvider,
IModelBinder innerBinder = null,
@ -210,6 +331,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
});
return mockStringBinder.Object;
}
private class ModelWithKeyValuePairProperty
{
public KeyValuePair<string, string> KeyValuePairProperty { get; set; }
}
}
}
#endif

View File

@ -138,7 +138,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("11", entry.Value.RawValue);
}
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task ArrayModelBinder_BindsArrayOfSimpleType_NoData()
{
// Arrange
@ -160,8 +160,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // This fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Empty(Assert.IsType<int[]>(modelBindingResult.Model));
Assert.Equal(0, modelState.Count);
@ -304,7 +304,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("lang", entry.Value.RawValue);
}
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task ArrayModelBinder_BindsArrayOfComplexType_NoData()
{
// Arrange
@ -326,8 +326,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // This fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Empty(Assert.IsType<Person[]>(modelBindingResult.Model));
Assert.Equal(0, modelState.Count);

View File

@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); // Should be skipped. bug#2447
}
[Fact]
[Fact(Skip = "ByteArrayModelBinder should return a non-null result #2456")]
public async Task BindParameter_NoData_DoesNotGetBound()
{
// Arrange
@ -102,11 +102,15 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
// Assert
// ModelBindingResult
Assert.Null(modelBindingResult);
Assert.NotNull(modelBindingResult);
// ModelState
Assert.True(modelState.IsValid);
Assert.Empty(modelState.Keys);
Assert.Equal("CustomParameter", modelBindingResult.Key);
Assert.True(modelBindingResult.IsModelSet);
Assert.Equal(new byte[0], modelBindingResult.Model);
}
[Fact(Skip = "ModelState.Value not set due to #2445")]

View File

@ -145,7 +145,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("11", entry.Value.RawValue);
}
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task CollectionModelBinder_BindsListOfSimpleType_NoData()
{
// Arrange
@ -167,8 +167,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // This fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Empty(Assert.IsType<List<int>>(modelBindingResult.Model));
Assert.Equal(0, modelState.Count);
@ -311,7 +311,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("11", entry.Value.RawValue);
}
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task CollectionModelBinder_BindsListOfComplexType_NoData()
{
// Arrange
@ -333,8 +333,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // This fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Empty(Assert.IsType<List<Person>>(modelBindingResult.Model));
Assert.Equal(0, modelState.Count);
@ -510,7 +510,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal(ModelValidationState.Invalid, entry.ValidationState);
}
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task CollectionModelBinder_BindsListOfComplexType_WithRequiredProperty_NoData()
{
// Arrange
@ -532,8 +532,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // This fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Empty(Assert.IsType<List<Person2>>(modelBindingResult.Model));
Assert.Equal(0, modelState.Count);

View File

@ -140,7 +140,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("10", entry.Value.RawValue);
}
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task DictionaryModelBinder_BindsDictionaryOfSimpleType_NoData()
{
// Arrange
@ -162,8 +162,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // This fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Empty(Assert.IsType<Dictionary<string, int>>(modelBindingResult.Model));
Assert.Equal(0, modelState.Count);
@ -309,7 +309,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("10", entry.Value.RawValue);
}
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task DictionaryModelBinder_BindsDictionaryOfComplexType_NoData()
{
// Arrange
@ -331,8 +331,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // This fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Empty(Assert.IsType<Dictionary<string, Person>>(modelBindingResult.Model));
Assert.Equal(0, modelState.Count);

View File

@ -99,7 +99,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
//
// In this example we choose IFormCollection - because IFormCollection has a dedicated
// model binder.
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task GenericModelBinder_BindsCollection_ElementTypeFromGreedyModelBinder_NoData()
{
// Arrange
@ -122,8 +122,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // This fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<List<IFormCollection>>(modelBindingResult.Model);
Assert.Empty(model);
@ -298,7 +298,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
// This is part of a random sampling of scenarios where a GenericModelBinder is used
// recursively.
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task GenericModelBinder_BindsArrayOfDictionary_NoData()
{
// Arrange
@ -320,8 +320,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // This fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<Dictionary<string, int>[]>(modelBindingResult.Model);
Assert.NotNull(model);
@ -424,7 +424,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
// This is part of a random sampling of scenarios where a GenericModelBinder is used
// recursively.
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task GenericModelBinder_BindsCollectionOfKeyValuePair_NoData()
{
// Arrange
@ -446,8 +446,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // Fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<Collection<KeyValuePair<string, int>>>(modelBindingResult.Model);
Assert.NotNull(model);
@ -559,7 +559,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
// This is part of a random sampling of scenarios where a GenericModelBinder is used
// recursively.
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task GenericModelBinder_BindsDictionaryOfList_NoData()
{
// Arrange
@ -581,8 +581,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // Fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<Dictionary<string, List<int>>>(modelBindingResult.Model);
Assert.NotNull(model);

View File

@ -139,7 +139,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("10", entry.Value.RawValue);
}
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task KeyValuePairModelBinder_BindsKeyValuePairOfSimpleType_NoData()
{
// Arrange
@ -161,10 +161,10 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // This fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Equal(new int[0], modelBindingResult.Model);
Assert.Equal(new KeyValuePair<string, int>(), modelBindingResult.Model);
Assert.Equal(0, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
@ -306,7 +306,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Equal("10", entry.Value.RawValue);
}
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task KeyValuePairModelBinder_BindsKeyValuePairOfComplexType_NoData()
{
// Arrange
@ -328,8 +328,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
// Assert
Assert.NotNull(modelBindingResult); // This fails due to #1579
Assert.False(modelBindingResult.IsModelSet);
Assert.NotNull(modelBindingResult);
Assert.True(modelBindingResult.IsModelSet);
Assert.Equal(new KeyValuePair<string, Person>(), modelBindingResult.Model);

View File

@ -974,7 +974,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
Assert.Null(error.Exception);
}
[Fact(Skip = "Empty collection should be created by the collection model binder #1579")]
[Fact]
public async Task Validation_StringLengthAttribute_OnProperyOfCollectionElement_NoData()
{
// Arrange
@ -997,14 +997,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
// Assert
Assert.NotNull(modelBindingResult);
Assert.False(modelBindingResult.IsModelSet);
Assert.True(modelBindingResult.IsModelSet);
var model = Assert.IsType<List<Order10>>(modelBindingResult.Model);
Assert.Empty(model);
Assert.Equal(0, modelState.Count);
Assert.Equal(0, modelState.ErrorCount);
Assert.False(modelState.IsValid);
Assert.True(modelState.IsValid);
}
private class Order11