Moving IModelValidatorProvider to Options

Fixes #879
This commit is contained in:
Pranav K 2014-08-20 09:33:26 -07:00
parent d77b06f742
commit d604c18368
34 changed files with 606 additions and 129 deletions

View File

@ -526,7 +526,7 @@ namespace Microsoft.AspNet.Mvc
bindingContext.MetadataProvider, bindingContext.MetadataProvider,
bindingContext.ModelBinder, bindingContext.ModelBinder,
valueProvider, valueProvider,
bindingContext.ValidatorProviders); bindingContext.ValidatorProvider);
} }
} }
} }

View File

@ -266,7 +266,7 @@ namespace Microsoft.AspNet.Mvc
ModelMetadata = modelMetadata, ModelMetadata = modelMetadata,
ModelBinder = actionBindingContext.ModelBinder, ModelBinder = actionBindingContext.ModelBinder,
ValueProvider = actionBindingContext.ValueProvider, ValueProvider = actionBindingContext.ValueProvider,
ValidatorProviders = actionBindingContext.ValidatorProviders, ValidatorProvider = actionBindingContext.ValidatorProvider,
MetadataProvider = metadataProvider, MetadataProvider = metadataProvider,
HttpContext = actionBindingContext.ActionContext.HttpContext, HttpContext = actionBindingContext.ActionContext.HttpContext,
FallbackToEmptyPrefix = true FallbackToEmptyPrefix = true

View File

@ -92,6 +92,12 @@ namespace Microsoft.AspNet.Mvc
/// </summary> /// </summary>
public List<ModelBinderDescriptor> ModelBinders { get; private set; } public List<ModelBinderDescriptor> ModelBinders { get; private set; }
/// <summary>
/// Get a list of the <see cref="IModelValidatorProvider" />s used by this application.
/// </summary>
public List<ModelValidatorProviderDescriptor> ModelValidatorProviders { get; } =
new List<ModelValidatorProviderDescriptor>();
/// <summary> /// <summary>
/// Gets a list of descriptors that represent <see cref="Rendering.IViewEngine"/> used /// Gets a list of descriptors that represent <see cref="Rendering.IViewEngine"/> used
/// by this application. /// by this application.

View File

@ -0,0 +1,37 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Mvc.OptionDescriptors
{
/// <inheritdoc />
public class DefaultModelValidatorProviderProvider : OptionDescriptorBasedProvider<IModelValidatorProvider>,
IModelValidatorProviderProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="DefaultModelValidatorProviderProvider"/> class.
/// </summary>
/// <param name="options">An accessor to the <see cref="MvcOptions"/> configured for this application.</param>
/// <param name="typeActivator">An <see cref="ITypeActivator"/> instance used to instantiate types.</param>
/// <param name="serviceProvider">A <see cref="IServiceProvider"/> instance that retrieves services from the
/// service collection.</param>
public DefaultModelValidatorProviderProvider(
IOptionsAccessor<MvcOptions> optionsAccessor,
ITypeActivator typeActivator,
IServiceProvider serviceProvider)
: base(optionsAccessor.Options.ModelValidatorProviders, typeActivator, serviceProvider)
{
}
/// <inheritdoc />
public IReadOnlyList<IModelValidatorProvider> ModelValidatorProviders
{
get { return Options; }
}
}
}

View File

@ -0,0 +1,32 @@
// 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;
using Microsoft.AspNet.Mvc.ModelBinding;
namespace Microsoft.AspNet.Mvc.OptionDescriptors
{
/// <summary>
/// Encapsulates information that describes an <see cref="IModelValidatorProvider"/>.
/// </summary>
public class ModelValidatorProviderDescriptor : OptionDescriptor<IModelValidatorProvider>
{
/// <summary>
/// Creates a new instance of <see cref="ModelValidatorProviderDescriptor"/>.
/// </summary>
/// <param name="type">A type that represents a <see cref="IModelValidatorProvider"/>.</param>
public ModelValidatorProviderDescriptor([NotNull] Type type)
: base(type)
{
}
/// <summary>
/// Creates a new instance of <see cref="ModelValidatorProviderDescriptor"/> with the specified instance.
/// </summary>
/// <param name="option">An instance of <see cref="IModelValidatorProvider"/>.</param>
public ModelValidatorProviderDescriptor([NotNull] IModelValidatorProvider validatorProvider)
: base(validatorProvider)
{
}
}
}

View File

