Introducing Controller.TryUpdateModel
This changeset reintroduces some of the overloads for Controller.TryUpdateModel. Fixes #415
This commit is contained in:
parent
da0bf6f7d8
commit
24f74222f5
|
|
@ -20,6 +20,11 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
if (ActionContext == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return ActionContext.HttpContext;
|
return ActionContext.HttpContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -28,6 +33,11 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
if (ViewData == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return ViewData.ModelState;
|
return ViewData.ModelState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +48,9 @@ namespace Microsoft.AspNet.Mvc
|
||||||
[Activate]
|
[Activate]
|
||||||
public IUrlHelper Url { get; set; }
|
public IUrlHelper Url { get; set; }
|
||||||
|
|
||||||
|
[Activate]
|
||||||
|
public IActionBindingContextProvider BindingContextProvider { get; set; }
|
||||||
|
|
||||||
public IPrincipal User
|
public IPrincipal User
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -438,5 +451,72 @@ namespace Microsoft.AspNet.Mvc
|
||||||
OnActionExecuted(await next());
|
OnActionExecuted(await next());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the specified model instance using values from the controller's current value provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TModel">The type of the model object.</typeparam>
|
||||||
|
/// <param name="model">The model instance to update.</param>
|
||||||
|
/// <returns>true if the update is successful; otherwise, false.</returns>
|
||||||
|
[NonAction]
|
||||||
|
public virtual Task<bool> TryUpdateModelAsync<TModel>([NotNull] TModel model)
|
||||||
|
where TModel : class
|
||||||
|
{
|
||||||
|
return TryUpdateModelAsync(model, prefix: typeof(TModel).Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the specified model instance using values from the controller's current value provider
|
||||||
|
/// and a prefix.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TModel">The type of the model object.</typeparam>
|
||||||
|
/// <param name="model">The model instance to update.</param>
|
||||||
|
/// <param name="prefix">The prefix to use when looking up values in the value provider.</param>
|
||||||
|
/// <returns>true if the update is successful; otherwise, false.</returns>
|
||||||
|
[NonAction]
|
||||||
|
public virtual async Task<bool> TryUpdateModelAsync<TModel>([NotNull] TModel model,
|
||||||
|
[NotNull] string prefix)
|
||||||
|
where TModel : class
|
||||||
|
{
|
||||||
|
if (BindingContextProvider == null)
|
||||||
|
{
|
||||||
|
var message = Resources.FormatPropertyOfTypeCannotBeNull("BindingContextProvider", GetType().FullName);
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
var bindingContext = await BindingContextProvider.GetActionBindingContextAsync(ActionContext);
|
||||||
|
return await TryUpdateModelAsync(model, prefix, bindingContext.ValueProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the specified model instance using the value provider and a prefix.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TModel">The type of the model object.</typeparam>
|
||||||
|
/// <param name="model">The model instance to update.</param>
|
||||||
|
/// <param name="prefix">The prefix to use when looking up values in the value provider.</param>
|
||||||
|
/// <param name="valueProvider">The value provider used for looking up values.</param>
|
||||||
|
/// <returns>true if the update is successful; otherwise, false.</returns>
|
||||||
|
[NonAction]
|
||||||
|
public virtual async Task<bool> TryUpdateModelAsync<TModel>([NotNull] TModel model,
|
||||||
|
[NotNull] string prefix,
|
||||||
|
[NotNull] IValueProvider valueProvider)
|
||||||
|
where TModel : class
|
||||||
|
{
|
||||||
|
if (BindingContextProvider == null)
|
||||||
|
{
|
||||||
|
var message = Resources.FormatPropertyOfTypeCannotBeNull("BindingContextProvider", GetType().FullName);
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
var bindingContext = await BindingContextProvider.GetActionBindingContextAsync(ActionContext);
|
||||||
|
return await ModelBindingHelper.TryUpdateModelAsync(model,
|
||||||
|
prefix,
|
||||||
|
ActionContext.HttpContext,
|
||||||
|
ModelState,
|
||||||
|
bindingContext.MetadataProvider,
|
||||||
|
bindingContext.ModelBinder,
|
||||||
|
valueProvider,
|
||||||
|
bindingContext.ValidatorProviders);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@
|
||||||
<Compile Include="Formatters\OutputFormatterContext.cs" />
|
<Compile Include="Formatters\OutputFormatterContext.cs" />
|
||||||
<Compile Include="Formatters\JsonOutputFormatter.cs" />
|
<Compile Include="Formatters\JsonOutputFormatter.cs" />
|
||||||
<Compile Include="Formatters\OutputFormatter.cs" />
|
<Compile Include="Formatters\OutputFormatter.cs" />
|
||||||
|
<Compile Include="ParameterBinding\ModelBindingHelper.cs" />
|
||||||
<Compile Include="ReflectedActionDescriptor.cs" />
|
<Compile Include="ReflectedActionDescriptor.cs" />
|
||||||
<Compile Include="ReflectedActionDescriptorProvider.cs" />
|
<Compile Include="ReflectedActionDescriptorProvider.cs" />
|
||||||
<Compile Include="ReflectedModelBuilder\IReflectedApplicationModelConvention.cs" />
|
<Compile Include="ReflectedModelBuilder\IReflectedApplicationModelConvention.cs" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public static class ModelBindingHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the specified model instance using the specified binder and value provider and
|
||||||
|
/// executes validation using the specified sequence of validator providers.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TModel">The type of the model object.</typeparam>
|
||||||
|
/// <param name="model">The model instance to update.</param>
|
||||||
|
/// <param name="prefix">The prefix to use when looking up values in the value provider.</param>
|
||||||
|
/// <param name="httpContext">The context for the current executing request.</param>
|
||||||
|
/// <param name="modelState">The 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 model binder used for binding.</param>
|
||||||
|
/// <param name="valueProvider">The value provider used for looking up values.</param>
|
||||||
|
/// <param name="validatorProviders">The validator providers used for executing validation
|
||||||
|
/// on the model instance.</param>
|
||||||
|
/// <returns>A Task with a value representing if the the update is successful.</returns>
|
||||||
|
public static async Task<bool> TryUpdateModelAsync<TModel>(
|
||||||
|
[NotNull] TModel model,
|
||||||
|
[NotNull] string prefix,
|
||||||
|
[NotNull] HttpContext httpContext,
|
||||||
|
[NotNull] ModelStateDictionary modelState,
|
||||||
|
[NotNull] IModelMetadataProvider metadataProvider,
|
||||||
|
[NotNull] IModelBinder modelBinder,
|
||||||
|
[NotNull] IValueProvider valueProvider,
|
||||||
|
[NotNull] IEnumerable<IModelValidatorProvider> validatorProviders)
|
||||||
|
where TModel : class
|
||||||
|
{
|
||||||
|
var modelMetadata = metadataProvider.GetMetadataForType(
|
||||||
|
modelAccessor: null,
|
||||||
|
modelType: typeof(TModel));
|
||||||
|
|
||||||
|
var modelBindingContext = new ModelBindingContext
|
||||||
|
{
|
||||||
|
ModelMetadata = modelMetadata,
|
||||||
|
ModelName = prefix,
|
||||||
|
Model = model,
|
||||||
|
ModelState = modelState,
|
||||||
|
ModelBinder = modelBinder,
|
||||||
|
ValueProvider = valueProvider,
|
||||||
|
ValidatorProviders = validatorProviders,
|
||||||
|
MetadataProvider = metadataProvider,
|
||||||
|
FallbackToEmptyPrefix = true,
|
||||||
|
HttpContext = httpContext
|
||||||
|
};
|
||||||
|
|
||||||
|
if (await modelBinder.BindModelAsync(modelBindingContext))
|
||||||
|
{
|
||||||
|
return modelState.IsValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ using Microsoft.AspNet.Testing;
|
||||||
using Moq;
|
using Moq;
|
||||||
#endif
|
#endif
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Test
|
namespace Microsoft.AspNet.Mvc.Test
|
||||||
{
|
{
|
||||||
|
|
@ -25,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
return typeof(Controller).GetTypeInfo()
|
return typeof(Controller).GetTypeInfo()
|
||||||
.DeclaredMethods
|
.DeclaredMethods
|
||||||
.Where(method => method.IsPublic && !method.IsSpecialName)
|
.Where(method => method.IsPublic && !method.IsSpecialName)
|
||||||
.Select(method => new [] { method });
|
.Select(method => new[] { method });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -541,6 +542,133 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
await ActionFilterAttributeTests.ActionFilter_Calls_OnActionExecuted(
|
await ActionFilterAttributeTests.ActionFilter_Calls_OnActionExecuted(
|
||||||
new Mock<Controller>());
|
new Mock<Controller>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TryUpdateModel_UsesModelTypeNameIfNotSpecified()
|
||||||
|
{
|
||||||
|
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
var valueProvider = Mock.Of<IValueProvider>();
|
||||||
|
var binder = new Mock<IModelBinder>();
|
||||||
|
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||||
|
.Callback((ModelBindingContext b) =>
|
||||||
|
{
|
||||||
|
Assert.Equal(typeof(MyModel).Name, b.ModelName);
|
||||||
|
Assert.Same(valueProvider, b.ValueProvider);
|
||||||
|
})
|
||||||
|
.Returns(Task.FromResult(false))
|
||||||
|
.Verifiable();
|
||||||
|
var model = new MyModel();
|
||||||
|
var actionContext = new ActionContext(Mock.Of<HttpContext>(), new RouteData(), new ActionDescriptor());
|
||||||
|
var bindingContext = new ActionBindingContext(actionContext,
|
||||||
|
metadataProvider,
|
||||||
|
binder.Object,
|
||||||
|
valueProvider,
|
||||||
|
Mock.Of<IInputFormatterProvider>(),
|
||||||
|
Enumerable.Empty<IModelValidatorProvider>());
|
||||||
|
var bindingContextProvider = new Mock<IActionBindingContextProvider>();
|
||||||
|
bindingContextProvider.Setup(b => b.GetActionBindingContextAsync(actionContext))
|
||||||
|
.Returns(Task.FromResult(bindingContext));
|
||||||
|
var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary());
|
||||||
|
var controller = new Controller
|
||||||
|
{
|
||||||
|
ActionContext = actionContext,
|
||||||
|
BindingContextProvider = bindingContextProvider.Object,
|
||||||
|
ViewData = viewData
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await controller.TryUpdateModelAsync(model);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
binder.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TryUpdateModel_UsesModelTypeNameIfSpecified()
|
||||||
|
{
|
||||||
|
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
var valueProvider = Mock.Of<IValueProvider>();
|
||||||
|
var binder = new Mock<IModelBinder>();
|
||||||
|
var modelName = "mymodel";
|
||||||
|
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||||
|
.Callback((ModelBindingContext b) =>
|
||||||
|
{
|
||||||
|
Assert.Equal(modelName, b.ModelName);
|
||||||
|
Assert.Same(valueProvider, b.ValueProvider);
|
||||||
|
})
|
||||||
|
.Returns(Task.FromResult(false))
|
||||||
|
.Verifiable();
|
||||||
|
var model = new MyModel();
|
||||||
|
var actionContext = new ActionContext(Mock.Of<HttpContext>(), new RouteData(), new ActionDescriptor());
|
||||||
|
var bindingContext = new ActionBindingContext(actionContext,
|
||||||
|
metadataProvider,
|
||||||
|
binder.Object,
|
||||||
|
valueProvider,
|
||||||
|
Mock.Of<IInputFormatterProvider>(),
|
||||||
|
Enumerable.Empty<IModelValidatorProvider>());
|
||||||
|
var bindingContextProvider = new Mock<IActionBindingContextProvider>();
|
||||||
|
bindingContextProvider.Setup(b => b.GetActionBindingContextAsync(actionContext))
|
||||||
|
.Returns(Task.FromResult(bindingContext));
|
||||||
|
var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary());
|
||||||
|
var controller = new Controller
|
||||||
|
{
|
||||||
|
ActionContext = actionContext,
|
||||||
|
BindingContextProvider = bindingContextProvider.Object,
|
||||||
|
ViewData = viewData
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await controller.TryUpdateModelAsync(model, modelName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
binder.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TryUpdateModel_UsesModelValueProviderIfSpecified()
|
||||||
|
{
|
||||||
|
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
var valueProvider = Mock.Of<IValueProvider>();
|
||||||
|
var binder = new Mock<IModelBinder>();
|
||||||
|
var modelName = "mymodel";
|
||||||
|
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||||
|
.Callback((ModelBindingContext b) =>
|
||||||
|
{
|
||||||
|
Assert.Equal(modelName, b.ModelName);
|
||||||
|
Assert.Same(valueProvider, b.ValueProvider);
|
||||||
|
})
|
||||||
|
.Returns(Task.FromResult(false))
|
||||||
|
.Verifiable();
|
||||||
|
var model = new MyModel();
|
||||||
|
var actionContext = new ActionContext(Mock.Of<HttpContext>(), new RouteData(), new ActionDescriptor());
|
||||||
|
var bindingContext = new ActionBindingContext(actionContext,
|
||||||
|
metadataProvider,
|
||||||
|
binder.Object,
|
||||||
|
Mock.Of<IValueProvider>(),
|
||||||
|
Mock.Of<IInputFormatterProvider>(),
|
||||||
|
Enumerable.Empty<IModelValidatorProvider>());
|
||||||
|
var bindingContextProvider = new Mock<IActionBindingContextProvider>();
|
||||||
|
bindingContextProvider.Setup(b => b.GetActionBindingContextAsync(actionContext))
|
||||||
|
.Returns(Task.FromResult(bindingContext));
|
||||||
|
var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary());
|
||||||
|
var controller = new Controller
|
||||||
|
{
|
||||||
|
ActionContext = actionContext,
|
||||||
|
BindingContextProvider = bindingContextProvider.Object,
|
||||||
|
ViewData = viewData
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await controller.TryUpdateModelAsync(model, modelName, valueProvider);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
binder.Verify();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private class MyModel
|
||||||
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
<Compile Include="ExpiringFileInfoCacheTest.cs" />
|
<Compile Include="ExpiringFileInfoCacheTest.cs" />
|
||||||
<Compile Include="DefaultActionDiscoveryConventionsTests.cs" />
|
<Compile Include="DefaultActionDiscoveryConventionsTests.cs" />
|
||||||
<Compile Include="Formatters\OutputFormatterTests.cs" />
|
<Compile Include="Formatters\OutputFormatterTests.cs" />
|
||||||
|
<Compile Include="ParameterBinding\ModelBindingHelperTest.cs" />
|
||||||
<Compile Include="ReflectedModelBuilder\ReflectedParameterModelTests.cs" />
|
<Compile Include="ReflectedModelBuilder\ReflectedParameterModelTests.cs" />
|
||||||
<Compile Include="ReflectedModelBuilder\ReflectedActionModelTests.cs" />
|
<Compile Include="ReflectedModelBuilder\ReflectedActionModelTests.cs" />
|
||||||
<Compile Include="ReflectedModelBuilder\ReflectedControllerModelTests.cs" />
|
<Compile Include="ReflectedModelBuilder\ReflectedControllerModelTests.cs" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#if NET45
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
|
{
|
||||||
|
public class ModelBindingHelperTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task TryUpdateModel_ReturnsFalse_IfBinderReturnsFalse()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||||
|
metadataProvider.Setup(m => m.GetMetadataForType(null, 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(false));
|
||||||
|
var model = new MyModel();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await ModelBindingHelper.TryUpdateModelAsync(
|
||||||
|
model,
|
||||||
|
null,
|
||||||
|
Mock.Of<HttpContext>(),
|
||||||
|
new ModelStateDictionary(),
|
||||||
|
metadataProvider.Object,
|
||||||
|
GetCompositeBinder(binder.Object),
|
||||||
|
Mock.Of<IValueProvider>(),
|
||||||
|
Enumerable.Empty<IModelValidatorProvider>());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(model.MyProperty);
|
||||||
|
metadataProvider.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TryUpdateModel_ReturnsFalse_IfModelValidationFails()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var binders = new IModelBinder[]
|
||||||
|
{
|
||||||
|
new TypeConverterModelBinder(),
|
||||||
|
new ComplexModelDtoModelBinder(),
|
||||||
|
new MutableObjectModelBinder()
|
||||||
|
};
|
||||||
|
|
||||||
|
var validator = new DataAnnotationsModelValidatorProvider();
|
||||||
|
var model = new MyModel();
|
||||||
|
var modelStateDictionary = new ModelStateDictionary();
|
||||||
|
var values = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "", null }
|
||||||
|
};
|
||||||
|
var valueProvider = new DictionaryBasedValueProvider(values);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await ModelBindingHelper.TryUpdateModelAsync(
|
||||||
|
model,
|
||||||
|
"",
|
||||||
|
Mock.Of<HttpContext>(),
|
||||||
|
modelStateDictionary,
|
||||||
|
new DataAnnotationsModelMetadataProvider(),
|
||||||
|
GetCompositeBinder(binders),
|
||||||
|
valueProvider,
|
||||||
|
new[] { validator });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Equal("The MyProperty field is required.",
|
||||||
|
modelStateDictionary["MyProperty"].Errors[0].ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TryUpdateModel_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 DictionaryBasedValueProvider(values);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await ModelBindingHelper.TryUpdateModelAsync(
|
||||||
|
model,
|
||||||
|
"",
|
||||||
|
Mock.Of<HttpContext>(),
|
||||||
|
modelStateDictionary,
|
||||||
|
new DataAnnotationsModelMetadataProvider(),
|
||||||
|
GetCompositeBinder(binders),
|
||||||
|
valueProvider,
|
||||||
|
new[] { validator });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Equal("MyPropertyValue", model.MyProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IModelBinder GetCompositeBinder(params IModelBinder[] binders)
|
||||||
|
{
|
||||||
|
var binderProvider = new Mock<IModelBinderProvider>();
|
||||||
|
binderProvider.SetupGet(p => p.ModelBinders)
|
||||||
|
.Returns(binders);
|
||||||
|
return new CompositeModelBinder(binderProvider.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string MyProperty { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue