Simplify BindAttribute - rename PredicateProvider

This change renames IPropertyBindingPredicateProvider to
IPropertyFilterProvider. The changes here are mostly renames of
parameters/variables from predicate -> propertyFilter. I did a
find+replace and left the term 'predicate' in some of the docs because it
refers to a predicate in the abstract sense.

This change also simplifies BindAttribute and removes support for type
activation.
This commit is contained in:
Ryan Nowak 2016-03-24 15:10:35 -07:00
Родитель 1bd66ffda0
Коммит 144766f2e3
24 изменённых файлов: 222 добавлений и 463 удалений

Просмотреть файл

@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
BindingSource = other.BindingSource;
BinderModelName = other.BinderModelName;
BinderType = other.BinderType;
PropertyBindingPredicateProvider = other.PropertyBindingPredicateProvider;
PropertyFilterProvider = other.PropertyFilterProvider;
}
/// <summary>
@ -52,9 +52,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public Type BinderType { get; set; }
/// <summary>
/// Gets or sets the <see cref="ModelBinding.IPropertyBindingPredicateProvider"/>.
/// Gets or sets the <see cref="ModelBinding.IPropertyFilterProvider"/>.
/// </summary>
public IPropertyBindingPredicateProvider PropertyBindingPredicateProvider { get; set; }
public IPropertyFilterProvider PropertyFilterProvider { get; set; }
/// <summary>
/// Constructs a new instance of <see cref="BindingInfo"/> from the given <paramref name="attributes"/>.
@ -100,46 +100,50 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
}
// PropertyBindingPredicateProvider
var predicateProviders = attributes.OfType<IPropertyBindingPredicateProvider>().ToArray();
if (predicateProviders.Length > 0)
// PropertyFilterProvider
var propertyFilterProviders = attributes.OfType<IPropertyFilterProvider>().ToArray();
if (propertyFilterProviders.Length == 1)
{
isBindingInfoPresent = true;
bindingInfo.PropertyBindingPredicateProvider = new CompositePredicateProvider(
predicateProviders);
bindingInfo.PropertyFilterProvider = propertyFilterProviders[0];
}
else if (propertyFilterProviders.Length > 1)
{
isBindingInfoPresent = true;
bindingInfo.PropertyFilterProvider = new CompositePropertyFilterProvider(propertyFilterProviders);
}
return isBindingInfoPresent ? bindingInfo : null;
}
private class CompositePredicateProvider : IPropertyBindingPredicateProvider
private class CompositePropertyFilterProvider : IPropertyFilterProvider
{
private readonly IEnumerable<IPropertyBindingPredicateProvider> _providers;
private readonly IEnumerable<IPropertyFilterProvider> _providers;
public CompositePredicateProvider(IEnumerable<IPropertyBindingPredicateProvider> providers)
public CompositePropertyFilterProvider(IEnumerable<IPropertyFilterProvider> providers)
{
_providers = providers;
}
public Func<ModelBindingContext, string, bool> PropertyFilter
public Func<ModelMetadata, bool> PropertyFilter
{
get
{
return CreatePredicate();
return CreatePropertyFilter();
}
}
private Func<ModelBindingContext, string, bool> CreatePredicate()
private Func<ModelMetadata, bool> CreatePropertyFilter()
{
var predicates = _providers
var propertyFilters = _providers
.Select(p => p.PropertyFilter)
.Where(p => p != null);
return (context, propertyName) =>
return (m) =>
{
foreach (var predicate in predicates)
foreach (var propertyFilter in propertyFilters)
{
if (!predicate(context, propertyName))
if (!propertyFilter(m))
{
return false;
}

Просмотреть файл

@ -8,11 +8,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// <summary>
/// Provides a predicate which can determines which model properties should be bound by model binding.
/// </summary>
public interface IPropertyBindingPredicateProvider
public interface IPropertyFilterProvider
{
/// <summary>
/// Gets a predicate which can determines which model properties should be bound by model binding.
/// </summary>
Func<ModelBindingContext, string, bool> PropertyFilter { get; }
Func<ModelMetadata, bool> PropertyFilter { get; }
}
}

Просмотреть файл

@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// Gets or sets a predicate which will be evaluated for each property to determine if the property
/// is eligible for model binding.
/// </summary>
public abstract Func<ModelBindingContext, string, bool> PropertyFilter { get; set; }
public abstract Func<ModelMetadata, bool> PropertyFilter { get; set; }
/// <summary>
/// Gets or sets the <see cref="ValidationStateDictionary"/>. Used for tracking validation state to

Просмотреть файл

@ -269,10 +269,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public abstract string NullDisplayText { get; }
/// <summary>
/// Gets the <see cref="IPropertyBindingPredicateProvider"/>, which can determine which properties
/// Gets the <see cref="IPropertyFilterProvider"/>, which can determine which properties
/// should be model bound.
/// </summary>
public abstract IPropertyBindingPredicateProvider PropertyBindingPredicateProvider { get; }
public abstract IPropertyFilterProvider PropertyFilterProvider { get; }
/// <summary>
/// Gets a value that indicates whether the property should be displayed in read-only views.

Просмотреть файл

@ -7,9 +7,7 @@ using System.Linq;
#if NETSTANDARD1_5
using System.Reflection;
#endif
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Mvc
{
@ -17,14 +15,11 @@ namespace Microsoft.AspNetCore.Mvc
/// This attribute can be used on action parameters and types, to indicate model level metadata.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class BindAttribute : Attribute, IModelNameProvider, IPropertyBindingPredicateProvider
public class BindAttribute : Attribute, IModelNameProvider, IPropertyFilterProvider
{
private static readonly Func<ModelBindingContext, string, bool> _defaultFilter =
(context, propertyName) => true;
private static readonly Func<ModelMetadata, bool> _default = (m) => true;
private ObjectFactory _factory;
private Func<ModelBindingContext, string, bool> _predicateFromInclude;
private Func<ModelMetadata, bool> _propertyFilter;
/// <summary>
/// Creates a new instace of <see cref="BindAttribute"/>.
@ -41,33 +36,6 @@ namespace Microsoft.AspNetCore.Mvc
Include = items.ToArray();
}
/// <summary>
/// Creates a new instance of <see cref="BindAttribute"/>.
/// </summary>
/// <param name="predicateProviderType">The type which implements
/// <see cref="IPropertyBindingPredicateProvider"/>.
/// </param>
public BindAttribute(Type predicateProviderType)
{
if (predicateProviderType == null)
{
throw new ArgumentNullException(nameof(predicateProviderType));
}
if (!typeof(IPropertyBindingPredicateProvider).IsAssignableFrom(predicateProviderType))
{
var message = Resources.FormatPropertyBindingPredicateProvider_WrongType(
predicateProviderType.FullName,
typeof(IPropertyBindingPredicateProvider).FullName);
throw new ArgumentException(message, nameof(predicateProviderType));
}
PredicateProviderType = predicateProviderType;
}
/// <inheritdoc />
public Type PredicateProviderType { get; }
/// <summary>
/// Gets the names of properties to include in model binding.
/// </summary>
@ -91,64 +59,26 @@ namespace Microsoft.AspNetCore.Mvc
}
/// <inheritdoc />
public Func<ModelBindingContext, string, bool> PropertyFilter
public Func<ModelMetadata, bool> PropertyFilter
{
get
{
if (PredicateProviderType != null)
if (Include != null && Include.Length > 0)
{
var factory = GetFactory();
return CreatePredicateFromProviderType(factory);
}
else if (Include != null && Include.Length > 0)
{
if (_predicateFromInclude == null)
if (_propertyFilter == null)
{
_predicateFromInclude =
(context, propertyName) => Include.Contains(propertyName, StringComparer.Ordinal);
_propertyFilter = (m) => Include.Contains(m.PropertyName, StringComparer.Ordinal);
}
return _predicateFromInclude;
return _propertyFilter;
}
else
{
return _defaultFilter;
return _default;
}
}
}
private ObjectFactory GetFactory()
{
if (_factory == null)
{
_factory = ActivatorUtilities.CreateFactory(PredicateProviderType, Type.EmptyTypes);
}
return _factory;
}
private static Func<ModelBindingContext, string, bool> CreatePredicateFromProviderType(
ObjectFactory factory)
{
// Holding state to avoid execessive creation of the provider.
var initialized = false;
Func<ModelBindingContext, string, bool> predicate = null;
return (ModelBindingContext context, string propertyName) =>
{
if (!initialized)
{
var services = context.OperationBindingContext.HttpContext.RequestServices;
var provider = (IPropertyBindingPredicateProvider)factory(services, arguments: null);
initialized = true;
predicate = provider.PropertyFilter ?? _defaultFilter;
}
return predicate(context, propertyName);
};
}
private static IEnumerable<string> SplitString(string original)
{
if (string.IsNullOrEmpty(original))

Просмотреть файл

@ -1222,13 +1222,13 @@ namespace Microsoft.AspNetCore.Mvc
/// <param name="model">The model instance to update.</param>
/// <param name="prefix">The prefix to use when looking up values in the current <see cref="IValueProvider"/>.
/// </param>
/// <param name="predicate">A predicate which can be used to filter properties at runtime.</param>
/// <param name="propertyFilter">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 Task<bool> TryUpdateModelAsync<TModel>(
TModel model,
string prefix,
Func<ModelBindingContext, string, bool> predicate)
Func<ModelMetadata, bool> propertyFilter)
where TModel : class
{
if (model == null)
@ -1236,9 +1236,9 @@ namespace Microsoft.AspNetCore.Mvc
throw new ArgumentNullException(nameof(model));
}
if (predicate == null)
if (propertyFilter == null)
{
throw new ArgumentNullException(nameof(predicate));
throw new ArgumentNullException(nameof(propertyFilter));
}
return ModelBindingHelper.TryUpdateModelAsync(
@ -1251,7 +1251,7 @@ namespace Microsoft.AspNetCore.Mvc
ControllerContext.InputFormatters,
ObjectValidator,
new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders),
predicate);
propertyFilter);
}
/// <summary>
@ -1311,14 +1311,14 @@ namespace Microsoft.AspNetCore.Mvc
/// <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>
/// <param name="propertyFilter">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 Task<bool> TryUpdateModelAsync<TModel>(
TModel model,
string prefix,
IValueProvider valueProvider,
Func<ModelBindingContext, string, bool> predicate)
Func<ModelMetadata, bool> propertyFilter)
where TModel : class
{
if (model == null)
@ -1331,9 +1331,9 @@ namespace Microsoft.AspNetCore.Mvc
throw new ArgumentNullException(nameof(valueProvider));
}
if (predicate == null)
if (propertyFilter == null)
{
throw new ArgumentNullException(nameof(predicate));
throw new ArgumentNullException(nameof(propertyFilter));
}
return ModelBindingHelper.TryUpdateModelAsync(
@ -1346,7 +1346,7 @@ namespace Microsoft.AspNetCore.Mvc
ControllerContext.InputFormatters,
ObjectValidator,
new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders),
predicate);
propertyFilter);
}
/// <summary>
@ -1396,7 +1396,7 @@ namespace Microsoft.AspNetCore.Mvc
/// <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>
/// <param name="propertyFilter">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 Task<bool> TryUpdateModelAsync(
@ -1404,7 +1404,7 @@ namespace Microsoft.AspNetCore.Mvc
Type modelType,
string prefix,
IValueProvider valueProvider,
Func<ModelBindingContext, string, bool> predicate)
Func<ModelMetadata, bool> propertyFilter)
{
if (model == null)
{
@ -1421,9 +1421,9 @@ namespace Microsoft.AspNetCore.Mvc
throw new ArgumentNullException(nameof(valueProvider));
}
if (predicate == null)
if (propertyFilter == null)
{
throw new ArgumentNullException(nameof(predicate));
throw new ArgumentNullException(nameof(propertyFilter));
}
return ModelBindingHelper.TryUpdateModelAsync(
@ -1437,7 +1437,7 @@ namespace Microsoft.AspNetCore.Mvc
ControllerContext.InputFormatters,
ObjectValidator,
new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders),
predicate);
propertyFilter);
}
/// <summary>