@ -0,0 +1,94 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.OptionDescriptors;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// Extension methods for adding validator provider to a collection.
/// </summary>
public static class ModelValidatorProviderDescriptorExtensions
{
/// <summary>
/// Adds a type representing a <see cref="IModelValidatorProvider"/> to <paramref name="descriptors"/>.
/// </summary>
/// <param name="descriptors">A list of <see cref="ModelValidatorProviderDescriptor"/>.</param>
/// <param name="modelValidatorProviderType">Type representing an <see cref="IModelValidatorProvider"/></param>
/// <returns>A <see cref="ModelValidatorProviderDescriptor"/> representing the added instance.</returns>
public static ModelValidatorProviderDescriptor Add(
[NotNull] this IList<ModelValidatorProviderDescriptor> descriptors,
[NotNull] Type modelValidatorProviderType)
{
var descriptor = new ModelValidatorProviderDescriptor(modelValidatorProviderType);
descriptors.Add(descriptor);
return descriptor;
}
/// <summary>
/// Inserts a type representing a <see cref="IModelValidatorProvider"/> in to <paramref name="descriptors"/> at
/// the specified <paramref name="index"/>.
/// </summary>
/// <param name="descriptors">A list of <see cref="ModelValidatorProviderDescriptor"/>.</param>
/// <param name="index">The zero-based index at which <paramref name="modelValidatorProviderType"/>
/// should be inserted.</param>
/// <param name="modelValidatorProviderType">Type representing an <see cref="IModelValidatorProvider"/></param>
/// <returns>A <see cref="ModelValidatorProviderDescriptor"/> representing the inserted instance.</returns>
public static ModelValidatorProviderDescriptor Insert(
[NotNull] this IList<ModelValidatorProviderDescriptor> descriptors,
int index,
[NotNull] Type modelValidatorProviderType)
{
if (index < 0 || index > descriptors.Count)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
var descriptor = new ModelValidatorProviderDescriptor(modelValidatorProviderType);
descriptors.Insert(index, descriptor);
return descriptor;
}
/// <summary>
/// Adds an <see cref="IModelValidatorProvider"/> to <paramref name="descriptors"/>.
/// </summary>
/// <param name="descriptors">A list of <see cref="ModelValidatorProviderDescriptor"/>.</param>
/// <param name="modelValidatorProvider">An <see cref="IModelBinder"/> instance.</param>
/// <returns>A <see cref="ModelValidatorProviderDescriptor"/> representing the added instance.</returns>
public static ModelValidatorProviderDescriptor Add(
[NotNull] this IList<ModelValidatorProviderDescriptor> descriptors,
[NotNull] IModelValidatorProvider modelValidatorProvider)
{
var descriptor = new ModelValidatorProviderDescriptor(modelValidatorProvider);
descriptors.Add(descriptor);
return descriptor;
}
/// <summary>
/// Insert an <see cref="IModelValidatorProvider"/> in to <paramref name="descriptors"/> at the specified
/// <paramref name="index"/>.
/// </summary>
/// <param name="descriptors">A list of <see cref="ModelValidatorProviderDescriptor"/>.</param>
/// <param name="index">The zero-based index at which <paramref name="modelValidatorProvider"/>
/// should be inserted.</param>
/// <param name="modelValidatorProvider">An <see cref="IModelBinder"/> instance.</param>
/// <returns>A <see cref="ModelValidatorProviderDescriptor"/> representing the added instance.</returns>
public static ModelValidatorProviderDescriptor Insert(
[NotNull] this IList<ModelValidatorProviderDescriptor> descriptors,
int index,
[NotNull] IModelValidatorProvider modelValidatorProvider)
{
if (index < 0 || index > descriptors.Count)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
var descriptor = new ModelValidatorProviderDescriptor(modelValidatorProvider);
descriptors.Insert(index, descriptor);
return descriptor;
}
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
namespace Microsoft.AspNet.Mvc namespace Microsoft.AspNet.Mvc
@ -13,14 +12,14 @@ namespace Microsoft.AspNet.Mvc
IModelBinder modelBinder, IModelBinder modelBinder,
IValueProvider valueProvider, IValueProvider valueProvider,
IInputFormatterSelector inputFormatterSelector, IInputFormatterSelector inputFormatterSelector,
IEnumerable<IModelValidatorProvider> validatorProviders) IModelValidatorProvider validatorProvider)
{ {
ActionContext = context; ActionContext = context;
MetadataProvider = metadataProvider; MetadataProvider = metadataProvider;
ModelBinder = modelBinder; ModelBinder = modelBinder;
ValueProvider = valueProvider; ValueProvider = valueProvider;
InputFormatterSelector = inputFormatterSelector; InputFormatterSelector = inputFormatterSelector;
ValidatorProviders = validatorProviders; ValidatorProvider = validatorProvider;
} }
public ActionContext ActionContext { get; private set; } public ActionContext ActionContext { get; private set; }
@ -33,6 +32,6 @@ namespace Microsoft.AspNet.Mvc
public IInputFormatterSelector InputFormatterSelector { get; private set; } public IInputFormatterSelector InputFormatterSelector { get; private set; }
public IEnumerable<IModelValidatorProvider> ValidatorProviders { get; private set; } public IModelValidatorProvider ValidatorProvider { get; private set; }
} }
} }

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -14,20 +13,20 @@ namespace Microsoft.AspNet.Mvc
private readonly ICompositeModelBinder _compositeModelBinder; private readonly ICompositeModelBinder _compositeModelBinder;
private readonly IValueProviderFactory _compositeValueProviderFactory; private readonly IValueProviderFactory _compositeValueProviderFactory;
private readonly IInputFormatterSelector _inputFormatterSelector; private readonly IInputFormatterSelector _inputFormatterSelector;
private readonly IEnumerable<IModelValidatorProvider> _validatorProviders; private readonly ICompositeModelValidatorProvider _validatorProvider;
private Tuple<ActionContext, ActionBindingContext> _bindingContext; private Tuple<ActionContext, ActionBindingContext> _bindingContext;
public DefaultActionBindingContextProvider(IModelMetadataProvider modelMetadataProvider, public DefaultActionBindingContextProvider(IModelMetadataProvider modelMetadataProvider,
ICompositeModelBinder compositeModelBinder, ICompositeModelBinder compositeModelBinder,
ICompositeValueProviderFactory compositeValueProviderFactory, ICompositeValueProviderFactory compositeValueProviderFactory,
IInputFormatterSelector inputFormatterProvider, IInputFormatterSelector inputFormatterProvider,
IEnumerable<IModelValidatorProvider> validatorProviders) ICompositeModelValidatorProvider validatorProvider)
{ {
_modelMetadataProvider = modelMetadataProvider; _modelMetadataProvider = modelMetadataProvider;
_compositeModelBinder = compositeModelBinder; _compositeModelBinder = compositeModelBinder;
_compositeValueProviderFactory = compositeValueProviderFactory; _compositeValueProviderFactory = compositeValueProviderFactory;
_inputFormatterSelector = inputFormatterProvider; _inputFormatterSelector = inputFormatterProvider;
_validatorProviders = validatorProviders; _validatorProvider = validatorProvider;
} }
public Task<ActionBindingContext> GetActionBindingContextAsync(ActionContext actionContext) public Task<ActionBindingContext> GetActionBindingContextAsync(ActionContext actionContext)
@ -52,7 +51,7 @@ namespace Microsoft.AspNet.Mvc
_compositeModelBinder, _compositeModelBinder,
valueProvider, valueProvider,
_inputFormatterSelector, _inputFormatterSelector,
_validatorProviders); _validatorProvider);
_bindingContext = new Tuple<ActionContext, ActionBindingContext>(actionContext, context); _bindingContext = new Tuple<ActionContext, ActionBindingContext>(actionContext, context);

View File

