From 144766f2e3ee802f50e143ee29d5ad654333a171 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Thu, 24 Mar 2016 15:10:35 -0700 Subject: [PATCH] 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. --- .../ModelBinding/BindingInfo.cs | 40 +++--- ...Provider.cs => IPropertyFilterProvider.cs} | 4 +- .../ModelBinding/ModelBindingContext.cs | 2 +- .../ModelBinding/ModelMetadata.cs | 4 +- .../BindAttribute.cs | 88 ++----------- .../ControllerBase.cs | 30 ++--- .../DefaultBindingMetadataProvider.cs | 36 +++--- .../Internal/DefaultModelBindingContext.cs | 11 +- .../Binders/ComplexTypeModelBinder.cs | 6 +- ...DefaultPropertyBindingPredicateProvider.cs | 18 ++- .../ModelBinding/Metadata/BindingMetadata.cs | 6 +- .../Metadata/DefaultModelMetadata.cs | 4 +- .../ModelBinding/ModelBinderFactory.cs | 2 +- .../ModelBinding/ModelBindingHelper.cs | 87 ++++++------- .../Properties/Resources.Designer.cs | 18 +-- .../Resources.resx | 3 - .../ModelBinding/ModelMetadataTest.cs | 2 +- .../BindAttributeTest.cs | 121 +----------------- .../ControllerBaseTest.cs | 101 ++++++++------- .../Binders/ComplexTypeModelBinderTest.cs | 56 +------- .../Metadata/DefaultModelMetadataTest.cs | 2 +- .../ModelBinding/ModelBindingHelperTest.cs | 36 +++--- .../TestModelBinderProviderContext.cs | 2 +- .../Internal/ModelMetadataProviderTest.cs | 6 +- 24 files changed, 222 insertions(+), 463 deletions(-) rename src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/{IPropertyBindingPredicateProvider.cs => IPropertyFilterProvider.cs} (81%) diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/BindingInfo.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/BindingInfo.cs index b746ccd374..4f4d313177 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/BindingInfo.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/BindingInfo.cs @@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding BindingSource = other.BindingSource; BinderModelName = other.BinderModelName; BinderType = other.BinderType; - PropertyBindingPredicateProvider = other.PropertyBindingPredicateProvider; + PropertyFilterProvider = other.PropertyFilterProvider; } /// @@ -52,9 +52,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding public Type BinderType { get; set; } /// - /// Gets or sets the . + /// Gets or sets the . /// - public IPropertyBindingPredicateProvider PropertyBindingPredicateProvider { get; set; } + public IPropertyFilterProvider PropertyFilterProvider { get; set; } /// /// Constructs a new instance of from the given . @@ -100,46 +100,50 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding } } - // PropertyBindingPredicateProvider - var predicateProviders = attributes.OfType().ToArray(); - if (predicateProviders.Length > 0) + // PropertyFilterProvider + var propertyFilterProviders = attributes.OfType().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 _providers; + private readonly IEnumerable _providers; - public CompositePredicateProvider(IEnumerable providers) + public CompositePropertyFilterProvider(IEnumerable providers) { _providers = providers; } - public Func PropertyFilter + public Func PropertyFilter { get { - return CreatePredicate(); + return CreatePropertyFilter(); } } - private Func CreatePredicate() + private Func 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; } diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/IPropertyBindingPredicateProvider.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/IPropertyFilterProvider.cs similarity index 81% rename from src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/IPropertyBindingPredicateProvider.cs rename to src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/IPropertyFilterProvider.cs index e1124e6b26..76ddd463cc 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/IPropertyBindingPredicateProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/IPropertyFilterProvider.cs @@ -8,11 +8,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// /// Provides a predicate which can determines which model properties should be bound by model binding. /// - public interface IPropertyBindingPredicateProvider + public interface IPropertyFilterProvider { /// /// Gets a predicate which can determines which model properties should be bound by model binding. /// - Func PropertyFilter { get; } + Func PropertyFilter { get; } } } diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs index a6fc24614e..0a1a711686 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBindingContext.cs @@ -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. /// - public abstract Func PropertyFilter { get; set; } + public abstract Func PropertyFilter { get; set; } /// /// Gets or sets the . Used for tracking validation state to diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelMetadata.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelMetadata.cs index de480a0dbc..be2d6cebc8 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelMetadata.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelMetadata.cs @@ -269,10 +269,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding public abstract string NullDisplayText { get; } /// - /// Gets the , which can determine which properties + /// Gets the , which can determine which properties /// should be model bound. /// - public abstract IPropertyBindingPredicateProvider PropertyBindingPredicateProvider { get; } + public abstract IPropertyFilterProvider PropertyFilterProvider { get; } /// /// Gets a value that indicates whether the property should be displayed in read-only views. diff --git a/src/Microsoft.AspNetCore.Mvc.Core/BindAttribute.cs b/src/Microsoft.AspNetCore.Mvc.Core/BindAttribute.cs index 6ccdc8c8fe..d3ee7257fd 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/BindAttribute.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/BindAttribute.cs @@ -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. /// [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 _defaultFilter = - (context, propertyName) => true; + private static readonly Func _default = (m) => true; - private ObjectFactory _factory; - - private Func _predicateFromInclude; + private Func _propertyFilter; /// /// Creates a new instace of . @@ -41,33 +36,6 @@ namespace Microsoft.AspNetCore.Mvc Include = items.ToArray(); } - /// - /// Creates a new instance of . - /// - /// The type which implements - /// . - /// - 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; - } - - /// - public Type PredicateProviderType { get; } - /// /// Gets the names of properties to include in model binding. /// @@ -91,64 +59,26 @@ namespace Microsoft.AspNetCore.Mvc } /// - public Func PropertyFilter + public Func 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 CreatePredicateFromProviderType( - ObjectFactory factory) - { - // Holding state to avoid execessive creation of the provider. - var initialized = false; - Func 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 SplitString(string original) { if (string.IsNullOrEmpty(original)) diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs b/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs index fd30b08024..4653aca3ce 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs @@ -1222,13 +1222,13 @@ namespace Microsoft.AspNetCore.Mvc /// The model instance to update. /// The prefix to use when looking up values in the current . /// - /// A predicate which can be used to filter properties at runtime. + /// A predicate which can be used to filter properties at runtime. /// A that on completion returns true if the update is successful. [NonAction] public Task TryUpdateModelAsync( TModel model, string prefix, - Func predicate) + Func 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); } /// @@ -1311,14 +1311,14 @@ namespace Microsoft.AspNetCore.Mvc /// The prefix to use when looking up values in the . /// /// The used for looking up values. - /// A predicate which can be used to filter properties at runtime. + /// A predicate which can be used to filter properties at runtime. /// A that on completion returns true if the update is successful. [NonAction] public Task TryUpdateModelAsync( TModel model, string prefix, IValueProvider valueProvider, - Func predicate) + Func 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); } /// @@ -1396,7 +1396,7 @@ namespace Microsoft.AspNetCore.Mvc /// The prefix to use when looking up values in the . /// /// The used for looking up values. - /// A predicate which can be used to filter properties at runtime. + /// A predicate which can be used to filter properties at runtime. /// A that on completion returns true if the update is successful. [NonAction] public Task TryUpdateModelAsync( @@ -1404,7 +1404,7 @@ namespace Microsoft.AspNetCore.Mvc Type modelType, string prefix, IValueProvider valueProvider, - Func predicate) + Func 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); } /// diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultBindingMetadataProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultBindingMetadataProvider.cs index efe6b2309a..be82a8f14a 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultBindingMetadataProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultBindingMetadataProvider.cs @@ -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().ToArray(); - if (predicateProviders.Length == 0) + // PropertyFilterProvider + var propertyFilterProviders = context.Attributes.OfType().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 _providers; + private readonly IEnumerable _providers; - public CompositePredicateProvider(IEnumerable providers) + public CompositePropertyFilterProvider(IEnumerable providers) { _providers = providers; } - public Func PropertyFilter + public Func PropertyFilter { get { - return CreatePredicate(); + return CreatePropertyFilter(); } } - private Func CreatePredicate() + private Func 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; } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultModelBindingContext.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultModelBindingContext.cs index 017596e4b0..a0e3025fe9 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultModelBindingContext.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultModelBindingContext.cs @@ -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 } /// - public override Func PropertyFilter + public override Func 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 PropertyFilter; + public Func PropertyFilter; public ValidationStateDictionary ValidationState; public ModelStateDictionary ModelState; diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ComplexTypeModelBinder.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ComplexTypeModelBinder.cs index 402dc2ec65..0100f8aa81 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ComplexTypeModelBinder.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ComplexTypeModelBinder.cs @@ -114,13 +114,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders /// true if the model property can be bound, otherwise false. 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; } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/DefaultPropertyBindingPredicateProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/DefaultPropertyBindingPredicateProvider.cs index 111d45f353..a26b6ca0be 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/DefaultPropertyBindingPredicateProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/DefaultPropertyBindingPredicateProvider.cs @@ -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 { /// - /// Default implementation for . + /// Default implementation for . /// Provides a expression based way to provide include properties. /// /// The target model Type. - public class DefaultPropertyBindingPredicateProvider : IPropertyBindingPredicateProvider + public class DefaultPropertyFilterProvider : IPropertyFilterProvider where TModel : class { - private static readonly Func _defaultFilter = - (context, propertyName) => true; + private static readonly Func _default = (m) => true; /// /// The prefix which is used while generating the property filter. @@ -44,24 +42,24 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding } /// - public virtual Func PropertyFilter + public virtual Func PropertyFilter { get { if (PropertyIncludeExpressions == null) { - return _defaultFilter; + return _default; } // We do not cache by default. - return GetPredicateFromExpression(PropertyIncludeExpressions); + return GetPropertyFilterFromExpression(PropertyIncludeExpressions); } } - private Func GetPredicateFromExpression( + private Func GetPropertyFilterFromExpression( IEnumerable>> includeExpressions) { - var expression = ModelBindingHelper.GetIncludePredicateExpression(Prefix, includeExpressions.ToArray()); + var expression = ModelBindingHelper.GetPropertyFilterExpression(includeExpressions.ToArray()); return expression.Compile(); } } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/BindingMetadata.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/BindingMetadata.cs index 19994e1505..47352d3cb1 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/BindingMetadata.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/BindingMetadata.cs @@ -74,9 +74,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata } /// - /// Gets or sets the . - /// See . + /// Gets or sets the . + /// See . /// - public IPropertyBindingPredicateProvider PropertyBindingPredicateProvider { get; set; } + public IPropertyFilterProvider PropertyFilterProvider { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs index b36238d310..8dc54ddea4 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs @@ -456,11 +456,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata } /// - public override IPropertyBindingPredicateProvider PropertyBindingPredicateProvider + public override IPropertyFilterProvider PropertyFilterProvider { get { - return BindingMetadata.PropertyBindingPredicateProvider; + return BindingMetadata.PropertyFilterProvider; } } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderFactory.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderFactory.cs index 179ef3202d..a551d20057 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderFactory.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderFactory.cs @@ -168,7 +168,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding BinderModelName = metadata.BinderModelName, BinderType = metadata.BinderType, BindingSource = metadata.BindingSource, - PropertyBindingPredicateProvider = metadata.PropertyBindingPredicateProvider, + PropertyFilterProvider = metadata.PropertyFilterProvider, }; } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBindingHelper.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBindingHelper.cs index a72483cc5f..26a8c5aca5 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBindingHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBindingHelper.cs @@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding inputFormatters, objectModelValidator, validatorProvider, - predicate: (context, propertyName) => true); + propertyFilter: (m) => true); } /// @@ -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); } /// @@ -234,8 +234,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// bound values. /// The used for executing validation /// on the model instance. - /// A predicate which can be used to - /// filter properties(for inclusion/exclusion) at runtime. + /// + /// A predicate which can be used to filter properties(for inclusion/exclusion) at runtime. + /// /// A that on completion returns true if the update is successful public static Task TryUpdateModelAsync( TModel model, @@ -247,7 +248,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding IList inputFormatters, IObjectModelValidator objectModelValidator, IModelValidatorProvider validatorProvider, - Func predicate) + Func 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); } /// @@ -409,7 +410,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding inputFormatters, objectModelValidator, validatorProvider, - predicate: (context, propertyName) => true); + propertyFilter: (m) => true); } /// @@ -432,21 +433,21 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// bound values. /// The used for executing validation /// on the model instance. - /// A predicate which can be used to + /// A predicate which can be used to /// filter properties(for inclusion/exclusion) at runtime. /// A that on completion returns true if the update is successful public static async Task TryUpdateModelAsync( - object model, - Type modelType, - string prefix, - ActionContext actionContext, - IModelMetadataProvider metadataProvider, - IModelBinderFactory modelBinderFactory, - IValueProvider valueProvider, - IList inputFormatters, - IObjectModelValidator objectModelValidator, - IModelValidatorProvider validatorProvider, - Func predicate) + object model, + Type modelType, + string prefix, + ActionContext actionContext, + IModelMetadataProvider metadataProvider, + IModelBinderFactory modelBinderFactory, + IValueProvider valueProvider, + IList inputFormatters, + IObjectModelValidator objectModelValidator, + IModelValidatorProvider validatorProvider, + Func 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. /// /// The model type. - /// The model prefix. /// Expressions identifying the properties to allow for binding. - /// An expression which can be used with . - public static Expression> GetIncludePredicateExpression( - string prefix, + /// An expression which can be used with . + public static Expression> GetPropertyFilterExpression( Expression>[] 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>( - orWrapperExpression, firstExpression.Parameters); + return Expression.Lambda>(orWrapperExpression, firstExpression.Parameters); } - private static Expression> GetPredicateExpression - (string prefix, Expression> expression) + private static Expression> GetPredicateExpression( + Expression> 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); } /// diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs index 8859b10fbb..bb38364f51 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs @@ -922,22 +922,6 @@ namespace Microsoft.AspNetCore.Mvc.Core return string.Format(CultureInfo.CurrentCulture, GetString("ModelBinding_MissingBindRequiredMember"), p0); } - /// - /// The type '{0}' does not implement the interface '{1}'. - /// - internal static string PropertyBindingPredicateProvider_WrongType - { - get { return GetString("PropertyBindingPredicateProvider_WrongType"); } - } - - /// - /// The type '{0}' does not implement the interface '{1}'. - /// - internal static string FormatPropertyBindingPredicateProvider_WrongType(object p0, object p1) - { - return string.Format(CultureInfo.CurrentCulture, GetString("PropertyBindingPredicateProvider_WrongType"), p0, p1); - } - /// /// The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types. /// @@ -1159,7 +1143,7 @@ namespace Microsoft.AspNetCore.Mvc.Core /// internal static string FormatMustSpecifyAtLeastOneAuthenticationScheme() { - return string.Format(CultureInfo.CurrentCulture, GetString("MustSpecifyAtLeastOneAuthenticationScheme")); + return GetString("MustSpecifyAtLeastOneAuthenticationScheme"); } /// diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx index 40506b3759..d5ce00f4ef 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx +++ b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx @@ -297,9 +297,6 @@ A value for the '{0}' property was not provided. - - The type '{0}' does not implement the interface '{1}'. - The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types. diff --git a/test/Microsoft.AspNetCore.Mvc.Abstractions.Test/ModelBinding/ModelMetadataTest.cs b/test/Microsoft.AspNetCore.Mvc.Abstractions.Test/ModelBinding/ModelMetadataTest.cs index 1abe824129..823bb15efc 100644 --- a/test/Microsoft.AspNetCore.Mvc.Abstractions.Test/ModelBinding/ModelMetadataTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Abstractions.Test/ModelBinding/ModelMetadataTest.cs @@ -536,7 +536,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding } } - public override IPropertyBindingPredicateProvider PropertyBindingPredicateProvider + public override IPropertyFilterProvider PropertyFilterProvider { get { diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/BindAttributeTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/BindAttributeTest.cs index 3537acdd99..93b614e477 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/BindAttributeTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/BindAttributeTest.cs @@ -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(() => 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(); - - context.OperationBindingContext.HttpContext.RequestServices = services.Object; + var identity = ModelMetadataIdentity.ForProperty(typeof(int), property, typeof(string)); + context.ModelMetadata = new Mock(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(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 PropertyFilter - { - get - { - return (context, property) => string.Equals(property, "UserName", StringComparison.Ordinal); - } - } - } - - private class BaseProvider : IPropertyBindingPredicateProvider - { - public Func PropertyFilter - { - get - { - throw new NotImplementedException(); - } - } - } - - private class DerivedProvider : BaseProvider - { - } - - private class UnrelatedType - { + Assert.Equal(isIncluded, propertyFilter(context.ModelMetadata)); } } } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs index b0e4184543..6c945cc37f 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs @@ -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 includePredicate = (context, propertyName) => - string.Equals(propertyName, "include1", StringComparison.OrdinalIgnoreCase) || - string.Equals(propertyName, "include2", StringComparison.OrdinalIgnoreCase); + Func propertyFilter = (m) => + string.Equals(m.PropertyName, "Include1", StringComparison.OrdinalIgnoreCase) || + string.Equals(m.PropertyName, "Include2", StringComparison.OrdinalIgnoreCase); var valueProvider = Mock.Of(); var binder = new StubModelBinder(context => { Assert.Same(valueProvider, Assert.IsType(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 includePredicate = - (context, propertyName) => string.Equals(propertyName, "include1", StringComparison.OrdinalIgnoreCase) || - string.Equals(propertyName, "include2", StringComparison.OrdinalIgnoreCase); + Func propertyFilter = (m) => + string.Equals(m.PropertyName, "Include1", StringComparison.OrdinalIgnoreCase) || + string.Equals(m.PropertyName, "Include2", StringComparison.OrdinalIgnoreCase); var valueProvider = Mock.Of(); 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(context.ValueProvider)[0]); + valueProvider.Object, + Assert.IsType(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 includePredicate = - (context, propertyName) => string.Equals(propertyName, "include1", StringComparison.OrdinalIgnoreCase) || - string.Equals(propertyName, "include2", StringComparison.OrdinalIgnoreCase); + Func propertyFilter = (m) => + string.Equals(m.PropertyName, "Include1", StringComparison.OrdinalIgnoreCase) || + string.Equals(m.PropertyName, "Include2", StringComparison.OrdinalIgnoreCase); var valueProvider = Mock.Of(); @@ -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 diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/ComplexTypeModelBinderTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/ComplexTypeModelBinderTest.cs index 0c965860f3..16135b6b6a 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/ComplexTypeModelBinderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/ComplexTypeModelBinderTest.cs @@ -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 PropertyFilter + public Func 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); } } } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Metadata/DefaultModelMetadataTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Metadata/DefaultModelMetadataTest.cs index 806117d35a..57def74719 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Metadata/DefaultModelMetadataTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Metadata/DefaultModelMetadataTest.cs @@ -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] diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBindingHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBindingHelperTest.cs index 4df7b01315..a99dbf1781 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBindingHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBindingHelperTest.cs @@ -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 includePredicate = (context, propertyName) => true; + Func propertyFilter = (m) => true; // Act var result = await ModelBindingHelper.TryUpdateModelAsync( @@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding new List(), new Mock(MockBehavior.Strict).Object, Mock.Of(), - 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 includePredicate = (context, propertyName) => - string.Equals(propertyName, "IncludedProperty", StringComparison.OrdinalIgnoreCase) || - string.Equals(propertyName, "MyProperty", StringComparison.OrdinalIgnoreCase); + Func 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(), 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 includePredicate = (context, propertyName) => true; + Func propertyFilter = (m) => true; // Act var result = await ModelBindingHelper.TryUpdateModelAsync( @@ -512,7 +512,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding inputFormatters: new List(), objectModelValidator: new Mock(MockBehavior.Strict).Object, validatorProvider: Mock.Of(), - 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 includePredicate = (context, propertyName) => - string.Equals(propertyName, "IncludedProperty", StringComparison.OrdinalIgnoreCase) || - string.Equals(propertyName, "MyProperty", StringComparison.OrdinalIgnoreCase); + Func 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(), 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 includePredicate = (context, propertyName) => true; + Func propertyFilter = (m) => true; // Act & Assert var exception = await Assert.ThrowsAsync( @@ -672,7 +672,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding new List(), new DefaultObjectValidator(metadataProvider, new ValidatorCache()), Mock.Of(), - includePredicate)); + propertyFilter)); var expectedMessage = string.Format("The model's runtime type '{0}' is not assignable to the type '{1}'." + Environment.NewLine + diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/TestModelBinderProviderContext.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/TestModelBinderProviderContext.cs index 1a78730ca0..1478ebb3fc 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/TestModelBinderProviderContext.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/TestModelBinderProviderContext.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding BinderModelName = Metadata.BinderModelName, BinderType = Metadata.BinderType, BindingSource = Metadata.BindingSource, - PropertyBindingPredicateProvider = Metadata.PropertyBindingPredicateProvider, + PropertyFilterProvider = Metadata.PropertyFilterProvider, }; } diff --git a/test/Microsoft.AspNetCore.Mvc.DataAnnotations.Test/Internal/ModelMetadataProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.DataAnnotations.Test/Internal/ModelMetadataProviderTest.cs index e7d8ab032a..8b413c582a 100644 --- a/test/Microsoft.AspNetCore.Mvc.DataAnnotations.Test/Internal/ModelMetadataProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.DataAnnotations.Test/Internal/ModelMetadataProviderTest.cs @@ -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(); foreach (var property in metadata.Properties) { - if (predicate(context, property.PropertyName)) + if (propertyFilter(property)) { matched.Add(property.PropertyName); }