Просмотреть файл

@ -69,20 +69,20 @@ namespace Microsoft.AspNetCore.Mvc.Internal
// Provide a unique instance based on one passed to the constructor.
context.BindingMetadata.ModelBindingMessageProvider = new ModelBindingMessageProvider(_messageProvider);
// PropertyBindingPredicateProvider
var predicateProviders = context.Attributes.OfType<IPropertyBindingPredicateProvider>().ToArray();
if (predicateProviders.Length == 0)
// PropertyFilterProvider
var propertyFilterProviders = context.Attributes.OfType<IPropertyFilterProvider>().ToArray();
if (propertyFilterProviders.Length == 0)
{
context.BindingMetadata.PropertyBindingPredicateProvider = null;
context.BindingMetadata.PropertyFilterProvider = null;
}
else if (predicateProviders.Length == 1)
else if (propertyFilterProviders.Length == 1)
{
context.BindingMetadata.PropertyBindingPredicateProvider = predicateProviders[0];
context.BindingMetadata.PropertyFilterProvider = propertyFilterProviders[0];
}
else
{
context.BindingMetadata.PropertyBindingPredicateProvider = new CompositePredicateProvider(
predicateProviders);
var composite = new CompositePropertyFilterProvider(propertyFilterProviders);
context.BindingMetadata.PropertyFilterProvider = composite;
}
if (context.Key.MetadataKind == ModelMetadataKind.Property)
@ -107,34 +107,34 @@ namespace Microsoft.AspNetCore.Mvc.Internal
}
}
private class CompositePredicateProvider : IPropertyBindingPredicateProvider
private class CompositePropertyFilterProvider : IPropertyFilterProvider
{
private readonly IEnumerable<IPropertyBindingPredicateProvider> _providers;
private readonly IEnumerable<IPropertyFilterProvider> _providers;
public CompositePredicateProvider(IEnumerable<IPropertyBindingPredicateProvider> providers)
public CompositePropertyFilterProvider(IEnumerable<IPropertyFilterProvider> providers)
{
_providers = providers;
}
public Func<ModelBindingContext, string, bool> PropertyFilter
public Func<ModelMetadata, bool> PropertyFilter
{
get
{
return CreatePredicate();
return CreatePropertyFilter();
}
}
private Func<ModelBindingContext, string, bool> CreatePredicate()
private Func<ModelMetadata, bool> CreatePropertyFilter()
{
var predicates = _providers
var propertyFilters = _providers
.Select(p => p.PropertyFilter)
.Where(p => p != null);
return (context, propertyName) =>
return (m) =>
{
foreach (var predicate in predicates)
foreach (var propertyFilter in propertyFilters)
{
if (!predicate(context, propertyName))
if (!propertyFilter(m))
{
return false;
}

Просмотреть файл

@ -56,8 +56,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
var binderModelName = bindingInfo?.BinderModelName ?? metadata.BinderModelName;
var propertyPredicateProvider =
bindingInfo?.PropertyBindingPredicateProvider ?? metadata.PropertyBindingPredicateProvider;
var propertyFilterProvider = bindingInfo?.PropertyFilterProvider ?? metadata.PropertyFilterProvider;
var valueProvider = operationBindingContext.ValueProvider;
var bindingSource = bindingInfo?.BindingSource ?? metadata.BindingSource;
@ -70,7 +69,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
BinderModelName = binderModelName,
BindingSource = bindingSource,
PropertyFilter = propertyPredicateProvider?.PropertyFilter,
PropertyFilter = propertyFilterProvider?.PropertyFilter,
// Because this is the top-level context, FieldName and ModelName should be the same.
FieldName = binderModelName ?? modelName,
@ -123,7 +122,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
FieldName = fieldName;
BinderModelName = modelMetadata.BinderModelName;
BindingSource = modelMetadata.BindingSource;
PropertyFilter = modelMetadata.PropertyBindingPredicateProvider?.PropertyFilter;
PropertyFilter = modelMetadata.PropertyFilterProvider?.PropertyFilter;
IsTopLevelObject = false;
@ -262,7 +261,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
/// <inheritdoc />
public override Func<ModelBindingContext, string, bool> PropertyFilter
public override Func<ModelMetadata, bool> PropertyFilter
{
get { return _state.PropertyFilter; }
set { _state.PropertyFilter = value; }
@ -317,7 +316,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public string ModelName;
public IValueProvider ValueProvider;
public Func<ModelBindingContext, string, bool> PropertyFilter;
public Func<ModelMetadata, bool> PropertyFilter;
public ValidationStateDictionary ValidationState;
public ModelStateDictionary ModelState;

Просмотреть файл

@ -114,13 +114,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
/// <returns><c>true</c> if the model property can be bound, otherwise <c>false</c>.</returns>
protected virtual bool CanBindProperty(ModelBindingContext bindingContext, ModelMetadata propertyMetadata)
{
var modelMetadataPredicate = bindingContext.ModelMetadata.PropertyBindingPredicateProvider?.PropertyFilter;
if (modelMetadataPredicate?.Invoke(bindingContext, propertyMetadata.PropertyName) == false)
var metadataProviderFilter = bindingContext.ModelMetadata.PropertyFilterProvider?.PropertyFilter;
if (metadataProviderFilter?.Invoke(propertyMetadata) == false)
{
return false;
}
if (bindingContext.PropertyFilter?.Invoke(bindingContext, propertyMetadata.PropertyName) == false)
if (bindingContext.PropertyFilter?.Invoke(propertyMetadata) == false)
{
return false;
}

Просмотреть файл

@ -5,20 +5,18 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
/// <summary>
/// Default implementation for <see cref="IPropertyBindingPredicateProvider"/>.
/// Default implementation for <see cref="IPropertyFilterProvider"/>.
/// Provides a expression based way to provide include properties.
/// </summary>
/// <typeparam name="TModel">The target model Type.</typeparam>
public class DefaultPropertyBindingPredicateProvider<TModel> : IPropertyBindingPredicateProvider
public class DefaultPropertyFilterProvider<TModel> : IPropertyFilterProvider
where TModel : class
{
private static readonly Func<ModelBindingContext, string, bool> _defaultFilter =
(context, propertyName) => true;
private static readonly Func<ModelMetadata, bool> _default = (m) => true;
/// <summary>
/// The prefix which is used while generating the property filter.
@ -44,24 +42,24 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
/// <inheritdoc />
public virtual Func<ModelBindingContext, string, bool> PropertyFilter
public virtual Func<ModelMetadata, bool> PropertyFilter
{
get
{
if (PropertyIncludeExpressions == null)
{
return _defaultFilter;
return _default;
}
// We do not cache by default.
return GetPredicateFromExpression(PropertyIncludeExpressions);
return GetPropertyFilterFromExpression(PropertyIncludeExpressions);
}
}
private Func<ModelBindingContext, string, bool> GetPredicateFromExpression(
private Func<ModelMetadata, bool> GetPropertyFilterFromExpression(
IEnumerable<Expression<Func<TModel, object>>> includeExpressions)
{
var expression = ModelBindingHelper.GetIncludePredicateExpression(Prefix, includeExpressions.ToArray());
var expression = ModelBindingHelper.GetPropertyFilterExpression(includeExpressions.ToArray());
return expression.Compile();
}
}

Просмотреть файл

@ -74,9 +74,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
}
/// <summary>
/// Gets or sets the <see cref="ModelBinding.IPropertyBindingPredicateProvider"/>.
/// See <see cref="ModelMetadata.PropertyBindingPredicateProvider"/>.
/// Gets or sets the <see cref="ModelBinding.IPropertyFilterProvider"/>.
/// See <see cref="ModelMetadata.PropertyFilterProvider"/>.
/// </summary>
public IPropertyBindingPredicateProvider PropertyBindingPredicateProvider { get; set; }
public IPropertyFilterProvider PropertyFilterProvider { get; set; }
}
}

Просмотреть файл

@ -456,11 +456,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
}
/// <inheritdoc />
public override IPropertyBindingPredicateProvider PropertyBindingPredicateProvider
public override IPropertyFilterProvider PropertyFilterProvider
{
get
{
return BindingMetadata.PropertyBindingPredicateProvider;
return BindingMetadata.PropertyFilterProvider;
}
}

Просмотреть файл

@ -168,7 +168,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
BinderModelName = metadata.BinderModelName,
BinderType = metadata.BinderType,
BindingSource = metadata.BindingSource,
PropertyBindingPredicateProvider = metadata.PropertyBindingPredicateProvider,
PropertyFilterProvider = metadata.PropertyFilterProvider,
};
}

Просмотреть файл

@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
inputFormatters,
objectModelValidator,
validatorProvider,
predicate: (context, propertyName) => true);
propertyFilter: (m) => true);
}
/// <summary>
@ -198,8 +198,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
throw new ArgumentNullException(nameof(includeExpressions));
}
var includeExpression = GetIncludePredicateExpression(prefix, includeExpressions);
var predicate = includeExpression.Compile();
var expression = GetPropertyFilterExpression(includeExpressions);
var propertyFilter = expression.Compile();
return TryUpdateModelAsync(
model,
@ -211,7 +211,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
inputFormatters,
objectModelValidator,
validatorProvider,
predicate: predicate);
propertyFilter: propertyFilter);
}
/// <summary>
@ -234,8 +234,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// 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>
/// <param name="propertyFilter">
/// 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 Task<bool> TryUpdateModelAsync<TModel>(
TModel model,
@ -247,7 +248,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
IList<IInputFormatter> inputFormatters,
IObjectModelValidator objectModelValidator,
IModelValidatorProvider validatorProvider,
Func<ModelBindingContext, string, bool> predicate)
Func<ModelMetadata, bool> propertyFilter)
where TModel : class
{
if (model == null)
@ -295,9 +296,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
throw new ArgumentNullException(nameof(validatorProvider));
}
if (predicate == null)
if (propertyFilter == null)
{
throw new ArgumentNullException(nameof(predicate));
throw new ArgumentNullException(nameof(propertyFilter));
}
return TryUpdateModelAsync(
@ -311,7 +312,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
inputFormatters,
objectModelValidator,
validatorProvider,
predicate: predicate);
propertyFilter: propertyFilter);
}
/// <summary>
@ -409,7 +410,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
inputFormatters,
objectModelValidator,
validatorProvider,
predicate: (context, propertyName) => true);
propertyFilter: (m) => true);
}
/// <summary>
@ -432,21 +433,21 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// 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
/// <param name="propertyFilter">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(
object model,
Type modelType,
string prefix,
ActionContext actionContext,
IModelMetadataProvider metadataProvider,
IModelBinderFactory modelBinderFactory,
IValueProvider valueProvider,
IList<IInputFormatter> inputFormatters,
IObjectModelValidator objectModelValidator,
IModelValidatorProvider validatorProvider,
Func<ModelBindingContext, string, bool> predicate)
object model,
Type modelType,
string prefix,
ActionContext actionContext,
IModelMetadataProvider metadataProvider,
IModelBinderFactory modelBinderFactory,
IValueProvider valueProvider,
IList<IInputFormatter> inputFormatters,
IObjectModelValidator objectModelValidator,
IModelValidatorProvider validatorProvider,
Func<ModelMetadata, bool> propertyFilter)
{
if (model == null)
{
@ -498,9 +499,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
throw new ArgumentNullException(nameof(validatorProvider));
}
if (predicate == null)
if (propertyFilter == null)
{
throw new ArgumentNullException(nameof(predicate));
throw new ArgumentNullException(nameof(propertyFilter));
}
if (!modelType.IsAssignableFrom(model.GetType()))
@ -529,7 +530,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
bindingInfo: null,
modelName: prefix ?? string.Empty);
modelBindingContext.Model = model;
modelBindingContext.PropertyFilter = predicate;
modelBindingContext.PropertyFilter = propertyFilter;
var factoryContext = new ModelBinderFactoryContext()
{
@ -539,7 +540,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
BinderModelName = modelMetadata.BinderModelName,
BinderType = modelMetadata.BinderType,
BindingSource = modelMetadata.BindingSource,
PropertyBindingPredicateProvider = modelMetadata.PropertyBindingPredicateProvider,
PropertyFilterProvider = modelMetadata.PropertyFilterProvider,
},
// We're using the model metadata as the cache token here so that TryUpdateModelAsync calls
@ -607,42 +608,36 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// Creates an expression for a predicate to limit the set of properties used in model binding.
/// </summary>
/// <typeparam name="TModel">The model type.</typeparam>
/// <param name="prefix">The model prefix.</param>
/// <param name="expressions">Expressions identifying the properties to allow for binding.</param>
/// <returns>An expression which can be used with <see cref="IPropertyBindingPredicateProvider"/>.</returns>
public static Expression<Func<ModelBindingContext, string, bool>> GetIncludePredicateExpression<TModel>(
string prefix,
/// <returns>An expression which can be used with <see cref="IPropertyFilterProvider"/>.</returns>
public static Expression<Func<ModelMetadata, bool>> GetPropertyFilterExpression<TModel>(
Expression<Func<TModel, object>>[] expressions)
{
if (expressions.Length == 0)
{
// If nothing is included explcitly, treat everything as included.
return (context, propertyName) => true;
// If nothing is included explicitly, treat everything as included.
return (m) => true;
}
var firstExpression = GetPredicateExpression(prefix, expressions[0]);
var firstExpression = GetPredicateExpression(expressions[0]);
var orWrapperExpression = firstExpression.Body;
foreach (var expression in expressions.Skip(1))
{
var predicate = GetPredicateExpression(prefix, expression);
orWrapperExpression = Expression.OrElse(orWrapperExpression,
Expression.Invoke(predicate, firstExpression.Parameters));
var predicate = GetPredicateExpression(expression);
orWrapperExpression = Expression.OrElse(
orWrapperExpression,
Expression.Invoke(predicate, firstExpression.Parameters));
}
return Expression.Lambda<Func<ModelBindingContext, string, bool>>(
orWrapperExpression, firstExpression.Parameters);
return Expression.Lambda<Func<ModelMetadata, bool>>(orWrapperExpression, firstExpression.Parameters);
}
private static Expression<Func<ModelBindingContext, string, bool>> GetPredicateExpression<TModel>
(string prefix, Expression<Func<TModel, object>> expression)
private static Expression<Func<ModelMetadata, bool>> GetPredicateExpression<TModel>(
Expression<Func<TModel, object>> expression)
{
var propertyName = GetPropertyName(expression.Body);
var property = ModelNames.CreatePropertyModelName(prefix, propertyName);
return
(context, modelPropertyName) =>
property.Equals(ModelNames.CreatePropertyModelName(context.ModelName, modelPropertyName),
StringComparison.OrdinalIgnoreCase);
return (metadata) => string.Equals(metadata.PropertyName, propertyName, StringComparison.Ordinal);
}
/// <summary>

Просмотреть файл

@ -922,22 +922,6 @@ namespace Microsoft.AspNetCore.Mvc.Core
return string.Format(CultureInfo.CurrentCulture, GetString("ModelBinding_MissingBindRequiredMember"), p0);
}
/// <summary>
/// The type '{0}' does not implement the interface '{1}'.
/// </summary>
internal static string PropertyBindingPredicateProvider_WrongType
{
get { return GetString("PropertyBindingPredicateProvider_WrongType"); }
}
/// <summary>
/// The type '{0}' does not implement the interface '{1}'.
/// </summary>
internal static string FormatPropertyBindingPredicateProvider_WrongType(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("PropertyBindingPredicateProvider_WrongType"), p0, p1);
}
/// <summary>
/// The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.
/// </summary>
@ -1159,7 +1143,7 @@ namespace Microsoft.AspNetCore.Mvc.Core
/// </summary>
internal static string FormatMustSpecifyAtLeastOneAuthenticationScheme()
{
return string.Format(CultureInfo.CurrentCulture, GetString("MustSpecifyAtLeastOneAuthenticationScheme"));
return GetString("MustSpecifyAtLeastOneAuthenticationScheme");
}
/// <summary>