@ -23,8 +23,8 @@ namespace Microsoft.AspNet.Mvc
/// <param name="metadataProvider">The provider used for reading metadata for the model type.</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="modelBinder">The model binder used for binding.</param>
/// <param name="valueProvider">The value provider used for looking up values.</param> /// <param name="valueProvider">The value provider used for looking up values.</param>
/// <param name="validatorProviders">The validator providers used for executing validation /// <param name="validatorProvider">The validator provider used for executing validation on the model
/// on the model instance.</param> /// instance.</param>
/// <returns>A Task with a value representing if the the update is successful.</returns> /// <returns>A Task with a value representing if the the update is successful.</returns>
public static async Task<bool> TryUpdateModelAsync<TModel>( public static async Task<bool> TryUpdateModelAsync<TModel>(
[NotNull] TModel model, [NotNull] TModel model,
@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Mvc
[NotNull] IModelMetadataProvider metadataProvider, [NotNull] IModelMetadataProvider metadataProvider,
[NotNull] IModelBinder modelBinder, [NotNull] IModelBinder modelBinder,
[NotNull] IValueProvider valueProvider, [NotNull] IValueProvider valueProvider,
[NotNull] IEnumerable<IModelValidatorProvider> validatorProviders) [NotNull] IModelValidatorProvider validatorProvider)
where TModel : class where TModel : class
{ {
var modelMetadata = metadataProvider.GetMetadataForType( var modelMetadata = metadataProvider.GetMetadataForType(
@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Mvc
ModelState = modelState, ModelState = modelState,
ModelBinder = modelBinder, ModelBinder = modelBinder,
ValueProvider = valueProvider, ValueProvider = valueProvider,
ValidatorProviders = validatorProviders, ValidatorProvider = validatorProvider,
MetadataProvider = metadataProvider, MetadataProvider = metadataProvider,
FallbackToEmptyPrefix = true, FallbackToEmptyPrefix = true,
HttpContext = httpContext HttpContext = httpContext

View File

@ -1315,13 +1315,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
string name) string name)
{ {
var actionBindingContext = _actionBindingContextProvider.GetActionBindingContextAsync(ViewContext).Result; var actionBindingContext = _actionBindingContextProvider.GetActionBindingContextAsync(ViewContext).Result;
metadata = metadata ?? metadata = metadata ?? ExpressionMetadataProvider.FromStringExpression(name, ViewData, MetadataProvider);
ExpressionMetadataProvider.FromStringExpression(name, ViewData, MetadataProvider); return actionBindingContext.ValidatorProvider
return actionBindingContext.ValidatorProviders .GetValidators(metadata)
.SelectMany(vp => vp.GetValidators(metadata)) .OfType<IClientModelValidator>()
.OfType<IClientModelValidator>() .SelectMany(v => v.GetClientValidationRules(
.SelectMany(v => v.GetClientValidationRules( new ClientModelValidationContext(metadata, MetadataProvider)));
new ClientModelValidationContext(metadata, MetadataProvider)));
} }
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null. // Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null.

View File

@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
} }
var validationContext = new ModelValidationContext(bindingContext.MetadataProvider, var validationContext = new ModelValidationContext(bindingContext.MetadataProvider,
bindingContext.ValidatorProviders, bindingContext.ValidatorProvider,
bindingContext.ModelState, bindingContext.ModelState,
bindingContext.ModelMetadata, bindingContext.ModelMetadata,
containerMetadata: null); containerMetadata: null);
@ -120,7 +120,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
ModelName = modelName, ModelName = modelName,
ModelState = oldBindingContext.ModelState, ModelState = oldBindingContext.ModelState,
ValueProvider = oldBindingContext.ValueProvider, ValueProvider = oldBindingContext.ValueProvider,
ValidatorProviders = oldBindingContext.ValidatorProviders, ValidatorProvider = oldBindingContext.ValidatorProvider,
MetadataProvider = oldBindingContext.MetadataProvider, MetadataProvider = oldBindingContext.MetadataProvider,
ModelBinder = oldBindingContext.ModelBinder, ModelBinder = oldBindingContext.ModelBinder,
HttpContext = oldBindingContext.HttpContext HttpContext = oldBindingContext.HttpContext

View File

@ -170,8 +170,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
var propertyName = property.Name; var propertyName = property.Name;
var propertyMetadata = bindingContext.PropertyMetadata[propertyName]; var propertyMetadata = bindingContext.PropertyMetadata[propertyName];
var requiredValidator = bindingContext.GetValidators(propertyMetadata) var requiredValidator = bindingContext.ValidatorProvider
.FirstOrDefault(v => v.IsRequired); .GetValidators(propertyMetadata)
.FirstOrDefault(v => v != null && v.IsRequired);
if (requiredValidator != null) if (requiredValidator != null)
{ {
validationInfo.RequiredValidators[propertyName] = requiredValidator; validationInfo.RequiredValidators[propertyName] = requiredValidator;

View File

@ -1,26 +0,0 @@
// 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.Linq;
namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
{
internal static class ModelBindingContextExtensions
{
public static IEnumerable<IModelValidator> GetValidators([NotNull] this ModelBindingContext context,
[NotNull] ModelMetadata metadata)
{
return context.ValidatorProviders.SelectMany(vp => vp.GetValidators(metadata))
.Where(v => v != null);
}
public static IEnumerable<ModelValidationResult> Validate([NotNull] this ModelBindingContext bindingContext)
{
var validators = GetValidators(bindingContext, bindingContext.ModelMetadata);
var compositeValidator = new CompositeModelValidator(validators);
var modelValidationContext = new ModelValidationContext(bindingContext, bindingContext.ModelMetadata);
return compositeValidator.Validate(modelValidationContext);
}
}
}

View File

@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
ValueProvider = bindingContext.ValueProvider; ValueProvider = bindingContext.ValueProvider;
MetadataProvider = bindingContext.MetadataProvider; MetadataProvider = bindingContext.MetadataProvider;
ModelBinder = bindingContext.ModelBinder; ModelBinder = bindingContext.ModelBinder;
ValidatorProviders = bindingContext.ValidatorProviders; ValidatorProvider = bindingContext.ValidatorProvider;
HttpContext = bindingContext.HttpContext; HttpContext = bindingContext.HttpContext;
} }
} }
@ -148,10 +148,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
public IModelMetadataProvider MetadataProvider { get; set; } public IModelMetadataProvider MetadataProvider { get; set; }
/// <summary> /// <summary>
/// Gets or sets the sequence of <see cref="IModelValidatorProvider"/> instances used for model validation /// Gets or sets the <see cref="IModelValidatorProvider"/> instance used for model validation with this
/// with this context. /// context.
/// </summary> /// </summary>
public IEnumerable<IModelValidatorProvider> ValidatorProviders { get; set; } public IModelValidatorProvider ValidatorProvider { get; set; }
/// <summary> /// <summary>
/// Gets a dictionary of property name to <see cref="ModelMetadata"/> instances for /// Gets a dictionary of property name to <see cref="ModelMetadata"/> instances for

View File

@ -0,0 +1,31 @@
// 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.Linq;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
/// <summary>
/// Default implementation for <see cref="ICompositeModelValidatorProvider"/>.
/// </summary>
public class CompositeModelValidatorProvider : ICompositeModelValidatorProvider
{
/// <summary>
/// Initializes a new instance of <see cref="CompositeModelValidatorProvider"/>.
/// </summary>
/// <param name="provider">The <see cref="IModelValidatorProviderProvider"/> instance used to get the list of
/// activated <see cref="IModelValidatorProvider"/> that this instance delegates to.</param>
public CompositeModelValidatorProvider(IModelValidatorProviderProvider provider)
{
ValidatorProviders = provider.ModelValidatorProviders;
}
public IReadOnlyList<IModelValidatorProvider> ValidatorProviders { get; private set; }
public IEnumerable<IModelValidator> GetValidators(ModelMetadata metadata)
{
return ValidatorProviders.SelectMany(v => v.GetValidators(metadata));
}
}
}

View File

@ -0,0 +1,12 @@
// 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.
namespace Microsoft.AspNet.Mvc.ModelBinding
{
/// <summary>
/// Represents aggregate of <see cref="IModelValidatorProvider"/>s that delegates to its underlying providers.
/// </summary>
public interface ICompositeModelValidatorProvider : IModelValidatorProvider
{
}
}

View File

@ -0,0 +1,18 @@
// 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;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
/// <summary>
/// Provides an activated collection of <see cref="IModelValidatorProvider"/> instances.
/// </summary>
public interface IModelValidatorProviderProvider
{
/// <summary>
/// Gets a collection of activated <see cref="IModelValidatorProvider"/> instances.
/// </summary>
IReadOnlyList<IModelValidatorProvider> ModelValidatorProviders { get; }
}
}

View File

