Reverting #1837 and add non-generic overloads for TryUpdateModel
This commit is contained in:
parent
1cc9be5df7
commit
f6e701b2b2
|
|
@ -1104,6 +1104,82 @@ namespace Microsoft.AspNet.Mvc
|
|||
predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the specified <paramref name="model"/> instance using values from the controller's current
|
||||
/// <see cref="IValueProvider"/> and a <paramref name="prefix"/>.
|
||||
/// </summary>
|
||||
/// <param name="model">The model instance to update.</param>
|
||||
/// <param name="modelType">The type of model instance to update.</param>
|
||||
/// <param name="prefix">The prefix to use when looking up values in the current <see cref="IValueProvider"/>
|
||||
/// </param>
|
||||
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
|
||||
[NonAction]
|
||||
public virtual async Task<bool> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the specified <paramref name="model"/> instance using the <paramref name="valueProvider"/> and a
|
||||
/// <paramref name="prefix"/>.
|
||||
/// </summary>
|
||||
/// <param name="model">The model instance to update.</param>
|
||||
/// <param name="modelType">The type of model instance to update.</param>
|
||||
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>
|
||||
/// </param>
|
||||
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
|
||||
/// <param name="predicate">A predicate which can be used to filter properties at runtime.</param>
|
||||
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
|
||||
[NonAction]
|
||||
public async Task<bool> TryUpdateModelAsync(
|
||||
[NotNull] object model,
|
||||
[NotNull] Type modelType,
|
||||
string prefix,
|
||||
[NotNull] IValueProvider valueProvider,
|
||||
[NotNull] Func<ModelBindingContext, string, bool> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the specified <paramref name="model"/> instance.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -128,14 +128,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// <param name="metadataProvider">The provider used for reading metadata for the model type.</param>
|
||||
/// <param name="modelBinder">The <see cref="IModelBinder"/> used for binding.</param>
|
||||
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
|
||||
/// /// <param name="objectModelValidator">The <see cref="IObjectModelValidator"/> used for validating the
|
||||
/// <param name="objectModelValidator">The <see cref="IObjectModelValidator"/> used for validating the
|
||||
/// bound values.</param>
|
||||
/// <param name="validatorProvider">The <see cref="IModelValidatorProvider"/> used for executing validation
|
||||
/// on the model instance.</param>
|
||||
/// <param name="predicate">A predicate which can be used to
|
||||
/// filter properties(for inclusion/exclusion) at runtime.</param>
|
||||
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
|
||||
public static async Task<bool> TryUpdateModelAsync<TModel>(
|
||||
public static Task<bool> TryUpdateModelAsync<TModel>(
|
||||
[NotNull] TModel model,
|
||||
[NotNull] string prefix,
|
||||
[NotNull] HttpContext httpContext,
|
||||
|
|
@ -148,9 +148,113 @@ namespace Microsoft.AspNet.Mvc
|
|||
[NotNull] Func<ModelBindingContext, string, bool> predicate)
|
||||
where TModel : class
|
||||
{
|
||||
return TryUpdateModelAsync(
|
||||
model,
|
||||
typeof(TModel),
|
||||
prefix,
|
||||
httpContext,
|
||||
modelState,
|
||||
metadataProvider,
|
||||
modelBinder,
|
||||
valueProvider,
|
||||
objectModelValidator,
|
||||
validatorProvider,
|
||||
predicate: predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the specified <paramref name="model"/> instance using the specified <paramref name="modelBinder"/>
|
||||
/// and the specified <paramref name="valueProvider"/> and executes validation using the specified
|
||||
/// <paramref name="validatorProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="model">The model instance to update and validate.</param>
|
||||
/// <param name="modelType">The type of model instance to update and validate.</param>
|
||||
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
|
||||
/// </param>
|
||||
/// <param name="httpContext">The <see cref="HttpContext"/> for the current executing request.</param>
|
||||
/// <param name="modelState">The <see cref="ModelStateDictionary"/> used for maintaining state and
|
||||
/// results of model-binding validation.</param>
|
||||
/// <param name="metadataProvider">The provider used for reading metadata for the model type.</param>
|
||||
/// <param name="modelBinder">The <see cref="IModelBinder"/> used for binding.</param>
|
||||
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
|
||||
/// <param name="objectModelValidator">The <see cref="IObjectModelValidator"/> used for validating the
|
||||
/// bound values.</param>
|
||||
/// <param name="validatorProvider">The <see cref="IModelValidatorProvider"/> used for executing validation
|
||||
/// on the model instance.</param>
|
||||
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
|
||||
public static Task<bool> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the specified <paramref name="model"/> instance using the specified <paramref name="modelBinder"/>
|
||||
/// and the specified <paramref name="valueProvider"/> and executes validation using the specified
|
||||
/// <paramref name="validatorProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="model">The model instance to update and validate.</param>
|
||||
/// <param name="modelType">The type of model instance to update and validate.</param>
|
||||
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
|
||||
/// </param>
|
||||
/// <param name="httpContext">The <see cref="HttpContext"/> for the current executing request.</param>
|
||||
/// <param name="modelState">The <see cref="ModelStateDictionary"/> used for maintaining state and
|
||||
/// results of model-binding validation.</param>
|
||||
/// <param name="metadataProvider">The provider used for reading metadata for the model type.</param>
|
||||
/// <param name="modelBinder">The <see cref="IModelBinder"/> used for binding.</param>
|
||||
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
|
||||
/// <param name="objectModelValidator">The <see cref="IObjectModelValidator"/> used for validating the
|
||||
/// bound values.</param>
|
||||
/// <param name="validatorProvider">The <see cref="IModelValidatorProvider"/> used for executing validation
|
||||
/// on the model instance.</param>
|
||||
/// <param name="predicate">A predicate which can be used to
|
||||
/// filter properties(for inclusion/exclusion) at runtime.</param>
|
||||
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
|
||||
public static async Task<bool> 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<ModelBindingContext, string, bool> 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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1706,6 +1706,14 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("CacheProfileNotFound"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The model type '{0}' does not match the '{1}' type parameter.
|
||||
/// </summary>
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -445,4 +445,7 @@
|
|||
<data name="CacheProfileNotFound" xml:space="preserve">
|
||||
<value>The '{0}' cache profile is not defined.</value>
|
||||
</data>
|
||||
<data name="ModelType_WrongType" xml:space="preserve">
|
||||
<value>The model's runtime type '{0}' is not assignable to the type '{1}'.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1140,6 +1140,110 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
binder.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryUpdateModelNonGeneric_PredicateWithValueProviderOverload_UsesPassedArguments()
|
||||
{
|
||||
// Arrange
|
||||
var modelName = "mymodel";
|
||||
|
||||
Func<ModelBindingContext, string, bool> includePredicate =
|
||||
(context, propertyName) => string.Equals(propertyName, "include1", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(propertyName, "include2", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var binder = new Mock<IModelBinder>();
|
||||
var valueProvider = Mock.Of<IValueProvider>();
|
||||
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||
.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<ModelBindingResult>(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<IValueProvider>();
|
||||
var binder = new Mock<IModelBinder>();
|
||||
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||
.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<ModelBindingResult>(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<IValueProvider>();
|
||||
var binder = new Mock<IModelBinder>();
|
||||
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||
.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<ModelBindingResult>(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)
|
||||
|
|
|
|||
|
|
@ -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<IModelMetadataProvider>();
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, null, typeof(MyModel), null))
|
||||
.Verifiable();
|
||||
|
||||
var binder = new Mock<IModelBinder>();
|
||||
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||
.Returns(Task.FromResult<ModelBindingResult>(null));
|
||||
var model = new MyModel();
|
||||
Func<ModelBindingContext, string, bool> includePredicate =
|
||||
(context, propertyName) => true;
|
||||
// Act
|
||||
var result = await ModelBindingHelper.TryUpdateModelAsync(
|
||||
model,
|
||||
model.GetType(),
|
||||
prefix: null,
|
||||
httpContext: Mock.Of<HttpContext>(),
|
||||
modelState: new ModelStateDictionary(),
|
||||
metadataProvider: metadataProvider.Object,
|
||||
modelBinder: GetCompositeBinder(binder.Object),
|
||||
valueProvider: Mock.Of<IValueProvider>(),
|
||||
objectModelValidator: Mock.Of<IObjectModelValidator>(),
|
||||
validatorProvider: Mock.Of<IModelValidatorProvider>(),
|
||||
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<string, object>
|
||||
{
|
||||
{ "", null },
|
||||
{ "MyProperty", "MyPropertyValue" },
|
||||
{ "IncludedProperty", "IncludedPropertyValue" },
|
||||
{ "ExcludedProperty", "ExcludedPropertyValue" }
|
||||
};
|
||||
|
||||
Func<ModelBindingContext, string, bool> 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<HttpContext>(),
|
||||
modelStateDictionary,
|
||||
metadataProvider,
|
||||
GetCompositeBinder(binders),
|
||||
valueProvider,
|
||||
new DefaultObjectValidator(
|
||||
Mock.Of<IValidationExcludeFiltersProvider>(),
|
||||
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<IModelMetadataProvider>();
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, null, typeof(MyModel), null))
|
||||
.Verifiable();
|
||||
|
||||
var binder = new Mock<IModelBinder>();
|
||||
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||
.Returns(Task.FromResult<ModelBindingResult>(null));
|
||||
var model = new MyModel();
|
||||
|
||||
// Act
|
||||
var result = await ModelBindingHelper.TryUpdateModelAsync(
|
||||
model,
|
||||
modelType: model.GetType(),
|
||||
prefix: null,
|
||||
httpContext: Mock.Of<HttpContext>(),
|
||||
modelState: new ModelStateDictionary(),
|
||||
metadataProvider: metadataProvider.Object,
|
||||
modelBinder: GetCompositeBinder(binder.Object),
|
||||
valueProvider: Mock.Of<IValueProvider>(),
|
||||
objectModelValidator: Mock.Of<IObjectModelValidator>(),
|
||||
validatorProvider: Mock.Of<IModelValidatorProvider>());
|
||||
|
||||
// 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<string, object>
|
||||
{
|
||||
{ "", null },
|
||||
{ "MyProperty", "MyPropertyValue" }
|
||||
};
|
||||
var valueProvider = new TestValueProvider(values);
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
|
||||
// Act
|
||||
var result = await ModelBindingHelper.TryUpdateModelAsync(
|
||||
model,
|
||||
model.GetType(),
|
||||
"",
|
||||
Mock.Of<HttpContext>(),
|
||||
modelStateDictionary,
|
||||
new DataAnnotationsModelMetadataProvider(),
|
||||
GetCompositeBinder(binders),
|
||||
valueProvider,
|
||||
new DefaultObjectValidator(
|
||||
Mock.Of<IValidationExcludeFiltersProvider>(),
|
||||
metadataProvider),
|
||||
validator);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Equal("MyPropertyValue", model.MyProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryUpdataModel_ModelTypeDifferentFromModel_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(null, It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: typeof(MyModel),
|
||||
propertyName: null))
|
||||
.Verifiable();
|
||||
|
||||
var binder = new Mock<IModelBinder>();
|
||||
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||
.Returns(Task.FromResult<ModelBindingResult>(null));
|
||||
var model = new MyModel();
|
||||
Func<ModelBindingContext, string, bool> includePredicate =
|
||||
(context, propertyName) => true;
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<ArgumentException>(
|
||||
() => ModelBindingHelper.TryUpdateModelAsync(
|
||||
model,
|
||||
typeof(User),
|
||||
null,
|
||||
Mock.Of<HttpContext>(),
|
||||
new ModelStateDictionary(),
|
||||
metadataProvider.Object,
|
||||
GetCompositeBinder(binder.Object),
|
||||
Mock.Of<IValueProvider>(),
|
||||
new DefaultObjectValidator(
|
||||
Mock.Of<IValidationExcludeFiltersProvider>(),
|
||||
metadataProvider.Object),
|
||||
Mock.Of<IModelValidatorProvider>(),
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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<User>(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<User>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Employee> GetEmployeeAsync_BindToBaseDeclaredType()
|
||||
{
|
||||
var employee = new Employee();
|
||||
await TryUpdateModelAsync<Person>(
|
||||
employee,
|
||||
prefix: string.Empty);
|
||||
var backingStore = new ReadableStringCollection(
|
||||
new Dictionary<string, string[]>
|
||||
{
|
||||
{ "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<User> GetUserAsync_ModelType_IncludeAll(int id)
|
||||
{
|
||||
var backingStore = new ReadableStringCollection(
|
||||
new Dictionary<string, string[]>
|
||||
{
|
||||
{ "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<User> GetUserAsync_ModelType_IncludeAllByDefault(int id)
|
||||
{
|
||||
var user = GetUser(id);
|
||||
|
||||
await TryUpdateModelAsync(user, user.GetType(), prefix: string.Empty);
|
||||
return user;
|
||||
}
|
||||
|
||||
private User GetUser(int id)
|
||||
|
|
|
|||
Loading…
Reference in New Issue