Просмотреть файл

@ -297,9 +297,6 @@
<data name="ModelBinding_MissingBindRequiredMember" xml:space="preserve">
<value>A value for the '{0}' property was not provided.</value>
</data>
<data name="PropertyBindingPredicateProvider_WrongType" xml:space="preserve">
<value>The type '{0}' does not implement the interface '{1}'.</value>
</data>
<data name="ValueProviderResult_NoConverterExists" xml:space="preserve">
<value>The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.</value>
</data>

Просмотреть файл

@ -536,7 +536,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
}
public override IPropertyBindingPredicateProvider PropertyBindingPredicateProvider
public override IPropertyFilterProvider PropertyFilterProvider
{
get
{

Просмотреть файл

@ -3,6 +3,7 @@
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Moq;
using Xunit;
@ -10,34 +11,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
public class BindAttributeTest
{
[Fact]
public void Constructor_Throws_IfTypeDoesNotImplement_IPropertyBindingPredicateProvider()
{
// Arrange
var expected =
"The type 'Microsoft.AspNetCore.Mvc.ModelBinding.BindAttributeTest+UnrelatedType' " +
"does not implement the interface " +
"'Microsoft.AspNetCore.Mvc.ModelBinding.IPropertyBindingPredicateProvider'." +
Environment.NewLine +
"Parameter name: predicateProviderType";
// Act & Assert
var exception = Assert.Throws<ArgumentException>(() => new BindAttribute(typeof(UnrelatedType)));
Assert.Equal(expected, exception.Message);
}
[Theory]
[InlineData(typeof(DerivedProvider))]
[InlineData(typeof(BaseProvider))]
public void Constructor_SetsThe_PropertyFilterProviderType_ForValidTypes(Type type)
{
// Arrange
var attribute = new BindAttribute(type);
// Act & Assert
Assert.Equal(type, attribute.PredicateProviderType);
}
[Theory]
[InlineData("UserName", true)]
[InlineData("Username", false)]
@ -54,98 +27,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var context = new DefaultModelBindingContext();
// Act
var predicate = bind.PropertyFilter;
// Assert
Assert.Equal(isIncluded, predicate(context, property));
}
[Theory]
[InlineData("UserName", true)]
[InlineData("Username", false)]
[InlineData("Password", false)]
public void BindAttribute_ProviderType(string property, bool isIncluded)
{
// Arrange
var bind = new BindAttribute(typeof(TestProvider));
var context = new DefaultModelBindingContext();
context.OperationBindingContext = new OperationBindingContext()
{
ActionContext = new ActionContext()
{
HttpContext = new DefaultHttpContext(),
},
};
var services = new Mock<IServiceProvider>();
context.OperationBindingContext.HttpContext.RequestServices = services.Object;
var identity = ModelMetadataIdentity.ForProperty(typeof(int), property, typeof(string));
context.ModelMetadata = new Mock<ModelMetadata>(identity).Object;
// Act
var predicate = bind.PropertyFilter;
var propertyFilter = bind.PropertyFilter;
// Assert
Assert.Equal(isIncluded, predicate(context, property));
}
// Each time .PropertyFilter is called, a since instance of the provider should
// be created and cached.
[Fact]
public void BindAttribute_ProviderType_Cached()
{
// Arrange
var bind = new BindAttribute(typeof(TestProvider));
var context = new DefaultModelBindingContext();
context.OperationBindingContext = new OperationBindingContext()
{
ActionContext = new ActionContext()
{
HttpContext = new DefaultHttpContext(),
},
};
var services = new Mock<IServiceProvider>(MockBehavior.Strict);
context.OperationBindingContext.HttpContext.RequestServices = services.Object;
// Act
var predicate = bind.PropertyFilter;
// Assert
Assert.True(predicate(context, "UserName"));
Assert.True(predicate(context, "UserName"));
}
private class TestProvider : IPropertyBindingPredicateProvider
{
public Func<ModelBindingContext, string, bool> PropertyFilter
{
get
{
return (context, property) => string.Equals(property, "UserName", StringComparison.Ordinal);
}
}
}
private class BaseProvider : IPropertyBindingPredicateProvider
{
public Func<ModelBindingContext, string, bool> PropertyFilter
{
get
{
throw new NotImplementedException();
}
}
}
private class DerivedProvider : BaseProvider
{
}
private class UnrelatedType
{
Assert.Equal(isIncluded, propertyFilter(context.ModelMetadata));
}
}
}