@ -1,32 +1,30 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
namespace Microsoft.AspNet.Mvc.ModelBinding namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
public class ModelValidationContext public class ModelValidationContext
{ {
public ModelValidationContext([NotNull] ModelBindingContext bindingContext, public ModelValidationContext([NotNull] ModelBindingContext bindingContext,
[NotNull] ModelMetadata metadata) [NotNull] ModelMetadata metadata)
: this(bindingContext.MetadataProvider, : this(bindingContext.MetadataProvider,
bindingContext.ValidatorProviders, bindingContext.ValidatorProvider,
bindingContext.ModelState, bindingContext.ModelState,
metadata, metadata,
bindingContext.ModelMetadata) bindingContext.ModelMetadata)
{ {
} }
public ModelValidationContext([NotNull] IModelMetadataProvider metadataProvider, public ModelValidationContext([NotNull] IModelMetadataProvider metadataProvider,
[NotNull] IEnumerable<IModelValidatorProvider> validatorProviders, [NotNull] IModelValidatorProvider validatorProvider,
[NotNull] ModelStateDictionary modelState, [NotNull] ModelStateDictionary modelState,
[NotNull] ModelMetadata metadata, [NotNull] ModelMetadata metadata,
ModelMetadata containerMetadata) ModelMetadata containerMetadata)
{ {
ModelMetadata = metadata; ModelMetadata = metadata;
ModelState = modelState; ModelState = modelState;
MetadataProvider = metadataProvider; MetadataProvider = metadataProvider;
ValidatorProviders = validatorProviders; ValidatorProvider = validatorProvider;
ContainerMetadata = containerMetadata; ContainerMetadata = containerMetadata;
} }
@ -37,7 +35,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
ContainerMetadata = parentContext.ModelMetadata; ContainerMetadata = parentContext.ModelMetadata;
ModelState = parentContext.ModelState; ModelState = parentContext.ModelState;
MetadataProvider = parentContext.MetadataProvider; MetadataProvider = parentContext.MetadataProvider;
ValidatorProviders = parentContext.ValidatorProviders; ValidatorProvider = parentContext.ValidatorProvider;
} }
public ModelMetadata ModelMetadata { get; private set; } public ModelMetadata ModelMetadata { get; private set; }
@ -48,6 +46,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
public IModelMetadataProvider MetadataProvider { get; private set; } public IModelMetadataProvider MetadataProvider { get; private set; }
public IEnumerable<IModelValidatorProvider> ValidatorProviders { get; private set; } public IModelValidatorProvider ValidatorProvider { get; private set; }
} }
} }

View File

@ -215,7 +215,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
private static IEnumerable<IModelValidator> GetValidators(ModelValidationContext validationContext, private static IEnumerable<IModelValidator> GetValidators(ModelValidationContext validationContext,
ModelMetadata metadata) ModelMetadata metadata)
{ {
return validationContext.ValidatorProviders.SelectMany(vp => vp.GetValidators(metadata)); return validationContext.ValidatorProvider.GetValidators(metadata);
} }
} }
} }

View File

@ -1,9 +1,7 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.OptionDescriptors;
using Microsoft.AspNet.Mvc.Razor; using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.OptionsModel; using Microsoft.Framework.OptionsModel;
@ -54,6 +52,10 @@ namespace Microsoft.AspNet.Mvc
options.ValueProviderFactories.Add(new RouteValueValueProviderFactory()); options.ValueProviderFactories.Add(new RouteValueValueProviderFactory());
options.ValueProviderFactories.Add(new QueryStringValueProviderFactory()); options.ValueProviderFactories.Add(new QueryStringValueProviderFactory());
options.ValueProviderFactories.Add(new FormValueProviderFactory()); options.ValueProviderFactories.Add(new FormValueProviderFactory());
// Set up validators
options.ModelValidatorProviders.Add(new DataAnnotationsModelValidatorProvider());
options.ModelValidatorProviders.Add(new DataMemberModelValidatorProvider());
} }
} }
} }

View File

@ -81,8 +81,8 @@ namespace Microsoft.AspNet.Mvc
yield return describe.Transient<INestedProvider<FilterProviderContext>, DefaultFilterProvider>(); yield return describe.Transient<INestedProvider<FilterProviderContext>, DefaultFilterProvider>();
yield return describe.Transient<IModelValidatorProvider, DataAnnotationsModelValidatorProvider>(); yield return describe.Transient<IModelValidatorProviderProvider, DefaultModelValidatorProviderProvider>();
yield return describe.Transient<IModelValidatorProvider, DataMemberModelValidatorProvider>(); yield return describe.Scoped<ICompositeModelValidatorProvider, CompositeModelValidatorProvider>();
yield return describe.Scoped<IUrlHelper, UrlHelper>(); yield return describe.Scoped<IUrlHelper, UrlHelper>();

View File

@ -578,7 +578,7 @@ namespace Microsoft.AspNet.Mvc.Test
binder.Object, binder.Object,
valueProvider, valueProvider,
Mock.Of<IInputFormatterSelector>(), Mock.Of<IInputFormatterSelector>(),
Enumerable.Empty<IModelValidatorProvider>()); Mock.Of<IModelValidatorProvider>());
var bindingContextProvider = new Mock<IActionBindingContextProvider>(); var bindingContextProvider = new Mock<IActionBindingContextProvider>();
bindingContextProvider.Setup(b => b.GetActionBindingContextAsync(actionContext)) bindingContextProvider.Setup(b => b.GetActionBindingContextAsync(actionContext))
.Returns(Task.FromResult(bindingContext)); .Returns(Task.FromResult(bindingContext));
@ -619,7 +619,7 @@ namespace Microsoft.AspNet.Mvc.Test
binder.Object, binder.Object,
valueProvider, valueProvider,
Mock.Of<IInputFormatterSelector>(), Mock.Of<IInputFormatterSelector>(),
Enumerable.Empty<IModelValidatorProvider>()); Mock.Of<IModelValidatorProvider>());
var bindingContextProvider = new Mock<IActionBindingContextProvider>(); var bindingContextProvider = new Mock<IActionBindingContextProvider>();
bindingContextProvider.Setup(b => b.GetActionBindingContextAsync(actionContext)) bindingContextProvider.Setup(b => b.GetActionBindingContextAsync(actionContext))
.Returns(Task.FromResult(bindingContext)); .Returns(Task.FromResult(bindingContext));
@ -660,7 +660,7 @@ namespace Microsoft.AspNet.Mvc.Test
binder.Object, binder.Object,
Mock.Of<IValueProvider>(), Mock.Of<IValueProvider>(),
Mock.Of<IInputFormatterSelector>(), Mock.Of<IInputFormatterSelector>(),
Enumerable.Empty<IModelValidatorProvider>()); Mock.Of<IModelValidatorProvider>());
var bindingContextProvider = new Mock<IActionBindingContextProvider>(); var bindingContextProvider = new Mock<IActionBindingContextProvider>();
bindingContextProvider.Setup(b => b.GetActionBindingContextAsync(actionContext)) bindingContextProvider.Setup(b => b.GetActionBindingContextAsync(actionContext))
.Returns(Task.FromResult(bindingContext)); .Returns(Task.FromResult(bindingContext));

