diff --git a/src/Microsoft.AspNet.Mvc.Core/Controller.cs b/src/Microsoft.AspNet.Mvc.Core/Controller.cs
index 79c2e8b36e..5fe319e4cb 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Controller.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Controller.cs
@@ -1104,6 +1104,82 @@ namespace Microsoft.AspNet.Mvc
predicate);
}
+ ///
+ /// Updates the specified instance using values from the controller's current
+ /// and a .
+ ///
+ /// The model instance to update.
+ /// The type of model instance to update.
+ /// The prefix to use when looking up values in the current
+ ///
+ /// A that on completion returns true if the update is successful
+ [NonAction]
+ public virtual async Task TryUpdateModelAsync([NotNull] object model,
+ [NotNull] Type modelType,
+ string prefix)
+ {
+ if (BindingContext == null)
+ {
+ var message = Resources.FormatPropertyOfTypeCannotBeNull(
+ nameof(BindingContext),
+ typeof(Controller).FullName);
+ throw new InvalidOperationException(message);
+ }
+
+ return await ModelBindingHelper.TryUpdateModelAsync(
+ model,
+ modelType,
+ prefix,
+ ActionContext.HttpContext,
+ ModelState,
+ MetadataProvider,
+ BindingContext.ModelBinder,
+ BindingContext.ValueProvider,
+ ObjectValidator,
+ BindingContext.ValidatorProvider);
+ }
+
+ ///
+ /// Updates the specified instance using the and a
+ /// .
+ ///
+ /// The model instance to update.
+ /// The type of model instance to update.
+ /// The prefix to use when looking up values in the
+ ///
+ /// The used for looking up values.
+ /// A predicate which can be used to filter properties at runtime.
+ /// A that on completion returns true if the update is successful
+ [NonAction]
+ public async Task TryUpdateModelAsync(
+ [NotNull] object model,
+ [NotNull] Type modelType,
+ string prefix,
+ [NotNull] IValueProvider valueProvider,
+ [NotNull] Func predicate)
+ {
+ if (BindingContext == null)
+ {
+ var message = Resources.FormatPropertyOfTypeCannotBeNull(
+ nameof(BindingContext),
+ typeof(Controller).FullName);
+ throw new InvalidOperationException(message);
+ }
+
+ return await ModelBindingHelper.TryUpdateModelAsync(
+ model,
+ modelType,
+ prefix,
+ ActionContext.HttpContext,
+ ModelState,
+ MetadataProvider,
+ BindingContext.ModelBinder,
+ valueProvider,
+ ObjectValidator,
+ BindingContext.ValidatorProvider,
+ predicate);
+ }
+
///
/// Validates the specified instance.
///
diff --git a/src/Microsoft.AspNet.Mvc.Core/ParameterBinding/ModelBindingHelper.cs b/src/Microsoft.AspNet.Mvc.Core/ParameterBinding/ModelBindingHelper.cs
index 91b0ee26b5..c7b7a92caf 100644
--- a/src/Microsoft.AspNet.Mvc.Core/ParameterBinding/ModelBindingHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/ParameterBinding/ModelBindingHelper.cs
@@ -128,14 +128,14 @@ namespace Microsoft.AspNet.Mvc
/// The provider used for reading metadata for the model type.
/// The used for binding.
/// The used for looking up values.
- /// /// The used for validating the
+ /// The used for validating the
/// bound values.
/// The used for executing validation
/// on the model instance.
/// A predicate which can be used to
/// filter properties(for inclusion/exclusion) at runtime.
/// A that on completion returns true if the update is successful
- public static async Task TryUpdateModelAsync(
+ public static Task TryUpdateModelAsync(
[NotNull] TModel model,
[NotNull] string prefix,
[NotNull] HttpContext httpContext,
@@ -148,9 +148,113 @@ namespace Microsoft.AspNet.Mvc
[NotNull] Func predicate)
where TModel : class
{
+ return TryUpdateModelAsync(
+ model,
+ typeof(TModel),
+ prefix,
+ httpContext,
+ modelState,
+ metadataProvider,
+ modelBinder,
+ valueProvider,
+ objectModelValidator,
+ validatorProvider,
+ predicate: predicate);
+ }
+
+ ///
+ /// Updates the specified instance using the specified
+ /// and the specified and executes validation using the specified
+ /// .
+ ///
+ /// The model instance to update and validate.
+ /// The type of model instance to update and validate.
+ /// The prefix to use when looking up values in the .
+ ///
+ /// The for the current executing request.
+ /// The used for maintaining state and
+ /// results of model-binding validation.
+ /// The provider used for reading metadata for the model type.
+ /// The used for binding.
+ /// The used for looking up values.
+ /// The used for validating the
+ /// bound values.
+ /// The used for executing validation
+ /// on the model instance.
+ /// A that on completion returns true if the update is successful
+ public static Task TryUpdateModelAsync(
+ [NotNull] object model,
+ [NotNull] Type modelType,
+ [NotNull] string prefix,
+ [NotNull] HttpContext httpContext,
+ [NotNull] ModelStateDictionary modelState,
+ [NotNull] IModelMetadataProvider metadataProvider,
+ [NotNull] IModelBinder modelBinder,
+ [NotNull] IValueProvider valueProvider,
+ [NotNull] IObjectModelValidator objectModelValidator,
+ [NotNull] IModelValidatorProvider validatorProvider)
+ {
+ // Includes everything by default.
+ return TryUpdateModelAsync(
+ model,
+ modelType,
+ prefix,
+ httpContext,
+ modelState,
+ metadataProvider,
+ modelBinder,
+ valueProvider,
+ objectModelValidator,
+ validatorProvider,
+ predicate: (context, propertyName) => true);
+ }
+
+ ///
+ /// Updates the specified instance using the specified
+ /// and the specified and executes validation using the specified
+ /// .
+ ///
+ /// The model instance to update and validate.
+ /// The type of model instance to update and validate.
+ /// The prefix to use when looking up values in the .
+ ///
+ /// The for the current executing request.
+ /// The used for maintaining state and
+ /// results of model-binding validation.
+ /// The provider used for reading metadata for the model type.
+ /// The used for binding.
+ /// The used for looking up values.
+ /// The used for validating the
+ /// bound values.
+ /// The used for executing validation
+ /// on the model instance.
+ /// A predicate which can be used to
+ /// filter properties(for inclusion/exclusion) at runtime.
+ /// A that on completion returns true if the update is successful
+ public static async Task TryUpdateModelAsync(
+ [NotNull] object model,
+ [NotNull] Type modelType,
+ [NotNull] string prefix,
+ [NotNull] HttpContext httpContext,
+ [NotNull] ModelStateDictionary modelState,
+ [NotNull] IModelMetadataProvider metadataProvider,
+ [NotNull] IModelBinder modelBinder,
+ [NotNull] IValueProvider valueProvider,
+ [NotNull] IObjectModelValidator objectModelValidator,
+ [NotNull] IModelValidatorProvider validatorProvider,
+ [NotNull] Func predicate)
+ {
+ if (!modelType.IsAssignableFrom(model.GetType()))
+ {
+ var message = Resources.FormatModelType_WrongType(
+ model.GetType().FullName,
+ modelType.FullName);
+ throw new ArgumentException(message, nameof(modelType));
+ }
+
var modelMetadata = metadataProvider.GetMetadataForType(
modelAccessor: () => model,
- modelType: model.GetType());
+ modelType: modelType);
var operationBindingContext = new OperationBindingContext
{
diff --git a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs
index 4954301d8f..292432e9ff 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs
@@ -1706,6 +1706,14 @@ namespace Microsoft.AspNet.Mvc.Core
return string.Format(CultureInfo.CurrentCulture, GetString("CacheProfileNotFound"), p0);
}
+ ///
+ /// The model type '{0}' does not match the '{1}' type parameter.
+ ///
+ internal static string FormatModelType_WrongType(object p0, object p1)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("ModelType_WrongType"), p0, p1);
+ }
+
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
diff --git a/src/Microsoft.AspNet.Mvc.Core/Resources.resx b/src/Microsoft.AspNet.Mvc.Core/Resources.resx
index c5434b5443..20099dea90 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Resources.resx
+++ b/src/Microsoft.AspNet.Mvc.Core/Resources.resx
@@ -445,4 +445,7 @@
The '{0}' cache profile is not defined.
+
+ The model's runtime type '{0}' is not assignable to the type '{1}'.
+
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs
index 78a96eae8d..f200ccd6ec 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs
@@ -1140,6 +1140,110 @@ namespace Microsoft.AspNet.Mvc.Test
binder.Verify();
}
+ [Fact]
+ public async Task TryUpdateModelNonGeneric_PredicateWithValueProviderOverload_UsesPassedArguments()
+ {
+ // Arrange
+ var modelName = "mymodel";
+
+ Func includePredicate =
+ (context, propertyName) => string.Equals(propertyName, "include1", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(propertyName, "include2", StringComparison.OrdinalIgnoreCase);
+
+ var binder = new Mock();
+ var valueProvider = Mock.Of();
+ binder.Setup(b => b.BindModelAsync(It.IsAny()))
+ .Callback((ModelBindingContext context) =>
+ {
+ Assert.Equal(modelName, context.ModelName);
+ Assert.Same(valueProvider, context.ValueProvider);
+
+ Assert.True(context.PropertyFilter(context, "include1"));
+ Assert.True(context.PropertyFilter(context, "include2"));
+
+ Assert.False(context.PropertyFilter(context, "exclude1"));
+ Assert.False(context.PropertyFilter(context, "exclude2"));
+ })
+ .Returns(Task.FromResult(null))
+ .Verifiable();
+
+ var controller = GetController(binder.Object, provider: null);
+
+ var model = new MyModel();
+
+ // Act
+ await controller.TryUpdateModelAsync(model, model.GetType(), modelName, valueProvider, includePredicate);
+
+ // Assert
+ binder.Verify();
+ }
+
+ [Fact]
+ public async Task TryUpdateModelNonGeneric_ModelTypeOverload_UsesPassedArguments()
+ {
+ // Arrange
+ var modelName = "mymodel";
+
+ var metadataProvider = new DataAnnotationsModelMetadataProvider();
+ var valueProvider = Mock.Of();
+ var binder = new Mock();
+ binder.Setup(b => b.BindModelAsync(It.IsAny()))
+ .Callback((ModelBindingContext context) =>
+ {
+ Assert.Equal(modelName, context.ModelName);
+ Assert.Same(valueProvider, context.ValueProvider);
+
+ // Include and exclude should be null, resulting in property
+ // being included.
+ Assert.True(context.PropertyFilter(context, "Property1"));
+ Assert.True(context.PropertyFilter(context, "Property2"));
+ })
+ .Returns(Task.FromResult(null))
+ .Verifiable();
+
+ var controller = GetController(binder.Object, valueProvider);
+ var model = new MyModel();
+
+ // Act
+ var result = await controller.TryUpdateModelAsync(model, model.GetType(), modelName);
+
+ // Assert
+ binder.Verify();
+ }
+
+ [Fact]
+ public async Task TryUpdateModelNonGeneric_BindToBaseDeclaredType_ModelTypeOverload()
+ {
+ // Arrange
+ var modelName = "mymodel";
+
+ var metadataProvider = new DataAnnotationsModelMetadataProvider();
+ var valueProvider = Mock.Of();
+ var binder = new Mock();
+ binder.Setup(b => b.BindModelAsync(It.IsAny()))
+ .Callback((ModelBindingContext context) =>
+ {
+ Assert.Equal(modelName, context.ModelName);
+ Assert.Same(valueProvider, context.ValueProvider);
+
+ // Include and exclude should be null, resulting in property
+ // being included.
+ Assert.True(context.PropertyFilter(context, "Property1"));
+ Assert.True(context.PropertyFilter(context, "Property2"));
+ })
+ .Returns(Task.FromResult(null))
+ .Verifiable();
+
+ var controller = GetController(binder.Object, valueProvider);
+ MyModel model = new MyDerivedModel();
+
+ // Act
+ var result = await controller.TryUpdateModelAsync(model, model.GetType(), modelName);
+
+ // Assert
+ binder.Verify();
+ }
+
#endif
[Fact]
@@ -1366,6 +1470,11 @@ namespace Microsoft.AspNet.Mvc.Test
public string Property2 { get; set; }
}
+ private class MyDerivedModel : MyModel
+ {
+ public string Property3 { get; set; }
+ }
+
private class User
{
public User(int id)
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ParameterBinding/ModelBindingHelperTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ParameterBinding/ModelBindingHelperTest.cs
index 16acb3f3fd..c9494920cf 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/ParameterBinding/ModelBindingHelperTest.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/ParameterBinding/ModelBindingHelperTest.cs
@@ -479,6 +479,222 @@ namespace Microsoft.AspNet.Mvc.Core.Test
ex.Message);
}
+ [Fact]
+ public async Task TryUpdateModelNonGeneric_PredicateOverload_ReturnsFalse_IfBinderReturnsFalse()
+ {
+ // Arrange
+ var metadataProvider = new Mock();
+ metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny>(), It.IsAny()))
+ .Returns(new ModelMetadata(metadataProvider.Object, null, null, typeof(MyModel), null))
+ .Verifiable();
+
+ var binder = new Mock();
+ binder.Setup(b => b.BindModelAsync(It.IsAny()))
+ .Returns(Task.FromResult(null));
+ var model = new MyModel();
+ Func includePredicate =
+ (context, propertyName) => true;
+ // Act
+ var result = await ModelBindingHelper.TryUpdateModelAsync(
+ model,
+ model.GetType(),
+ prefix: null,
+ httpContext: Mock.Of(),
+ modelState: new ModelStateDictionary(),
+ metadataProvider: metadataProvider.Object,
+ modelBinder: GetCompositeBinder(binder.Object),
+ valueProvider: Mock.Of(),
+ objectModelValidator: Mock.Of(),
+ validatorProvider: Mock.Of(),
+ predicate: includePredicate);
+
+ // Assert
+ Assert.False(result);
+ Assert.Null(model.MyProperty);
+ Assert.Null(model.IncludedProperty);
+ Assert.Null(model.ExcludedProperty);
+ metadataProvider.Verify();
+ }
+
+ [Fact]
+ public async Task TryUpdateModelNonGeneric_PredicateOverload_ReturnsTrue_ModelBindsAndValidatesSuccessfully()
+ {
+ // Arrange
+ var binders = new IModelBinder[]
+ {
+ new TypeConverterModelBinder(),
+ new ComplexModelDtoModelBinder(),
+ new MutableObjectModelBinder()
+ };
+
+ var validator = new DataAnnotationsModelValidatorProvider();
+ var model = new MyModel
+ {
+ MyProperty = "Old-Value",
+ IncludedProperty = "Old-IncludedPropertyValue",
+ ExcludedProperty = "Old-ExcludedPropertyValue"
+ };
+
+ var modelStateDictionary = new ModelStateDictionary();
+ var values = new Dictionary
+ {
+ { "", null },
+ { "MyProperty", "MyPropertyValue" },
+ { "IncludedProperty", "IncludedPropertyValue" },
+ { "ExcludedProperty", "ExcludedPropertyValue" }
+ };
+
+ Func includePredicate =
+ (context, propertyName) =>
+ string.Equals(propertyName, "IncludedProperty", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(propertyName, "MyProperty", StringComparison.OrdinalIgnoreCase);
+
+ var valueProvider = new TestValueProvider(values);
+ var metadataProvider = new DataAnnotationsModelMetadataProvider();
+
+ // Act
+ var result = await ModelBindingHelper.TryUpdateModelAsync(
+ model,
+ model.GetType(),
+ "",
+ Mock.Of(),
+ modelStateDictionary,
+ metadataProvider,
+ GetCompositeBinder(binders),
+ valueProvider,
+ new DefaultObjectValidator(
+ Mock.Of(),
+ metadataProvider),
+ validator,
+ includePredicate);
+
+ // Assert
+ Assert.True(result);
+ Assert.Equal("MyPropertyValue", model.MyProperty);
+ Assert.Equal("IncludedPropertyValue", model.IncludedProperty);
+ Assert.Equal("Old-ExcludedPropertyValue", model.ExcludedProperty);
+ }
+
+ [Fact]
+ public async Task TryUpdateModelNonGeneric_ModelTypeOverload_ReturnsFalse_IfBinderReturnsFalse()
+ {
+ // Arrange
+ var metadataProvider = new Mock();
+ metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny>(), It.IsAny()))
+ .Returns(new ModelMetadata(metadataProvider.Object, null, null, typeof(MyModel), null))
+ .Verifiable();
+
+ var binder = new Mock();
+ binder.Setup(b => b.BindModelAsync(It.IsAny()))
+ .Returns(Task.FromResult(null));
+ var model = new MyModel();
+
+ // Act
+ var result = await ModelBindingHelper.TryUpdateModelAsync(
+ model,
+ modelType: model.GetType(),
+ prefix: null,
+ httpContext: Mock.Of(),
+ modelState: new ModelStateDictionary(),
+ metadataProvider: metadataProvider.Object,
+ modelBinder: GetCompositeBinder(binder.Object),
+ valueProvider: Mock.Of(),
+ objectModelValidator: Mock.Of(),
+ validatorProvider: Mock.Of());
+
+ // Assert
+ Assert.False(result);
+ Assert.Null(model.MyProperty);
+ metadataProvider.Verify();
+ }
+
+ [Fact]
+ public async Task TryUpdateModelNonGeneric_ModelTypeOverload_ReturnsTrue_IfModelBindsAndValidatesSuccessfully()
+ {
+ // Arrange
+ var binders = new IModelBinder[]
+ {
+ new TypeConverterModelBinder(),
+ new ComplexModelDtoModelBinder(),
+ new MutableObjectModelBinder()
+ };
+
+ var validator = new DataAnnotationsModelValidatorProvider();
+ var model = new MyModel { MyProperty = "Old-Value" };
+ var modelStateDictionary = new ModelStateDictionary();
+ var values = new Dictionary
+ {
+ { "", null },
+ { "MyProperty", "MyPropertyValue" }
+ };
+ var valueProvider = new TestValueProvider(values);
+ var metadataProvider = new DataAnnotationsModelMetadataProvider();
+
+ // Act
+ var result = await ModelBindingHelper.TryUpdateModelAsync(
+ model,
+ model.GetType(),
+ "",
+ Mock.Of(),
+ modelStateDictionary,
+ new DataAnnotationsModelMetadataProvider(),
+ GetCompositeBinder(binders),
+ valueProvider,
+ new DefaultObjectValidator(
+ Mock.Of(),
+ metadataProvider),
+ validator);
+
+ // Assert
+ Assert.True(result);
+ Assert.Equal("MyPropertyValue", model.MyProperty);
+ }
+
+ [Fact]
+ public async Task TryUpdataModel_ModelTypeDifferentFromModel_Throws()
+ {
+ // Arrange
+ var metadataProvider = new Mock();
+ metadataProvider.Setup(m => m.GetMetadataForType(null, It.IsAny()))
+ .Returns(new ModelMetadata(metadataProvider.Object,
+ containerType: null,
+ modelAccessor: null,
+ modelType: typeof(MyModel),
+ propertyName: null))
+ .Verifiable();
+
+ var binder = new Mock();
+ binder.Setup(b => b.BindModelAsync(It.IsAny()))
+ .Returns(Task.FromResult(null));
+ var model = new MyModel();
+ Func includePredicate =
+ (context, propertyName) => true;
+
+ // Act & Assert
+ var exception = await Assert.ThrowsAsync(
+ () => ModelBindingHelper.TryUpdateModelAsync(
+ model,
+ typeof(User),
+ null,
+ Mock.Of(),
+ new ModelStateDictionary(),
+ metadataProvider.Object,
+ GetCompositeBinder(binder.Object),
+ Mock.Of(),
+ new DefaultObjectValidator(
+ Mock.Of(),
+ metadataProvider.Object),
+ Mock.Of(),
+ includePredicate));
+
+ var expectedMessage = string.Format("The model's runtime type '{0}' is not assignable to the type '{1}'." +
+ Environment.NewLine +
+ "Parameter name: modelType",
+ model.GetType().FullName,
+ typeof(User).FullName);
+ Assert.Equal(expectedMessage, exception.Message);
+ }
+
private static IModelBinder GetCompositeBinder(params IModelBinder[] binders)
{
return new CompositeModelBinder(binders);
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTest.cs
index a715fc02f8..86ffbfb80d 100644
--- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTest.cs
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTest.cs
@@ -398,7 +398,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal("WA_Query", user.ShippingAddress.State);
Assert.Equal(3, user.ShippingAddress.Street);
Assert.Equal(4, user.ShippingAddress.Zip);
-
}
[Fact]
@@ -1573,6 +1572,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
[Fact]
public async Task ModelBinder_FormatsDontMatch_ThrowsUserFriendlyException()
+
{
// Arrange
var server = TestServer.Create(_services, _app);
@@ -1644,6 +1644,29 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(expectedDictionary, dictionary);
}
+ [Fact]
+ public async Task TryUpdateModelNonGeneric_IncludesAllProperties_CanBind()
+ {
+ // Arrange
+ var server = TestServer.Create(_services, _app);
+ var client = server.CreateClient();
+
+ // Act
+ var response = await client.GetStringAsync("http://localhost/TryUpdateModel/" +
+ "GetUserAsync_ModelType_IncludeAll" +
+ "?id=123&RegisterationMonth=March&Key=123&UserName=SomeName");
+
+ // Assert
+ var user = JsonConvert.DeserializeObject(response);
+
+ // Should not update any not explicitly mentioned properties.
+ Assert.Equal("SomeName", user.UserName);
+ Assert.Equal(123, user.Key);
+
+ // Should Update all included properties.
+ Assert.Equal("March", user.RegisterationMonth);
+ }
+
[Fact]
public async Task FormCollectionModelBinder_CanBind_FormValues()
{
@@ -1731,5 +1754,28 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var fileContent = await response.Content.ReadAsStringAsync();
Assert.Equal(expectedContent, fileContent);
}
+
+ [Fact]
+ public async Task TryUpdateModelNonGenericIncludesAllProperties_ByDefault()
+ {
+ // Arrange
+ var server = TestServer.Create(_services, _app);
+ var client = server.CreateClient();
+
+ // Act
+ var response = await client.GetStringAsync("http://localhost/TryUpdateModel/" +
+ "GetUserAsync_ModelType_IncludeAllByDefault" +
+ "?id=123&RegisterationMonth=March&Key=123&UserName=SomeName");
+
+ // Assert
+ var user = JsonConvert.DeserializeObject(response);
+
+ // Should not update any not explicitly mentioned properties.
+ Assert.Equal("SomeName", user.UserName);
+ Assert.Equal(123, user.Key);
+
+ // Should Update all included properties.
+ Assert.Equal("March", user.RegisterationMonth);
+ }
}
}
\ No newline at end of file
diff --git a/test/WebSites/ModelBindingWebSite/Controllers/TryUpdateModelController.cs b/test/WebSites/ModelBindingWebSite/Controllers/TryUpdateModelController.cs
index 77fb8539f7..fe5d89d543 100644
--- a/test/WebSites/ModelBindingWebSite/Controllers/TryUpdateModelController.cs
+++ b/test/WebSites/ModelBindingWebSite/Controllers/TryUpdateModelController.cs
@@ -2,9 +2,13 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
+using System.Collections.Generic;
+using Microsoft.AspNet.Http.Core.Collections;
+using Microsoft.AspNet.Http;
namespace ModelBindingWebSite.Controllers
{
@@ -100,12 +104,58 @@ namespace ModelBindingWebSite.Controllers
public async Task GetEmployeeAsync_BindToBaseDeclaredType()
{
- var employee = new Employee();
- await TryUpdateModelAsync(
- employee,
- prefix: string.Empty);
+ var backingStore = new ReadableStringCollection(
+ new Dictionary
+ {
+ { "Parent.Name", new[] { "fatherName"} },
+ { "Parent.Parent.Name", new[] {"grandFatherName" } },
+ { "Department", new[] {"Sales" } }
+ });
- return employee;
+ Person employee = new Employee();
+ await TryUpdateModelAsync(
+ employee,
+ employee.GetType(),
+ prefix: string.Empty,
+ valueProvider: new ReadableStringCollectionValueProvider(
+ BindingSource.Query,
+ backingStore,
+ CultureInfo.CurrentCulture),
+ predicate: (content, propertyName) => true);
+
+ return (Employee)employee;
+ }
+
+ public async Task GetUserAsync_ModelType_IncludeAll(int id)
+ {
+ var backingStore = new ReadableStringCollection(
+ new Dictionary
+ {
+ { "Key", new[] { "123"} },
+ { "RegisterationMonth", new[] {"March" } },
+ { "UserName", new[] {"SomeName" } }
+ });
+
+ var user = GetUser(id);
+
+ await TryUpdateModelAsync(user,
+ typeof(User),
+ prefix: string.Empty,
+ valueProvider: new ReadableStringCollectionValueProvider(
+ BindingSource.Query,
+ backingStore,
+ CultureInfo.CurrentCulture),
+ predicate: (content, propertyName) => true);
+
+ return user;
+ }
+
+ public async Task GetUserAsync_ModelType_IncludeAllByDefault(int id)
+ {
+ var user = GetUser(id);
+
+ await TryUpdateModelAsync(user, user.GetType(), prefix: string.Empty);
+ return user;
}
private User GetUser(int id)