Просмотреть файл

@ -1151,8 +1151,8 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
// Include and exclude should be null, resulting in property
// being included.
Assert.True(context.PropertyFilter(context, "Property1"));
Assert.True(context.PropertyFilter(context, "Property2"));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property1"]));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property2"]));
});
var controller = GetController(binder, valueProvider);
@ -1179,8 +1179,8 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
// Include and exclude should be null, resulting in property
// being included.
Assert.True(context.PropertyFilter(context, "Property1"));
Assert.True(context.PropertyFilter(context, "Property2"));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property1"]));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property2"]));
});
var controller = GetController(binder, valueProvider);
@ -1206,8 +1206,8 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
// Include and exclude should be null, resulting in property
// being included.
Assert.True(context.PropertyFilter(context, "Property1"));
Assert.True(context.PropertyFilter(context, "Property2"));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property1"]));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property2"]));
});
var controller = GetController(binder, valueProvider: null);
@ -1221,64 +1221,65 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
}
[Fact]
public async Task TryUpdateModel_PredicateOverload_UsesPassedArguments()
public async Task TryUpdateModel_PropertyFilterOverload_UsesPassedArguments()
{
// Arrange
var modelName = "mymodel";
Func<ModelBindingContext, string, bool> includePredicate = (context, propertyName) =>
string.Equals(propertyName, "include1", StringComparison.OrdinalIgnoreCase) ||
string.Equals(propertyName, "include2", StringComparison.OrdinalIgnoreCase);
Func<ModelMetadata, bool> propertyFilter = (m) =>
string.Equals(m.PropertyName, "Include1", StringComparison.OrdinalIgnoreCase) ||
string.Equals(m.PropertyName, "Include2", StringComparison.OrdinalIgnoreCase);
var valueProvider = Mock.Of<IValueProvider>();
var binder = new StubModelBinder(context =>
{
Assert.Same(valueProvider, Assert.IsType<CompositeValueProvider>(context.ValueProvider)[0]);
Assert.True(context.PropertyFilter(context, "include1"));
Assert.True(context.PropertyFilter(context, "include2"));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Include1"]));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Include2"]));
Assert.False(context.PropertyFilter(context.ModelMetadata.Properties["Exclude1"]));
Assert.False(context.PropertyFilter(context.ModelMetadata.Properties["Exclude2"]));
Assert.False(context.PropertyFilter(context, "exclude1"));
Assert.False(context.PropertyFilter(context, "exclude2"));
});
var controller = GetController(binder, valueProvider);
var model = new MyModel();
// Act
await controller.TryUpdateModelAsync(model, modelName, includePredicate);
await controller.TryUpdateModelAsync(model, modelName, propertyFilter);
// Assert
Assert.NotEqual(0, binder.BindModelCount);
}
[Fact]
public async Task TryUpdateModel_PredicateWithValueProviderOverload_UsesPassedArguments()
public async Task TryUpdateModel_PropertyFilterWithValueProviderOverload_UsesPassedArguments()
{
// Arrange
var modelName = "mymodel";
Func<ModelBindingContext, string, bool> includePredicate =
(context, propertyName) => string.Equals(propertyName, "include1", StringComparison.OrdinalIgnoreCase) ||
string.Equals(propertyName, "include2", StringComparison.OrdinalIgnoreCase);
Func<ModelMetadata, bool> propertyFilter = (m) =>
string.Equals(m.PropertyName, "Include1", StringComparison.OrdinalIgnoreCase) ||
string.Equals(m.PropertyName, "Include2", StringComparison.OrdinalIgnoreCase);
var valueProvider = Mock.Of<IValueProvider>();
var binder = new StubModelBinder(context =>
{
Assert.Same(valueProvider, context.ValueProvider);
Assert.True(context.PropertyFilter(context, "include1"));
Assert.True(context.PropertyFilter(context, "include2"));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Include1"]));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Include2"]));
Assert.False(context.PropertyFilter(context, "exclude1"));
Assert.False(context.PropertyFilter(context, "exclude2"));
Assert.False(context.PropertyFilter(context.ModelMetadata.Properties["Exclude1"]));
Assert.False(context.PropertyFilter(context.ModelMetadata.Properties["Exclude2"]));
});
var controller = GetController(binder, valueProvider: null);
var model = new MyModel();
// Act
await controller.TryUpdateModelAsync(model, modelName, valueProvider, includePredicate);
await controller.TryUpdateModelAsync(model, modelName, valueProvider, propertyFilter);
// Assert
Assert.NotEqual(0, binder.BindModelCount);
@ -1298,14 +1299,14 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
var binder = new StubModelBinder(context =>
{
Assert.Same(
valueProvider.Object,
Assert.IsType<CompositeValueProvider>(context.ValueProvider)[0]);
valueProvider.Object,
Assert.IsType<CompositeValueProvider>(context.ValueProvider)[0]);
Assert.True(context.PropertyFilter(context, "Property1"));
Assert.True(context.PropertyFilter(context, "Property2"));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property1"]));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property2"]));
Assert.False(context.PropertyFilter(context, "exclude1"));
Assert.False(context.PropertyFilter(context, "exclude2"));
Assert.False(context.PropertyFilter(context.ModelMetadata.Properties["Exclude1"]));
Assert.False(context.PropertyFilter(context.ModelMetadata.Properties["Exclude2"]));
});
@ -1335,11 +1336,11 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
{
Assert.Same(valueProvider.Object, context.ValueProvider);
Assert.True(context.PropertyFilter(context, "Property1"));
Assert.True(context.PropertyFilter(context, "Property2"));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property1"]));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property2"]));
Assert.False(context.PropertyFilter(context, "exclude1"));
Assert.False(context.PropertyFilter(context, "exclude2"));
Assert.False(context.PropertyFilter(context.ModelMetadata.Properties["Exclude1"]));
Assert.False(context.PropertyFilter(context.ModelMetadata.Properties["Exclude2"]));
});
var controller = GetController(binder, valueProvider: null);
@ -1353,14 +1354,14 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
}
[Fact]
public async Task TryUpdateModelNonGeneric_PredicateWithValueProviderOverload_UsesPassedArguments()
public async Task TryUpdateModelNonGeneric_PropertyFilterWithValueProviderOverload_UsesPassedArguments()
{
// Arrange
var modelName = "mymodel";
Func<ModelBindingContext, string, bool> includePredicate =
(context, propertyName) => string.Equals(propertyName, "include1", StringComparison.OrdinalIgnoreCase) ||
string.Equals(propertyName, "include2", StringComparison.OrdinalIgnoreCase);
Func<ModelMetadata, bool> propertyFilter = (m) =>
string.Equals(m.PropertyName, "Include1", StringComparison.OrdinalIgnoreCase) ||
string.Equals(m.PropertyName, "Include2", StringComparison.OrdinalIgnoreCase);
var valueProvider = Mock.Of<IValueProvider>();
@ -1368,11 +1369,11 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
{
Assert.Same(valueProvider, context.ValueProvider);
Assert.True(context.PropertyFilter(context, "include1"));
Assert.True(context.PropertyFilter(context, "include2"));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Include1"]));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Include2"]));
Assert.False(context.PropertyFilter(context, "exclude1"));
Assert.False(context.PropertyFilter(context, "exclude2"));
Assert.False(context.PropertyFilter(context.ModelMetadata.Properties["Exclude1"]));
Assert.False(context.PropertyFilter(context.ModelMetadata.Properties["Exclude2"]));
});
var controller = GetController(binder, valueProvider: null);
@ -1380,7 +1381,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
var model = new MyModel();
// Act
await controller.TryUpdateModelAsync(model, model.GetType(), modelName, valueProvider, includePredicate);
await controller.TryUpdateModelAsync(model, model.GetType(), modelName, valueProvider, propertyFilter);
// Assert
Assert.NotEqual(0, binder.BindModelCount);
@ -1400,8 +1401,8 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
// Include and exclude should be null, resulting in property
// being included.
Assert.True(context.PropertyFilter(context, "Property1"));
Assert.True(context.PropertyFilter(context, "Property2"));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property1"]));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property2"]));
});
var controller = GetController(binder, valueProvider);
@ -1428,8 +1429,8 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
// Include and exclude should be null, resulting in property
// being included.
Assert.True(context.PropertyFilter(context, "Property1"));
Assert.True(context.PropertyFilter(context, "Property2"));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property1"]));
Assert.True(context.PropertyFilter(context.ModelMetadata.Properties["Property2"]));
});
var controller = GetController(binder, valueProvider);
@ -1667,6 +1668,12 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Include1 { get; set; }
public string Include2 { get; set; }
public string Exclude1 { get; set; }
public string Exclude2 { get; set; }
}
private class MyDerivedModel : MyModel