View File

@ -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;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.OptionDescriptors
{
public class DefaultValidationProviderProviderTest
{
[Fact]
public void ValidationProviders_ReturnsInstantiatedListOfValueProviders()
{
// Arrange
var service = Mock.Of<ITestService>();
var validationProvider = Mock.Of<IModelValidatorProvider>();
var type = typeof(TestModelValidationProvider);
var typeActivator = new TypeActivator();
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider.Setup(p => p.GetService(typeof(ITestService)))
.Returns(service);
var options = new MvcOptions();
options.ModelValidatorProviders.Add(type);
options.ModelValidatorProviders.Add(validationProvider);
var accessor = new Mock<IOptionsAccessor<MvcOptions>>();
accessor.SetupGet(a => a.Options)
.Returns(options);
var provider = new DefaultModelValidatorProviderProvider(accessor.Object,
typeActivator,
serviceProvider.Object);
// Act
var result = provider.ModelValidatorProviders;
// Assert
Assert.Equal(2, result.Count);
var testModelValidationProvider = Assert.IsType<TestModelValidationProvider>(result[0]);
Assert.Same(service, testModelValidationProvider.Service);
Assert.Same(validationProvider, result[1]);
}
private class TestModelValidationProvider : IModelValidatorProvider
{
public TestModelValidationProvider(ITestService service)
{
Service = service;
}
public ITestService Service { get; private set; }
public IEnumerable<IModelValidator> GetValidators(ModelMetadata metadata)
{
throw new NotImplementedException();
}
}
public interface ITestService
{
}
}
}

View File

@ -0,0 +1,63 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Testing;
using Xunit;
namespace Microsoft.AspNet.Mvc.OptionDescriptors
{
public class ModelValidatorProviderDescriptorTest
{
[Fact]
public void ConstructorThrows_IfTypeIsNotModelValidatorProvider()
{
// Arrange
var validatorProviderType = typeof(IModelValidatorProvider).FullName;
var type = typeof(string);
var expected = string.Format("The type '{0}' must derive from '{1}'.",
type.FullName, validatorProviderType);
// Act & Assert
ExceptionAssert.ThrowsArgument(() => new ModelValidatorProviderDescriptor(type), "type", expected);
}
[Fact]
public void ConstructorSetsModelValidatorProviderType()
{
// Arrange
var type = typeof(TestModelValidatorProvider);
// Act
var descriptor = new ModelValidatorProviderDescriptor(type);
// Assert
Assert.Equal(type, descriptor.OptionType);
Assert.Null(descriptor.Instance);
}
[Fact]
public void ConstructorSetsInstanceAndType()
{
// Arrange
var validatorProvider = new TestModelValidatorProvider();
// Act
var descriptor = new ModelValidatorProviderDescriptor(validatorProvider);
// Assert
Assert.Same(validatorProvider, descriptor.Instance);
Assert.Equal(validatorProvider.GetType(), descriptor.OptionType);
}
private class TestModelValidatorProvider : IModelValidatorProvider
{
public IEnumerable<IModelValidator> GetValidators(ModelMetadata metadata)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -0,0 +1,73 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.OptionDescriptors;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc
{
public class ModelValidatorProviderDescriptorExtensionsTest
{
[Theory]
[InlineData(-1)]
[InlineData(5)]
public void Insert_WithType_ThrowsIfIndexIsOutOfBounds(int index)
{
// Arrange
var collection = new List<ModelValidatorProviderDescriptor>
{
new ModelValidatorProviderDescriptor(Mock.Of<IModelValidatorProvider>()),
new ModelValidatorProviderDescriptor(Mock.Of<IModelValidatorProvider>())
};
// Act & Assert
Assert.Throws<ArgumentOutOfRangeException>("index",
() => collection.Insert(index, typeof(IModelValidatorProvider)));
}
[Theory]
[InlineData(-2)]
[InlineData(3)]
public void Insert_WithInstance_ThrowsIfIndexIsOutOfBounds(int index)
{
// Arrange
var collection = new List<ModelValidatorProviderDescriptor>
{
new ModelValidatorProviderDescriptor(Mock.Of<IModelValidatorProvider>()),
new ModelValidatorProviderDescriptor(Mock.Of<IModelValidatorProvider>())
};
var valueProviderFactory = Mock.Of<IModelValidatorProvider>();
// Act & Assert
Assert.Throws<ArgumentOutOfRangeException>("index", () => collection.Insert(index, valueProviderFactory));
}
[InlineData]
public void ModelValidatorProviderDescriptors_AddsTypesAndInstances()
{
// Arrange
var provider1 = Mock.Of<IModelValidatorProvider>();
var provider2 = Mock.Of<IModelValidatorProvider>();
var type1 = typeof(DataMemberModelValidatorProvider);
var type2 = typeof(DataAnnotationsModelValidatorProvider);
var collection = new List<ModelValidatorProviderDescriptor>();
// Act
collection.Add(provider2);
collection.Insert(0, provider1);
collection.Add(type2);
collection.Insert(2, type1);
// Assert
Assert.Equal(4, collection.Count);
Assert.Same(provider1, collection[0].Instance);
Assert.Same(provider2, collection[1].Instance);
Assert.IsType<DataMemberModelValidatorProvider>(collection[2].OptionType);
Assert.IsType<DataAnnotationsModelValidatorProvider>(collection[3].OptionType);
}
}
}

View File

@ -5,7 +5,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -39,7 +38,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
metadataProvider.Object, metadataProvider.Object,
GetCompositeBinder(binder.Object), GetCompositeBinder(binder.Object),
Mock.Of<IValueProvider>(), Mock.Of<IValueProvider>(),
Enumerable.Empty<IModelValidatorProvider>()); Mock.Of<IModelValidatorProvider>());
// Assert // Assert
Assert.False(result); Assert.False(result);
@ -76,7 +75,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
new DataAnnotationsModelMetadataProvider(), new DataAnnotationsModelMetadataProvider(),
GetCompositeBinder(binders), GetCompositeBinder(binders),
valueProvider, valueProvider,
new[] { validator }); validator);
// Assert // Assert
Assert.False(result); Assert.False(result);
@ -114,7 +113,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
new DataAnnotationsModelMetadataProvider(), new DataAnnotationsModelMetadataProvider(),
GetCompositeBinder(binders), GetCompositeBinder(binders),
valueProvider, valueProvider,
new[] { validator }); validator);
// Assert // Assert
Assert.True(result); Assert.True(result);

View File

