/test/System.Web.Mvc.Test/Test/DefaultModelBinderTest.cs
C# | 1202 lines | 914 code | 176 blank | 112 comment | 0 complexity | 126d762d8d0bfe7c00726505144abf06 MD5 | raw file
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.ComponentModel.DataAnnotations;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using Microsoft.Web.UnitTestUtil;
- using Moq;
- using Moq.Protected;
- using Xunit;
- using Assert = Microsoft.TestCommon.AssertEx;
- namespace System.Web.Mvc.Test
- {
- [CLSCompliant(false)]
- public class DefaultModelBinderTest
- {
- [Fact]
- public void BindComplexElementalModelReturnsIfOnModelUpdatingReturnsFalse()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- MyModel model = new MyModel() { ReadWriteProperty = 3 };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- };
- Mock<DefaultModelBinderHelper> mockHelper = new Mock<DefaultModelBinderHelper>() { CallBase = true };
- mockHelper.Setup(b => b.PublicOnModelUpdating(controllerContext, It.IsAny<ModelBindingContext>())).Returns(false);
- DefaultModelBinderHelper helper = mockHelper.Object;
- // Act
- helper.BindComplexElementalModel(controllerContext, bindingContext, model);
- // Assert
- Assert.Equal(3, model.ReadWriteProperty);
- mockHelper.Verify();
- mockHelper.Verify(b => b.PublicGetModelProperties(controllerContext, It.IsAny<ModelBindingContext>()), Times.Never());
- mockHelper.Verify(b => b.PublicBindProperty(controllerContext, It.IsAny<ModelBindingContext>(), It.IsAny<PropertyDescriptor>()), Times.Never());
- }
- [Fact]
- public void BindComplexModelCanBindArrays()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(int[])),
- ModelName = "foo",
- PropertyFilter = _ => false,
- ValueProvider = new SimpleValueProvider()
- {
- { "foo[0]", null },
- { "foo[1]", null },
- { "foo[2]", null }
- }
- };
- Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
- mockInnerBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc)
- {
- Assert.Equal(controllerContext, cc);
- Assert.Equal(typeof(int), bc.ModelType);
- Assert.Equal(bindingContext.ModelState, bc.ModelState);
- Assert.Equal(bindingContext.PropertyFilter, bc.PropertyFilter);
- Assert.Equal(bindingContext.ValueProvider, bc.ValueProvider);
- return Int32.Parse(bc.ModelName.Substring(4, 1), CultureInfo.InvariantCulture);
- });
- DefaultModelBinder binder = new DefaultModelBinder()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(int), mockInnerBinder.Object }
- }
- };
- // Act
- object newModel = binder.BindComplexModel(controllerContext, bindingContext);
- // Assert
- var newIntArray = Assert.IsType<int[]>(newModel);
- Assert.Equal(new[] { 0, 1, 2 }, newIntArray);
- }
- [Fact]
- public void BindComplexModelCanBindCollections()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(IList<int>)),
- ModelName = "foo",
- PropertyFilter = _ => false,
- ValueProvider = new SimpleValueProvider()
- {
- { "foo[0]", null },
- { "foo[1]", null },
- { "foo[2]", null }
- }
- };
- Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
- mockInnerBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc)
- {
- Assert.Equal(controllerContext, cc);
- Assert.Equal(typeof(int), bc.ModelType);
- Assert.Equal(bindingContext.ModelState, bc.ModelState);
- Assert.Equal(bindingContext.PropertyFilter, bc.PropertyFilter);
- Assert.Equal(bindingContext.ValueProvider, bc.ValueProvider);
- return Int32.Parse(bc.ModelName.Substring(4, 1), CultureInfo.InvariantCulture);
- });
- DefaultModelBinder binder = new DefaultModelBinder()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(int), mockInnerBinder.Object }
- }
- };
- // Act
- object newModel = binder.BindComplexModel(controllerContext, bindingContext);
- // Assert
- var modelAsList = Assert.IsAssignableFrom<IList<int>>(newModel);
- Assert.Equal(new[] { 0, 1, 2 }, modelAsList.ToArray());
- }
- [Fact]
- public void BindComplexModelCanBindDictionariesWithDotsNotation()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(IDictionary<string, CountryState>)),
- ModelName = "countries",
- PropertyFilter = _ => true,
- ValueProvider = new DictionaryValueProvider<object>(new Dictionary<string, object>()
- {
- { "countries.CA.Name", "Canada" },
- { "countries.CA.States[0]", "Québec" },
- { "countries.CA.States[1]", "British Columbia" },
- { "countries.US.Name", "United States" },
- { "countries.US.States[0]", "Washington" },
- { "countries.US.States[1]", "Oregon" }
- }, CultureInfo.CurrentCulture)
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object newModel = binder.BindComplexModel(controllerContext, bindingContext);
- // Assert
- var modelAsDictionary = Assert.IsAssignableFrom<IDictionary<string, CountryState>>(newModel);
- Assert.Equal(2, modelAsDictionary.Count);
- Assert.Equal("Canada", modelAsDictionary["CA"].Name);
- Assert.Equal("United States", modelAsDictionary["US"].Name);
- Assert.Equal(2, modelAsDictionary["CA"].States.Count());
- Assert.True(modelAsDictionary["CA"].States.Contains("Québec"));
- Assert.True(modelAsDictionary["CA"].States.Contains("British Columbia"));
- Assert.Equal(2, modelAsDictionary["US"].States.Count());
- Assert.True(modelAsDictionary["US"].States.Contains("Washington"));
- Assert.True(modelAsDictionary["US"].States.Contains("Oregon"));
- }
- [Fact]
- public void BindComplexModelCanBindDictionariesWithBracketsNotation()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(IDictionary<string, CountryState>)),
- ModelName = "countries",
- PropertyFilter = _ => true,
- ValueProvider = new DictionaryValueProvider<object>(new Dictionary<string, object>()
- {
- { "countries[CA].Name", "Canada" },
- { "countries[CA].States[0]", "Québec" },
- { "countries[CA].States[1]", "British Columbia" },
- { "countries[US].Name", "United States" },
- { "countries[US].States[0]", "Washington" },
- { "countries[US].States[1]", "Oregon" }
- }, CultureInfo.CurrentCulture)
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object newModel = binder.BindComplexModel(controllerContext, bindingContext);
- // Assert
- var modelAsDictionary = Assert.IsAssignableFrom<IDictionary<string, CountryState>>(newModel);
- Assert.Equal(2, modelAsDictionary.Count);
- Assert.Equal("Canada", modelAsDictionary["CA"].Name);
- Assert.Equal("United States", modelAsDictionary["US"].Name);
- Assert.Equal(2, modelAsDictionary["CA"].States.Count());
- Assert.True(modelAsDictionary["CA"].States.Contains("Québec"));
- Assert.True(modelAsDictionary["CA"].States.Contains("British Columbia"));
- Assert.Equal(2, modelAsDictionary["US"].States.Count());
- Assert.True(modelAsDictionary["US"].States.Contains("Washington"));
- Assert.True(modelAsDictionary["US"].States.Contains("Oregon"));
- }
- [Fact]
- public void BindComplexModelCanBindDictionariesWithBracketsAndDotsNotation()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(IDictionary<string, CountryState>)),
- ModelName = "countries",
- PropertyFilter = _ => true,
- ValueProvider = new DictionaryValueProvider<object>(new Dictionary<string, object>()
- {
- { "countries[CA].Name", "Canada" },
- { "countries[CA].States[0]", "Québec" },
- { "countries.CA.States[1]", "British Columbia" },
- { "countries.US.Name", "United States" },
- { "countries.US.States[0]", "Washington" },
- { "countries.US.States[1]", "Oregon" }
- }, CultureInfo.CurrentCulture)
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object newModel = binder.BindComplexModel(controllerContext, bindingContext);
- // Assert
- var modelAsDictionary = Assert.IsAssignableFrom<IDictionary<string, CountryState>>(newModel);
- Assert.Equal(2, modelAsDictionary.Count);
- Assert.Equal("Canada", modelAsDictionary["CA"].Name);
- Assert.Equal("United States", modelAsDictionary["US"].Name);
- Assert.Equal(1, modelAsDictionary["CA"].States.Count());
- Assert.True(modelAsDictionary["CA"].States.Contains("Québec"));
- // We do not accept double notation for a same entry, so we can't find that state.
- Assert.False(modelAsDictionary["CA"].States.Contains("British Columbia"));
- Assert.Equal(2, modelAsDictionary["US"].States.Count());
- Assert.True(modelAsDictionary["US"].States.Contains("Washington"));
- Assert.True(modelAsDictionary["US"].States.Contains("Oregon"));
- }
- [Fact]
- public void BindComplexModelCanBindDictionaries()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(IDictionary<int, string>)),
- ModelName = "foo",
- PropertyFilter = _ => false,
- ValueProvider = new SimpleValueProvider()
- {
- { "foo[0].key", null }, { "foo[0].value", null },
- { "foo[1].key", null }, { "foo[1].value", null },
- { "foo[2].key", null }, { "foo[2].value", null }
- }
- };
- Mock<IModelBinder> mockIntBinder = new Mock<IModelBinder>();
- mockIntBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc)
- {
- Assert.Equal(controllerContext, cc);
- Assert.Equal(typeof(int), bc.ModelType);
- Assert.Equal(bindingContext.ModelState, bc.ModelState);
- Assert.Equal(new ModelBindingContext().PropertyFilter, bc.PropertyFilter);
- Assert.Equal(bindingContext.ValueProvider, bc.ValueProvider);
- return Int32.Parse(bc.ModelName.Substring(4, 1), CultureInfo.InvariantCulture) + 10;
- });
- Mock<IModelBinder> mockStringBinder = new Mock<IModelBinder>();
- mockStringBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc)
- {
- Assert.Equal(controllerContext, cc);
- Assert.Equal(typeof(string), bc.ModelType);
- Assert.Equal(bindingContext.ModelState, bc.ModelState);
- Assert.Equal(bindingContext.PropertyFilter, bc.PropertyFilter);
- Assert.Equal(bindingContext.ValueProvider, bc.ValueProvider);
- return (Int32.Parse(bc.ModelName.Substring(4, 1), CultureInfo.InvariantCulture) + 10) + "Value";
- });
- DefaultModelBinder binder = new DefaultModelBinder()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(int), mockIntBinder.Object },
- { typeof(string), mockStringBinder.Object }
- }
- };
- // Act
- object newModel = binder.BindComplexModel(controllerContext, bindingContext);
- // Assert
- var modelAsDictionary = Assert.IsAssignableFrom<IDictionary<int, string>>(newModel);
- Assert.Equal(3, modelAsDictionary.Count);
- Assert.Equal("10Value", modelAsDictionary[10]);
- Assert.Equal("11Value", modelAsDictionary[11]);
- Assert.Equal("12Value", modelAsDictionary[12]);
- }
- [Fact]
- public void BindComplexModelCanBindObjects()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- ModelWithoutBindAttribute model = new ModelWithoutBindAttribute()
- {
- Foo = "FooPreValue",
- Bar = "BarPreValue",
- Baz = "BazPreValue",
- };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ValueProvider = new SimpleValueProvider() { { "Foo", null }, { "Bar", null } }
- };
- Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
- mockInnerBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc)
- {
- Assert.Equal(controllerContext, cc);
- Assert.Equal(bindingContext.ValueProvider, bc.ValueProvider);
- return bc.ModelName + "PostValue";
- });
- DefaultModelBinder binder = new DefaultModelBinder()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(string), mockInnerBinder.Object }
- }
- };
- // Act
- object updatedModel = binder.BindComplexModel(controllerContext, bindingContext);
- // Assert
- Assert.Same(model, updatedModel);
- Assert.Equal("FooPostValue", model.Foo);
- Assert.Equal("BarPostValue", model.Bar);
- Assert.Equal("BazPreValue", model.Baz);
- }
- [Fact]
- public void BindComplexModelReturnsNullArrayIfNoValuesProvided()
- {
- // Arrange
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(int[])),
- ModelName = "foo",
- ValueProvider = new SimpleValueProvider() { { "foo", null } }
- };
- Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
- mockInnerBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc) { return Int32.Parse(bc.ModelName.Substring(4, 1), CultureInfo.InvariantCulture); });
- DefaultModelBinder binder = new DefaultModelBinder()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(int), mockInnerBinder.Object }
- }
- };
- // Act
- object newModel = binder.BindComplexModel(null, bindingContext);
- // Assert
- Assert.Null(newModel);
- }
- [Fact]
- public void BindComplexModelWhereModelTypeContainsBindAttribute()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- ModelWithBindAttribute model = new ModelWithBindAttribute()
- {
- Foo = "FooPreValue",
- Bar = "BarPreValue",
- Baz = "BazPreValue",
- };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ValueProvider = new SimpleValueProvider() { { "Foo", null }, { "Bar", null } }
- };
- Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
- mockInnerBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc)
- {
- Assert.Equal(controllerContext, cc);
- Assert.Equal(bindingContext.ValueProvider, bc.ValueProvider);
- return bc.ModelName + "PostValue";
- });
- DefaultModelBinder binder = new DefaultModelBinder()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(string), mockInnerBinder.Object }
- }
- };
- // Act
- binder.BindComplexModel(controllerContext, bindingContext);
- // Assert
- Assert.Equal("FooPreValue", model.Foo);
- Assert.Equal("BarPostValue", model.Bar);
- Assert.Equal("BazPreValue", model.Baz);
- }
- [Fact]
- public void BindComplexModelWhereModelTypeDoesNotContainBindAttribute()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- ModelWithoutBindAttribute model = new ModelWithoutBindAttribute()
- {
- Foo = "FooPreValue",
- Bar = "BarPreValue",
- Baz = "BazPreValue",
- };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ValueProvider = new SimpleValueProvider() { { "Foo", null }, { "Bar", null } }
- };
- Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
- mockInnerBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc)
- {
- Assert.Equal(controllerContext, cc);
- Assert.Equal(bindingContext.ValueProvider, bc.ValueProvider);
- return bc.ModelName + "PostValue";
- });
- DefaultModelBinder binder = new DefaultModelBinder()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(string), mockInnerBinder.Object }
- }
- };
- // Act
- binder.BindComplexModel(controllerContext, bindingContext);
- // Assert
- Assert.Equal("FooPostValue", model.Foo);
- Assert.Equal("BarPostValue", model.Bar);
- Assert.Equal("BazPreValue", model.Baz);
- }
- // BindModel tests
- [Fact]
- public void BindModelCanBindObjects()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- ModelWithoutBindAttribute model = new ModelWithoutBindAttribute()
- {
- Foo = "FooPreValue",
- Bar = "BarPreValue",
- Baz = "BazPreValue",
- };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ValueProvider = new SimpleValueProvider() { { "Foo", null }, { "Bar", null } }
- };
- Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
- mockInnerBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc)
- {
- Assert.Equal(controllerContext, cc);
- Assert.Equal(bindingContext.ValueProvider, bc.ValueProvider);
- return bc.ModelName + "PostValue";
- });
- DefaultModelBinder binder = new DefaultModelBinder()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(string), mockInnerBinder.Object }
- }
- };
- // Act
- object updatedModel = binder.BindModel(controllerContext, bindingContext);
- // Assert
- Assert.Same(model, updatedModel);
- Assert.Equal("FooPostValue", model.Foo);
- Assert.Equal("BarPostValue", model.Bar);
- Assert.Equal("BazPreValue", model.Baz);
- }
- [Fact]
- public void BindModelCanBindSimpleTypes()
- {
- // Arrange
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(int)),
- ModelName = "foo",
- ValueProvider = new SimpleValueProvider()
- {
- { "foo", "42" }
- }
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object updatedModel = binder.BindModel(new ControllerContext(), bindingContext);
- // Assert
- Assert.Equal(42, updatedModel);
- }
- [Fact]
- public void BindModel_PerformsValidationByDefault()
- {
- // Arrange
- ModelMetadata metadata = new DataAnnotationsModelMetadataProvider().GetMetadataForType(null, typeof(string));
- ControllerContext controllerContext = new ControllerContext();
- controllerContext.Controller = new SimpleController();
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = metadata,
- ModelName = "foo",
- ValueProvider = new CustomUnvalidatedValueProvider()
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object updatedModel = binder.BindModel(controllerContext, bindingContext);
- // Assert
- Assert.Equal("fooValidated", updatedModel);
- }
- [Fact]
- public void BindModel_SkipsValidationIfControllerOptsOut()
- {
- // Arrange
- ModelMetadata metadata = new DataAnnotationsModelMetadataProvider().GetMetadataForType(null, typeof(string));
- ControllerContext controllerContext = new ControllerContext();
- controllerContext.Controller = new SimpleController();
- controllerContext.Controller.ValidateRequest = false;
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = metadata,
- ModelName = "foo",
- ValueProvider = new CustomUnvalidatedValueProvider()
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object updatedModel = binder.BindModel(controllerContext, bindingContext);
- // Assert
- Assert.Equal("fooUnvalidated", updatedModel);
- }
- [Fact]
- public void BindModel_SkipsValidationIfModelOptsOut()
- {
- // Arrange
- ModelMetadata metadata = new DataAnnotationsModelMetadataProvider().GetMetadataForType(null, typeof(string));
- metadata.RequestValidationEnabled = false;
- ControllerContext controllerContext = new ControllerContext();
- controllerContext.Controller = new SimpleController();
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = metadata,
- ModelName = "foo",
- ValueProvider = new CustomUnvalidatedValueProvider()
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object updatedModel = binder.BindModel(controllerContext, bindingContext);
- // Assert
- Assert.Equal("fooUnvalidated", updatedModel);
- }
- [Fact]
- public void BindModelReturnsNullIfKeyNotFound()
- {
- // Arrange
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(int)),
- ModelName = "foo",
- ValueProvider = new SimpleValueProvider()
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object returnedModel = binder.BindModel(new ControllerContext(), bindingContext);
- // Assert
- Assert.Null(returnedModel);
- }
- [Fact]
- public void BindModelThrowsIfBindingContextIsNull()
- {
- // Arrange
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act & assert
- Assert.ThrowsArgumentNull(
- delegate { binder.BindModel(new ControllerContext(), null); }, "bindingContext");
- }
- [Fact]
- public void BindModelValuesCanBeOverridden()
- {
- // Arrange
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => new ModelWithoutBindAttribute(), typeof(ModelWithoutBindAttribute)),
- ModelName = "",
- ValueProvider = new SimpleValueProvider()
- {
- { "foo", "FooPostValue" },
- { "bar", "BarPostValue" },
- { "baz", "BazPostValue" }
- }
- };
- Mock<DefaultModelBinder> binder = new Mock<DefaultModelBinder> { CallBase = true };
- binder.Protected().Setup<object>("GetPropertyValue",
- ItExpr.IsAny<ControllerContext>(), ItExpr.IsAny<ModelBindingContext>(),
- ItExpr.IsAny<PropertyDescriptor>(), ItExpr.IsAny<IModelBinder>())
- .Returns("Hello, world!");
- // Act
- ModelWithoutBindAttribute model = (ModelWithoutBindAttribute)binder.Object.BindModel(new ControllerContext(), bindingContext);
- // Assert
- Assert.Equal("Hello, world!", model.Bar);
- Assert.Equal("Hello, world!", model.Baz);
- Assert.Equal("Hello, world!", model.Foo);
- }
- [Fact]
- public void BindModelWithTypeConversionErrorUpdatesModelStateMessage()
- {
- // Arrange
- ModelBindingContext bindingContext = new ModelBindingContext
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => new PropertyTestingModel(), typeof(PropertyTestingModel)),
- ModelName = "",
- ValueProvider = new SimpleValueProvider()
- {
- { "IntReadWrite", "foo" }
- },
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- PropertyTestingModel model = (PropertyTestingModel)binder.BindModel(new ControllerContext(), bindingContext);
- // Assert
- ModelState modelState = bindingContext.ModelState["IntReadWrite"];
- Assert.NotNull(modelState);
- Assert.Single(modelState.Errors);
- Assert.Equal("The value 'foo' is not valid for IntReadWrite.", modelState.Errors[0].ErrorMessage);
- }
- [Fact]
- public void BindModelWithPrefix()
- {
- // Arrange
- ModelWithoutBindAttribute model = new ModelWithoutBindAttribute()
- {
- Foo = "FooPreValue",
- Bar = "BarPreValue",
- Baz = "BazPreValue",
- };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ModelName = "prefix",
- ValueProvider = new SimpleValueProvider()
- {
- { "prefix.foo", "FooPostValue" },
- { "prefix.bar", "BarPostValue" }
- }
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object updatedModel = binder.BindModel(new ControllerContext(), bindingContext);
- // Assert
- Assert.Same(model, updatedModel);
- Assert.Equal("FooPostValue", model.Foo);
- Assert.Equal("BarPostValue", model.Bar);
- Assert.Equal("BazPreValue", model.Baz);
- }
- [Fact]
- public void BindModelWithPrefixAndFallback()
- {
- // Arrange
- ModelWithoutBindAttribute model = new ModelWithoutBindAttribute()
- {
- Foo = "FooPreValue",
- Bar = "BarPreValue",
- Baz = "BazPreValue",
- };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- FallbackToEmptyPrefix = true,
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ModelName = "prefix",
- ValueProvider = new SimpleValueProvider()
- {
- { "foo", "FooPostValue" },
- { "bar", "BarPostValue" }
- }
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object updatedModel = binder.BindModel(new ControllerContext(), bindingContext);
- // Assert
- Assert.Same(model, updatedModel);
- Assert.Equal("FooPostValue", model.Foo);
- Assert.Equal("BarPostValue", model.Bar);
- Assert.Equal("BazPreValue", model.Baz);
- }
- [Fact]
- public void BindModelWithPrefixReturnsNullIfFallbackNotSpecifiedAndValueProviderContainsNoEntries()
- {
- // Arrange
- ModelWithoutBindAttribute model = new ModelWithoutBindAttribute()
- {
- Foo = "FooPreValue",
- Bar = "BarPreValue",
- Baz = "BazPreValue",
- };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ModelName = "prefix",
- ValueProvider = new SimpleValueProvider()
- {
- { "foo", "FooPostValue" },
- { "bar", "BarPostValue" }
- }
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object updatedModel = binder.BindModel(new ControllerContext(), bindingContext);
- // Assert
- Assert.Null(updatedModel);
- }
- [Fact]
- public void BindModelReturnsNullIfSimpleTypeNotFound()
- {
- // DevDiv 216165: ModelBinders should not try and instantiate simple types
- // Arrange
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(string)),
- ModelName = "prefix",
- ValueProvider = new SimpleValueProvider()
- {
- { "prefix.foo", "foo" },
- { "prefix.bar", "bar" }
- }
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object updatedModel = binder.BindModel(new ControllerContext(), bindingContext);
- // Assert
- Assert.Null(updatedModel);
- }
- // BindProperty tests
- [Fact]
- public void BindPropertyCanUpdateComplexReadOnlyProperties()
- {
- // Arrange
- // the Customer type contains a single read-only Address property
- Customer model = new Customer();
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ValueProvider = new SimpleValueProvider() { { "Address", null } }
- };
- Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
- mockInnerBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc)
- {
- Address address = (Address)bc.Model;
- address.Street = "1 Microsoft Way";
- address.Zip = "98052";
- return address;
- });
- PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["Address"];
- DefaultModelBinderHelper helper = new DefaultModelBinderHelper()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(Address), mockInnerBinder.Object }
- }
- };
- // Act
- helper.PublicBindProperty(new ControllerContext(), bindingContext, pd);
- // Assert
- Assert.Equal("1 Microsoft Way", model.Address.Street);
- Assert.Equal("98052", model.Address.Zip);
- }
- [Fact]
- public void BindPropertyDoesNothingIfValueProviderContainsNoEntryForProperty()
- {
- // Arrange
- MyModel2 model = new MyModel2() { IntReadWrite = 3 };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ValueProvider = new SimpleValueProvider()
- };
- PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["IntReadWrite"];
- DefaultModelBinderHelper helper = new DefaultModelBinderHelper();
- // Act
- helper.PublicBindProperty(new ControllerContext(), bindingContext, pd);
- // Assert
- Assert.Equal(3, model.IntReadWrite);
- }
- [Fact]
- public void BindProperty()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- MyModel2 model = new MyModel2() { IntReadWrite = 3 };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ValueProvider = new SimpleValueProvider()
- {
- { "IntReadWrite", "42" }
- }
- };
- PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["IntReadWrite"];
- Mock<DefaultModelBinderHelper> mockHelper = new Mock<DefaultModelBinderHelper>() { CallBase = true };
- mockHelper.Setup(b => b.PublicOnPropertyValidating(controllerContext, bindingContext, pd, 42)).Returns(true).Verifiable();
- mockHelper.Setup(b => b.PublicSetProperty(controllerContext, bindingContext, pd, 42)).Verifiable();
- mockHelper.Setup(b => b.PublicOnPropertyValidated(controllerContext, bindingContext, pd, 42)).Verifiable();
- DefaultModelBinderHelper helper = mockHelper.Object;
- // Act
- helper.PublicBindProperty(controllerContext, bindingContext, pd);
- // Assert
- mockHelper.Verify();
- }
- [Fact]
- public void BindPropertyReturnsIfOnPropertyValidatingReturnsFalse()
- {
- // Arrange
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- MyModel2 model = new MyModel2() { IntReadWrite = 3 };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ValueProvider = new SimpleValueProvider()
- {
- { "IntReadWrite", "42" }
- }
- };
- PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["IntReadWrite"];
- Mock<DefaultModelBinderHelper> mockHelper = new Mock<DefaultModelBinderHelper>() { CallBase = true };
- mockHelper.Setup(b => b.PublicOnPropertyValidating(controllerContext, bindingContext, pd, 42)).Returns(false);
- DefaultModelBinderHelper helper = mockHelper.Object;
- // Act
- helper.PublicBindProperty(controllerContext, bindingContext, pd);
- // Assert
- Assert.Equal(3, model.IntReadWrite);
- mockHelper.Verify();
- mockHelper.Verify(b => b.PublicSetProperty(controllerContext, bindingContext, pd, 42), Times.Never());
- mockHelper.Verify(b => b.PublicOnPropertyValidated(controllerContext, bindingContext, pd, 42), Times.Never());
- }
- [Fact]
- public void BindPropertySetsPropertyToNullIfUserLeftTextEntryFieldBlankForOptionalValue()
- {
- // Arrange
- MyModel2 model = new MyModel2() { NullableIntReadWrite = 8 };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ValueProvider = new SimpleValueProvider() { { "NullableIntReadWrite", null } }
- };
- Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
- mockInnerBinder.Setup(b => b.BindModel(new ControllerContext(), It.IsAny<ModelBindingContext>())).Returns((object)null);
- PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["NullableIntReadWrite"];
- DefaultModelBinderHelper helper = new DefaultModelBinderHelper()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(int?), mockInnerBinder.Object }
- }
- };
- // Act
- helper.PublicBindProperty(new ControllerContext(), bindingContext, pd);
- // Assert
- Assert.Empty(bindingContext.ModelState);
- Assert.Null(model.NullableIntReadWrite);
- }
- [Fact]
- public void BindPropertyUpdatesPropertyOnFailureIfInnerBinderReturnsNonNullObject()
- {
- // Arrange
- MyModel2 model = new MyModel2() { IntReadWriteNonNegative = 8 };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ValueProvider = new SimpleValueProvider() { { "IntReadWriteNonNegative", null } }
- };
- Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
- mockInnerBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc)
- {
- bc.ModelState.AddModelError("IntReadWriteNonNegative", "Some error text.");
- return 4;
- });
- PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["IntReadWriteNonNegative"];
- DefaultModelBinderHelper helper = new DefaultModelBinderHelper()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(int), mockInnerBinder.Object }
- }
- };
- // Act
- helper.PublicBindProperty(new ControllerContext(), bindingContext, pd);
- // Assert
- Assert.Equal(false, bindingContext.ModelState.IsValidField("IntReadWriteNonNegative"));
- var error = Assert.Single(bindingContext.ModelState["IntReadWriteNonNegative"].Errors);
- Assert.Equal("Some error text.", error.ErrorMessage);
- Assert.Equal(4, model.IntReadWriteNonNegative);
- }
- [Fact]
- public void BindPropertyUpdatesPropertyOnSuccess()
- {
- // Arrange
- // Effectively, this is just testing updating a single property named "IntReadWrite"
- ControllerContext controllerContext = new Mock<ControllerContext>().Object;
- MyModel2 model = new MyModel2() { IntReadWrite = 3 };
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
- ModelName = "foo",
- ModelState = new ModelStateDictionary() { { "blah", new ModelState() } },
- ValueProvider = new SimpleValueProvider() { { "foo.IntReadWrite", null } }
- };
- Mock<IModelBinder> mockInnerBinder = new Mock<IModelBinder>();
- mockInnerBinder
- .Setup(b => b.BindModel(It.IsAny<ControllerContext>(), It.IsAny<ModelBindingContext>()))
- .Returns(
- delegate(ControllerContext cc, ModelBindingContext bc)
- {
- Assert.Equal(controllerContext, cc);
- Assert.Equal(3, bc.Model);
- Assert.Equal(typeof(int), bc.ModelType);
- Assert.Equal("foo.IntReadWrite", bc.ModelName);
- Assert.Equal(new ModelBindingContext().PropertyFilter, bc.PropertyFilter);
- Assert.Equal(bindingContext.ModelState, bc.ModelState);
- Assert.Equal(bindingContext.ValueProvider, bc.ValueProvider);
- return 4;
- });
- PropertyDescriptor pd = TypeDescriptor.GetProperties(model)["IntReadWrite"];
- DefaultModelBinderHelper helper = new DefaultModelBinderHelper()
- {
- Binders = new ModelBinderDictionary()
- {
- { typeof(int), mockInnerBinder.Object }
- }
- };
- // Act
- helper.PublicBindProperty(controllerContext, bindingContext, pd);
- // Assert
- Assert.Equal(4, model.IntReadWrite);
- }
- // BindSimpleModel tests
- [Fact]
- public void BindSimpleModelCanReturnArrayTypes()
- {
- // Arrange
- ValueProviderResult result = new ValueProviderResult(42, null, null);
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(int[])),
- ModelName = "foo",
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object returnedValue = binder.BindSimpleModel(null, bindingContext, result);
- // Assert
- var returnedValueAsIntArray = Assert.IsType<int[]>(returnedValue);
- Assert.Single(returnedValueAsIntArray);
- Assert.Equal(42, returnedValueAsIntArray[0]);
- }
- [Fact]
- public void BindSimpleModelCanReturnCollectionTypes()
- {
- // Arrange
- ValueProviderResult result = new ValueProviderResult(new string[] { "42", "82" }, null, null);
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(IEnumerable<int>)),
- ModelName = "foo",
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object returnedValue = binder.BindSimpleModel(null, bindingContext, result);
- // Assert
- var returnedValueAsList = Assert.IsAssignableFrom<IEnumerable<int>>(returnedValue).ToList();
- Assert.Equal(2, returnedValueAsList.Count);
- Assert.Equal(42, returnedValueAsList[0]);
- Assert.Equal(82, returnedValueAsList[1]);
- }
- [Fact]
- public void BindSimpleModelCanReturnElementalTypes()
- {
- // Arrange
- ValueProviderResult result = new ValueProviderResult("42", null, null);
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(int)),
- ModelName = "foo",
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object returnedValue = binder.BindSimpleModel(null, bindingContext, result);
- // Assert
- Assert.Equal(42, returnedValue);
- }
- [Fact]
- public void BindSimpleModelCanReturnStrings()
- {
- // Arrange
- ValueProviderResult result = new ValueProviderResult(new object[] { "42" }, null, null);
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(string)),
- ModelName = "foo",
- };
- DefaultModelBinder binder = new DefaultModelBinder();
- // Act
- object returnedValue = binder.BindSimpleModel(null, bindingContext, result);
- // Assert
- Assert.Equal("42", returnedValue);
- }
- [Fact]
- public void BindSimpleModelChecksValueProviderResultRawValueType()
- {
- // Arrange
- ValueProviderResult result = new ValueProviderResult(new MemoryStream(), null, null);
- ModelBindingContext bindingContext = new ModelBindingContext()
- {
- ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(Stream)),
- ModelName = "foo",
- };
- DefaultModelBinder