Просмотреть файл

@ -488,39 +488,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
Assert.False(result);
}
[Theory]
[InlineData(nameof(TypeWithExcludedPropertiesUsingBindAttribute.IncludedByDefault1), true)]
[InlineData(nameof(TypeWithExcludedPropertiesUsingBindAttribute.IncludedByDefault2), true)]
[InlineData(nameof(TypeWithExcludedPropertiesUsingBindAttribute.Excluded1), false)]
[InlineData(nameof(TypeWithExcludedPropertiesUsingBindAttribute.Excluded2), false)]
public void CanBindProperty_WithPredicate(string property, bool expected)
{
// Arrange
var metadata = GetMetadataForProperty(typeof(TypeWithExcludedPropertiesUsingBindAttribute), property);
var bindingContext = new DefaultModelBindingContext()
{
ModelMetadata = GetMetadataForType(typeof(TypeWithExcludedPropertiesUsingBindAttribute)),
OperationBindingContext = new OperationBindingContext()
{
ActionContext = new ActionContext()
{
HttpContext = new DefaultHttpContext()
{
RequestServices = new ServiceCollection().BuildServiceProvider(),
},
},
},
};
var binder = CreateBinder(bindingContext.ModelMetadata);
// Act
var result = binder.CanBindPropertyPublic(bindingContext, metadata);
// Assert
Assert.Equal(expected, result);
}
[Theory]
[InlineData(nameof(TypeWithIncludedPropertiesUsingBindAttribute.IncludedExplicitly1), true)]
[InlineData(nameof(TypeWithIncludedPropertiesUsingBindAttribute.IncludedExplicitly2), true)]
@ -1084,7 +1051,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
BinderModelName = metadata.BinderModelName,
BinderType = metadata.BinderType,
BindingSource = metadata.BindingSource,
PropertyBindingPredicateProvider = metadata.PropertyBindingPredicateProvider,
PropertyFilterProvider = metadata.PropertyFilterProvider,
},
});
}
@ -1284,17 +1251,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public int IncludedExplicitly2 { get; set; }
}
[Bind(typeof(ExcludedProvider))]
private class TypeWithExcludedPropertiesUsingBindAttribute
{
public int Excluded1 { get; set; }
public int Excluded2 { get; set; }
public int IncludedByDefault1 { get; set; }
public int IncludedByDefault2 { get; set; }
}
private class Document
{
[NonValueBinderMetadata]
@ -1317,15 +1273,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public BindingSource BindingSource { get { return BindingSource.Query; } }
}
private class ExcludedProvider : IPropertyBindingPredicateProvider
private class ExcludedProvider : IPropertyFilterProvider
{
public Func<ModelBindingContext, string, bool> PropertyFilter
public Func<ModelMetadata, bool> PropertyFilter
{
get
{
return (context, propertyName) =>
!string.Equals("Excluded1", propertyName, StringComparison.OrdinalIgnoreCase) &&
!string.Equals("Excluded2", propertyName, StringComparison.OrdinalIgnoreCase);
return (m) =>
!string.Equals("Excluded1", m.PropertyName, StringComparison.OrdinalIgnoreCase) &&
!string.Equals("Excluded2", m.PropertyName, StringComparison.OrdinalIgnoreCase);
}
}
}