@ -1371,7 +1371,7 @@ namespace Microsoft.AspNet.Mvc
binder.Object, binder.Object,
Mock.Of<IValueProvider>(), Mock.Of<IValueProvider>(),
Mock.Of<IInputFormatterSelector>(), Mock.Of<IInputFormatterSelector>(),
Enumerable.Empty<IModelValidatorProvider>()); Mock.Of<IModelValidatorProvider>());
var actionBindingContextProvider = new Mock<IActionBindingContextProvider>(); var actionBindingContextProvider = new Mock<IActionBindingContextProvider>();
actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny<ActionContext>())) actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny<ActionContext>()))
@ -1430,7 +1430,7 @@ namespace Microsoft.AspNet.Mvc
binder.Object, binder.Object,
Mock.Of<IValueProvider>(), Mock.Of<IValueProvider>(),
Mock.Of<IInputFormatterSelector>(), Mock.Of<IInputFormatterSelector>(),
Enumerable.Empty<IModelValidatorProvider>()); Mock.Of<IModelValidatorProvider>());
var actionBindingContextProvider = new Mock<IActionBindingContextProvider>(); var actionBindingContextProvider = new Mock<IActionBindingContextProvider>();
actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny<ActionContext>())) actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny<ActionContext>()))
@ -1481,7 +1481,7 @@ namespace Microsoft.AspNet.Mvc
Mock.Of<IModelBinder>(), Mock.Of<IModelBinder>(),
Mock.Of<IValueProvider>(), Mock.Of<IValueProvider>(),
Mock.Of<IInputFormatterSelector>(), Mock.Of<IInputFormatterSelector>(),
Enumerable.Empty<IModelValidatorProvider>()); Mock.Of<IModelValidatorProvider>());
var actionBindingContextProvider = new Mock<IActionBindingContextProvider>(); var actionBindingContextProvider = new Mock<IActionBindingContextProvider>();
actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny<ActionContext>())) actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny<ActionContext>()))
@ -1548,7 +1548,7 @@ namespace Microsoft.AspNet.Mvc
binder.Object, binder.Object,
Mock.Of<IValueProvider>(), Mock.Of<IValueProvider>(),
Mock.Of<IInputFormatterSelector>(), Mock.Of<IInputFormatterSelector>(),
Enumerable.Empty<IModelValidatorProvider>()); Mock.Of<IModelValidatorProvider>());
var actionBindingContextProvider = new Mock<IActionBindingContextProvider>(); var actionBindingContextProvider = new Mock<IActionBindingContextProvider>();
actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny<ActionContext>())) actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny<ActionContext>()))

View File

@ -93,7 +93,7 @@ namespace Microsoft.AspNet.Mvc.Core
Mock.Of<IModelBinder>(), Mock.Of<IModelBinder>(),
Mock.Of<IValueProvider>(), Mock.Of<IValueProvider>(),
Mock.Of<IInputFormatterSelector>(), Mock.Of<IInputFormatterSelector>(),
Enumerable.Empty<IModelValidatorProvider>()); Mock.Of<IModelValidatorProvider>());
var urlHelper = Mock.Of<IUrlHelper>(); var urlHelper = Mock.Of<IUrlHelper>();
var actionBindingContextProvider = new Mock<IActionBindingContextProvider>(); var actionBindingContextProvider = new Mock<IActionBindingContextProvider>();
actionBindingContextProvider actionBindingContextProvider

View File

@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
{ "someName", "dummyValue" } { "someName", "dummyValue" }
}, },
ValidatorProviders = Enumerable.Empty<IModelValidatorProvider>() ValidatorProvider = GetValidatorProvider()
}; };
var mockIntBinder = new Mock<IModelBinder>(); var mockIntBinder = new Mock<IModelBinder>();
@ -78,14 +78,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
{ "someOtherName", "dummyValue" } { "someOtherName", "dummyValue" }
}, },
ValidatorProviders = Enumerable.Empty<IModelValidatorProvider>() ValidatorProvider = GetValidatorProvider()
}; };
var mockIntBinder = new Mock<IModelBinder>(); var mockIntBinder = new Mock<IModelBinder>();
mockIntBinder mockIntBinder
.Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns( .Returns(
delegate(ModelBindingContext mbc) delegate (ModelBindingContext mbc)
{ {
if (!string.IsNullOrEmpty(mbc.ModelName)) if (!string.IsNullOrEmpty(mbc.ModelName))
{ {
@ -122,7 +122,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
.Returns(Task.FromResult(false)) .Returns(Task.FromResult(false))
.Verifiable(); .Verifiable();
var shimBinder = (IModelBinder)mockListBinder.Object; var shimBinder = mockListBinder.Object;
var bindingContext = new ModelBindingContext var bindingContext = new ModelBindingContext
{ {
@ -233,7 +233,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ "user.password", "password-val" }, { "user.password", "password-val" },
{ "user.confirmpassword", "not-password-val" }, { "user.confirmpassword", "not-password-val" },
}; };
var bindingContext = CreateBindingContext(binder, valueProvider, typeof(User), new[] { validatorProvider }); var bindingContext = CreateBindingContext(binder, valueProvider, typeof(User), validatorProvider);
bindingContext.ModelName = "user"; bindingContext.ModelName = "user";
// Act // Act
@ -255,7 +255,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ "user.password", "password" }, { "user.password", "password" },
{ "user.confirmpassword", "password" }, { "user.confirmpassword", "password" },
}; };
var bindingContext = CreateBindingContext(binder, valueProvider, typeof(User), new[] { validatorProvider }); var bindingContext = CreateBindingContext(binder, valueProvider, typeof(User), validatorProvider);
bindingContext.ModelName = "user"; bindingContext.ModelName = "user";
// Act // Act
@ -269,9 +269,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
private static ModelBindingContext CreateBindingContext(IModelBinder binder, private static ModelBindingContext CreateBindingContext(IModelBinder binder,
IValueProvider valueProvider, IValueProvider valueProvider,
Type type, Type type,
IEnumerable<IModelValidatorProvider> validatorProviders = null) IModelValidatorProvider validatorProvider = null)
{ {
validatorProviders = validatorProviders ?? Enumerable.Empty<IModelValidatorProvider>(); validatorProvider = validatorProvider ?? GetValidatorProvider();
var metadataProvider = new DataAnnotationsModelMetadataProvider(); var metadataProvider = new DataAnnotationsModelMetadataProvider();
var bindingContext = new ModelBindingContext var bindingContext = new ModelBindingContext
{ {
@ -281,7 +281,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
ModelMetadata = metadataProvider.GetMetadataForType(null, type), ModelMetadata = metadataProvider.GetMetadataForType(null, type),
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
ValueProvider = valueProvider, ValueProvider = valueProvider,
ValidatorProviders = validatorProviders ValidatorProvider = validatorProvider
}; };
return bindingContext; return bindingContext;
} }
@ -293,8 +293,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
typeActivator typeActivator
.Setup(t => t.CreateInstance(serviceProvider, It.IsAny<Type>(), It.IsAny<object[]>())) .Setup(t => t.CreateInstance(serviceProvider, It.IsAny<Type>(), It.IsAny<object[]>()))
.Returns((IServiceProvider sp, Type t, object[] args) => Activator.CreateInstance(t)); .Returns((IServiceProvider sp, Type t, object[] args) => Activator.CreateInstance(t));
var binders = new IModelBinder[] var binders = new IModelBinder[]
{ {
new TypeMatchModelBinder(), new TypeMatchModelBinder(),
new ByteArrayModelBinder(), new ByteArrayModelBinder(),
new GenericModelBinder(serviceProvider, typeActivator.Object), new GenericModelBinder(serviceProvider, typeActivator.Object),
@ -319,6 +319,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
return shimBinder; return shimBinder;
} }
private static IModelValidatorProvider GetValidatorProvider(params IModelValidator[] validators)
{
var provider = new Mock<IModelValidatorProvider>();
provider.Setup(v => v.GetValidators(It.IsAny<ModelMetadata>()))
.Returns(validators ?? Enumerable.Empty<IModelValidator>());
return provider.Object;
}
private class SimplePropertiesModel private class SimplePropertiesModel
{ {
public string FirstName { get; set; } public string FirstName { get; set; }

View File

@ -122,7 +122,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
ValueProvider = valueProvider, ValueProvider = valueProvider,
ModelBinder = innerBinder ?? CreateIntBinder(), ModelBinder = innerBinder ?? CreateIntBinder(),
MetadataProvider = metataProvider, MetadataProvider = metataProvider,
ValidatorProviders = Enumerable.Empty<IModelValidatorProvider>() ValidatorProvider = Mock.Of<IModelValidatorProvider>()
}; };
return bindingContext; return bindingContext;
} }

View File

@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
ValueProvider = mockValueProvider.Object, ValueProvider = mockValueProvider.Object,
ModelBinder = mockDtoBinder.Object, ModelBinder = mockDtoBinder.Object,
MetadataProvider = new DataAnnotationsModelMetadataProvider(), MetadataProvider = new DataAnnotationsModelMetadataProvider(),
ValidatorProviders = Enumerable.Empty<IModelValidatorProvider>() ValidatorProvider = Mock.Of<IModelValidatorProvider>()
}; };
mockDtoBinder mockDtoBinder
@ -194,7 +194,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var bindingContext = new ModelBindingContext var bindingContext = new ModelBindingContext
{ {
ModelMetadata = GetMetadataForType(typeof(PersonWithBindExclusion)), ModelMetadata = GetMetadataForType(typeof(PersonWithBindExclusion)),
ValidatorProviders = Enumerable.Empty<IModelValidatorProvider>() ValidatorProvider = Mock.Of<IModelValidatorProvider>()
}; };
var testableBinder = new TestableMutableObjectModelBinder(); var testableBinder = new TestableMutableObjectModelBinder();
@ -215,7 +215,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var bindingContext = new ModelBindingContext var bindingContext = new ModelBindingContext
{ {
ModelMetadata = GetMetadataForType(typeof(Person)), ModelMetadata = GetMetadataForType(typeof(Person)),
ValidatorProviders = Enumerable.Empty<IModelValidatorProvider>() ValidatorProvider = Mock.Of<IModelValidatorProvider>()
}; };
var testableBinder = new TestableMutableObjectModelBinder(); var testableBinder = new TestableMutableObjectModelBinder();
@ -235,7 +235,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var bindingContext = new ModelBindingContext var bindingContext = new ModelBindingContext
{ {
ModelMetadata = GetMetadataForObject(new ModelWithMixedBindingBehaviors()), ModelMetadata = GetMetadataForObject(new ModelWithMixedBindingBehaviors()),
ValidatorProviders = Enumerable.Empty<IModelValidatorProvider>() ValidatorProvider = Mock.Of<IModelValidatorProvider>()
}; };
// Act // Act
@ -256,7 +256,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var modelMetadata = GetMetadataForType(typeof(Person)); var modelMetadata = GetMetadataForType(typeof(Person));
var validationNode = new ModelValidationNode(modelMetadata, "foo"); var validationNode = new ModelValidationNode(modelMetadata, "foo");
var validationContext = new ModelValidationContext(new DataAnnotationsModelMetadataProvider(), var validationContext = new ModelValidationContext(new DataAnnotationsModelMetadataProvider(),
Enumerable.Empty<IModelValidatorProvider>(), Mock.Of<IModelValidatorProvider>(),
modelState, modelState,
modelMetadata, modelMetadata,
null); null);
@ -278,7 +278,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var modelMetadata = GetMetadataForType(typeof(Person)); var modelMetadata = GetMetadataForType(typeof(Person));
var validationNode = new ModelValidationNode(modelMetadata, "foo"); var validationNode = new ModelValidationNode(modelMetadata, "foo");
var validationContext = new ModelValidationContext(new DataAnnotationsModelMetadataProvider(), var validationContext = new ModelValidationContext(new DataAnnotationsModelMetadataProvider(),
Enumerable.Empty<IModelValidatorProvider>(), Mock.Of<IModelValidatorProvider>(),
modelState, modelState,
modelMetadata, modelMetadata,
null); null);
@ -309,7 +309,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
ModelMetadata = containerMetadata, ModelMetadata = containerMetadata,
ModelName = "theModel", ModelName = "theModel",
ValidatorProviders = Enumerable.Empty<IModelValidatorProvider>() ValidatorProvider = Mock.Of<IModelValidatorProvider>()
}; };
var dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties); var dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties);
@ -354,10 +354,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
ModelMetadata = containerMetadata, ModelMetadata = containerMetadata,
ModelName = "theModel", ModelName = "theModel",
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
ValidatorProviders = Enumerable.Empty<IModelValidatorProvider>() ValidatorProvider = Mock.Of<IModelValidatorProvider>()
}; };
var validationContext = new ModelValidationContext(new EmptyModelMetadataProvider(), var validationContext = new ModelValidationContext(new EmptyModelMetadataProvider(),
bindingContext.ValidatorProviders, bindingContext.ValidatorProvider,
bindingContext.ModelState, bindingContext.ModelState,
containerMetadata, containerMetadata,
null); null);
@ -590,10 +590,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var propertyMetadata = bindingContext.ModelMetadata.Properties.First(o => o.PropertyName == "PropertyWithDefaultValue"); var propertyMetadata = bindingContext.ModelMetadata.Properties.First(o => o.PropertyName == "PropertyWithDefaultValue");
var validationNode = new ModelValidationNode(propertyMetadata, "foo"); var validationNode = new ModelValidationNode(propertyMetadata, "foo");
var dtoResult = new ComplexModelDtoResult(model: null, validationNode: validationNode); var dtoResult = new ComplexModelDtoResult(model: null, validationNode: validationNode);
var requiredValidator = bindingContext.ValidatorProviders var requiredValidator = bindingContext.ValidatorProvider
.SelectMany(v => v.GetValidators(propertyMetadata)) .GetValidators(propertyMetadata)
.Where(v => v.IsRequired) .FirstOrDefault(v => v.IsRequired);
.FirstOrDefault();
var testableBinder = new TestableMutableObjectModelBinder(); var testableBinder = new TestableMutableObjectModelBinder();
@ -634,10 +633,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth"); var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth");
var validationNode = new ModelValidationNode(propertyMetadata, "foo"); var validationNode = new ModelValidationNode(propertyMetadata, "foo");
var dtoResult = new ComplexModelDtoResult(new DateTime(2001, 1, 1), validationNode); var dtoResult = new ComplexModelDtoResult(new DateTime(2001, 1, 1), validationNode);
var requiredValidator = bindingContext.ValidatorProviders var requiredValidator = bindingContext.ValidatorProvider
.SelectMany(v => v.GetValidators(propertyMetadata)) .GetValidators(propertyMetadata)
.Where(v => v.IsRequired) .FirstOrDefault(v => v.IsRequired);
.FirstOrDefault();
var validationContext = new ModelValidationContext(bindingContext, propertyMetadata); var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);
var testableBinder = new TestableMutableObjectModelBinder(); var testableBinder = new TestableMutableObjectModelBinder();
@ -769,42 +767,45 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
private static ModelBindingContext CreateContext(ModelMetadata metadata) private static ModelBindingContext CreateContext(ModelMetadata metadata)
{ {
var provider = new Mock<IModelValidatorProviderProvider>();
provider.SetupGet(p => p.ModelValidatorProviders)
.Returns(new IModelValidatorProvider[]
{
new DataAnnotationsModelValidatorProvider(),
new DataMemberModelValidatorProvider()
});
return new ModelBindingContext return new ModelBindingContext
{ {
ModelState = new ModelStateDictionary(), ModelState = new ModelStateDictionary(),
ModelMetadata = metadata, ModelMetadata = metadata,
ModelName = "theModel", ModelName = "theModel",
ValidatorProviders = new IModelValidatorProvider[] ValidatorProvider = new CompositeModelValidatorProvider(provider.Object)
{
new DataAnnotationsModelValidatorProvider(),
new DataMemberModelValidatorProvider()
}
}; };
} }
private static IModelValidator GetRequiredValidator(ModelBindingContext bindingContext, ModelMetadata propertyMetadata) private static IModelValidator GetRequiredValidator(ModelBindingContext bindingContext, ModelMetadata propertyMetadata)
{ {
return bindingContext.ValidatorProviders return bindingContext.ValidatorProvider
.SelectMany(v => v.GetValidators(propertyMetadata)) .GetValidators(propertyMetadata)
.Where(v => v.IsRequired) .FirstOrDefault(v => v.IsRequired);
.FirstOrDefault();
} }
private static ModelMetadata GetMetadataForCanUpdateProperty(string propertyName) private static ModelMetadata GetMetadataForCanUpdateProperty(string propertyName)
{ {
DataAnnotationsModelMetadataProvider metadataProvider = new DataAnnotationsModelMetadataProvider(); var metadataProvider = new DataAnnotationsModelMetadataProvider();
return metadataProvider.GetMetadataForProperty(null, typeof(MyModelTestingCanUpdateProperty), propertyName); return metadataProvider.GetMetadataForProperty(null, typeof(MyModelTestingCanUpdateProperty), propertyName);
} }
private static ModelMetadata GetMetadataForObject(object o) private static ModelMetadata GetMetadataForObject(object o)
{ {
DataAnnotationsModelMetadataProvider metadataProvider = new DataAnnotationsModelMetadataProvider(); var metadataProvider = new DataAnnotationsModelMetadataProvider();
return metadataProvider.GetMetadataForType(() => o, o.GetType()); return metadataProvider.GetMetadataForType(() => o, o.GetType());
} }
private static ModelMetadata GetMetadataForType(Type t) private static ModelMetadata GetMetadataForType(Type t)
{ {
DataAnnotationsModelMetadataProvider metadataProvider = new DataAnnotationsModelMetadataProvider(); var metadataProvider = new DataAnnotationsModelMetadataProvider();
return metadataProvider.GetMetadataForType(null, t); return metadataProvider.GetMetadataForType(null, t);
} }