Просмотреть файл

@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
Assert.Null(metadata.BinderModelName);
Assert.Null(metadata.BinderType);
Assert.Null(metadata.BindingSource);
Assert.Null(metadata.PropertyBindingPredicateProvider);
Assert.Null(metadata.PropertyFilterProvider);
}
[Fact]

Просмотреть файл

@ -150,14 +150,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
[Theory]
[MemberData(nameof(UnsuccessfulModelBindingData))]
public async Task TryUpdateModel_UsingIncludePredicateOverload_ReturnsFalse_IfBinderIsUnsuccessful(
public async Task TryUpdateModel_UsingPropertyFilterOverload_ReturnsFalse_IfBinderIsUnsuccessful(
ModelBindingResult? binderResult)
{
// Arrange
var metadataProvider = new EmptyModelMetadataProvider();
var binder = new StubModelBinder(binderResult);
var model = new MyModel();
Func<ModelBindingContext, string, bool> includePredicate = (context, propertyName) => true;
Func<ModelMetadata, bool> propertyFilter = (m) => true;
// Act
var result = await ModelBindingHelper.TryUpdateModelAsync(
@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
new List<IInputFormatter>(),
new Mock<IObjectModelValidator>(MockBehavior.Strict).Object,
Mock.Of<IModelValidatorProvider>(),
includePredicate);
propertyFilter);
// Assert
Assert.False(result);
@ -180,7 +180,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
[Fact]
public async Task TryUpdateModel_UsingIncludePredicateOverload_ReturnsTrue_ModelBindsAndValidatesSuccessfully()
public async Task TryUpdateModel_UsingPropertyFilterOverload_ReturnsTrue_ModelBindsAndValidatesSuccessfully()
{
// Arrange
var binderProviders = new IModelBinderProvider[]
@ -208,9 +208,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
{ "ExcludedProperty", "ExcludedPropertyValue" }
};
Func<ModelBindingContext, string, bool> includePredicate = (context, propertyName) =>
string.Equals(propertyName, "IncludedProperty", StringComparison.OrdinalIgnoreCase) ||
string.Equals(propertyName, "MyProperty", StringComparison.OrdinalIgnoreCase);
Func<ModelMetadata, bool> propertyFilter = (m) =>
string.Equals(m.PropertyName, "IncludedProperty", StringComparison.OrdinalIgnoreCase) ||
string.Equals(m.PropertyName, "MyProperty", StringComparison.OrdinalIgnoreCase);
var valueProvider = new TestValueProvider(values);
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
@ -226,7 +226,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
new List<IInputFormatter>(),
new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
validator,
includePredicate);
propertyFilter);
// Assert
Assert.True(result);
@ -491,14 +491,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
[Theory]
[MemberData(nameof(UnsuccessfulModelBindingData))]
public async Task TryUpdateModelNonGeneric_PredicateOverload_ReturnsFalse_IfBinderIsUnsuccessful(
public async Task TryUpdateModelNonGeneric_PropertyFilterOverload_ReturnsFalse_IfBinderIsUnsuccessful(
ModelBindingResult? binderResult)
{
// Arrange
var metadataProvider = new EmptyModelMetadataProvider();
var binder = new StubModelBinder(binderResult);
var model = new MyModel();
Func<ModelBindingContext, string, bool> includePredicate = (context, propertyName) => true;
Func<ModelMetadata, bool> propertyFilter = (m) => true;
// Act
var result = await ModelBindingHelper.TryUpdateModelAsync(
@ -512,7 +512,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
inputFormatters: new List<IInputFormatter>(),
objectModelValidator: new Mock<IObjectModelValidator>(MockBehavior.Strict).Object,
validatorProvider: Mock.Of<IModelValidatorProvider>(),
predicate: includePredicate);
propertyFilter: propertyFilter);
// Assert
Assert.False(result);
@ -522,7 +522,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
[Fact]
public async Task TryUpdateModelNonGeneric_PredicateOverload_ReturnsTrue_ModelBindsAndValidatesSuccessfully()
public async Task TryUpdateModelNonGeneric_PropertyFilterOverload_ReturnsTrue_ModelBindsAndValidatesSuccessfully()
{
// Arrange
var binderProviders = new IModelBinderProvider[]
@ -550,9 +550,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
{ "ExcludedProperty", "ExcludedPropertyValue" }
};
Func<ModelBindingContext, string, bool> includePredicate = (context, propertyName) =>
string.Equals(propertyName, "IncludedProperty", StringComparison.OrdinalIgnoreCase) ||
string.Equals(propertyName, "MyProperty", StringComparison.OrdinalIgnoreCase);
Func<ModelMetadata, bool> propertyFilter = (m) =>
string.Equals(m.PropertyName, "IncludedProperty", StringComparison.OrdinalIgnoreCase) ||
string.Equals(m.PropertyName, "MyProperty", StringComparison.OrdinalIgnoreCase);
var valueProvider = new TestValueProvider(values);
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
@ -569,7 +569,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
new List<IInputFormatter>(),
new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
validator,
includePredicate);
propertyFilter);
// Assert
Assert.True(result);
@ -657,7 +657,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var binder = new StubModelBinder();
var model = new MyModel();
Func<ModelBindingContext, string, bool> includePredicate = (context, propertyName) => true;
Func<ModelMetadata, bool> propertyFilter = (m) => true;
// Act & Assert
var exception = await Assert.ThrowsAsync<ArgumentException>(
@ -672,7 +672,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
new List<IInputFormatter>(),
new DefaultObjectValidator(metadataProvider, new ValidatorCache()),
Mock.Of<IModelValidatorProvider>(),
includePredicate));
propertyFilter));
var expectedMessage = string.Format("The model's runtime type '{0}' is not assignable to the type '{1}'." +
Environment.NewLine +

Просмотреть файл

@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
BinderModelName = Metadata.BinderModelName,
BinderType = Metadata.BinderType,
BindingSource = Metadata.BindingSource,
PropertyBindingPredicateProvider = Metadata.PropertyBindingPredicateProvider,
PropertyFilterProvider = Metadata.PropertyFilterProvider,
};
}

Просмотреть файл

@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
public class ModelMetadataProviderTest
{
[Fact]
public void ModelMetadataProvider_UsesPredicateOnType()
public void ModelMetadataProvider_UsesPropertyFilterProviderOnType()
{
// Arrange
var type = typeof(User);
@ -32,12 +32,12 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
var metadata = provider.GetMetadataForType(type);
// Assert
var predicate = metadata.PropertyBindingPredicateProvider.PropertyFilter;
var propertyFilter = metadata.PropertyFilterProvider.PropertyFilter;
var matched = new HashSet<string>();
foreach (var property in metadata.Properties)
{
if (predicate(context, property.PropertyName))
if (propertyFilter(property))
{
matched.Add(property.PropertyName);
}