View File

@ -0,0 +1,41 @@
// 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 Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{
public class CompositeModelValidatorProviderTest
{
[Fact]
public void GetModelValidators_ReturnsValidatorsFromAllProviders()
{
// Arrange
var validator1 = Mock.Of<IModelValidator>();
var validator2 = Mock.Of<IModelValidator>();
var validator3 = Mock.Of<IModelValidator>();
var provider1 = new Mock<IModelValidatorProvider>();
provider1.Setup(p => p.GetValidators(It.IsAny<ModelMetadata>()))
.Returns(new[] { validator1, validator2 });
var provider2 = new Mock<IModelValidatorProvider>();
provider2.Setup(p => p.GetValidators(It.IsAny<ModelMetadata>()))
.Returns(new[] { validator3 });
var providerProvider = new Mock<IModelValidatorProviderProvider>();
providerProvider.Setup(p => p.ModelValidatorProviders)
.Returns(new[] { provider1.Object, provider2.Object });
var compositeModelValidator = new CompositeModelValidatorProvider(providerProvider.Object);
var modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(
modelAccessor: null,
modelType: typeof(string));
// Act
var result = compositeModelValidator.GetValidators(modelMetadata);
// Assert
Assert.Equal(new[] { validator1, validator2, validator3 }, result);
}
}
}
#endif

View File

@ -1,10 +1,12 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using Microsoft.AspNet.Testing; using Microsoft.AspNet.Testing;
using Moq;
using Xunit; using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding namespace Microsoft.AspNet.Mvc.ModelBinding
@ -294,8 +296,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
new DataMemberModelValidatorProvider() new DataMemberModelValidatorProvider()
}; };
var provider = new Mock<IModelValidatorProviderProvider>();
provider.SetupGet(p => p.ModelValidatorProviders)
.Returns(providers);
return new ModelValidationContext(new EmptyModelMetadataProvider(), return new ModelValidationContext(new EmptyModelMetadataProvider(),
providers, new CompositeModelValidatorProvider(provider.Object),
new ModelStateDictionary(), new ModelStateDictionary(),
metadata, metadata,
null); null);
@ -343,4 +349,5 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
public string ValidString { get; set; } public string ValidString { get; set; }
} }
} }
} }
#endif

View File

@ -97,5 +97,21 @@ namespace Microsoft.AspNet.Mvc
Assert.IsType<XmlSerializerInputFormatter>(mvcOptions.InputFormatters[1].Instance); Assert.IsType<XmlSerializerInputFormatter>(mvcOptions.InputFormatters[1].Instance);
Assert.IsType<XmlDataContractSerializerInputFormatter>(mvcOptions.InputFormatters[2].Instance); Assert.IsType<XmlDataContractSerializerInputFormatter>(mvcOptions.InputFormatters[2].Instance);
} }
[Fact]
public void Setup_SetsUpModelValidatorProviders()
{
// Arrange
var mvcOptions = new MvcOptions();
var setup = new MvcOptionsSetup();
// Act
setup.Setup(mvcOptions);
// Assert
Assert.Equal(2, mvcOptions.ModelValidatorProviders.Count);
Assert.IsType<DataAnnotationsModelValidatorProvider>(mvcOptions.ModelValidatorProviders[0].Instance);
Assert.IsType<DataMemberModelValidatorProvider>(mvcOptions.ModelValidatorProviders[1].Instance);
}
} }
} }