Updating Associated Metadata Provider to follow the existing pattern.
This commit is contained in:
parent
680cdf4d57
commit
b54c326ee6
|
|
@ -43,11 +43,11 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var metadata = metadataProvider.GetMetadataForParameter(
|
var metadata = metadataProvider.GetMetadataForParameter(
|
||||||
modelAccessor: null,
|
modelAccessor: null,
|
||||||
methodInfo: actionDescriptor.MethodInfo,
|
methodInfo: actionDescriptor.MethodInfo,
|
||||||
parameterName: parameter.Name,
|
parameterName: parameter.Name);
|
||||||
binderMetadata: parameter.BinderMetadata);
|
|
||||||
|
|
||||||
if (metadata != null)
|
if (metadata != null)
|
||||||
{
|
{
|
||||||
|
UpdateParameterMetadata(metadata, parameter.BinderMetadata);
|
||||||
parameterMetadata.Add(metadata);
|
parameterMetadata.Add(metadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -57,6 +57,20 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return actionArguments;
|
return actionArguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateParameterMetadata(ModelMetadata metadata, IBinderMetadata binderMetadata)
|
||||||
|
{
|
||||||
|
if (binderMetadata != null)
|
||||||
|
{
|
||||||
|
metadata.BinderMetadata = binderMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nameProvider = binderMetadata as IModelNameProvider;
|
||||||
|
if (nameProvider != null && nameProvider.Name != null)
|
||||||
|
{
|
||||||
|
metadata.BinderModelName = nameProvider.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task PopulateArgumentAsync(
|
private async Task PopulateArgumentAsync(
|
||||||
ActionBindingContext actionBindingContext,
|
ActionBindingContext actionBindingContext,
|
||||||
IDictionary<string, object> arguments,
|
IDictionary<string, object> arguments,
|
||||||
|
|
@ -82,23 +96,23 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ModelBindingContext GetModelBindingContext(ModelMetadata modelMetadata,
|
internal static ModelBindingContext GetModelBindingContext(ModelMetadata modelMetadata,
|
||||||
ActionBindingContext actionBindingContext,
|
ActionBindingContext actionBindingContext,
|
||||||
OperationBindingContext operationBindingContext)
|
OperationBindingContext operationBindingContext)
|
||||||
{
|
{
|
||||||
Predicate<string> propertyFilter =
|
Predicate<string> propertyFilter =
|
||||||
propertyName => BindAttribute.IsPropertyAllowed(propertyName,
|
propertyName => BindAttribute.IsPropertyAllowed(propertyName,
|
||||||
modelMetadata.IncludedProperties,
|
modelMetadata.BinderIncludeProperties,
|
||||||
modelMetadata.ExcludedProperties);
|
modelMetadata.BinderExcludeProperties);
|
||||||
|
|
||||||
var modelBindingContext = new ModelBindingContext
|
var modelBindingContext = new ModelBindingContext
|
||||||
{
|
{
|
||||||
ModelName = modelMetadata.ModelName ?? modelMetadata.PropertyName,
|
ModelName = modelMetadata.BinderModelName ?? modelMetadata.PropertyName,
|
||||||
ModelMetadata = modelMetadata,
|
ModelMetadata = modelMetadata,
|
||||||
ModelState = actionBindingContext.ActionContext.ModelState,
|
ModelState = actionBindingContext.ActionContext.ModelState,
|
||||||
PropertyFilter = propertyFilter,
|
PropertyFilter = propertyFilter,
|
||||||
// Fallback only if there is no explicit model name set.
|
// Fallback only if there is no explicit model name set.
|
||||||
FallbackToEmptyPrefix = modelMetadata.ModelName == null,
|
FallbackToEmptyPrefix = modelMetadata.BinderModelName == null,
|
||||||
ValueProvider = actionBindingContext.ValueProvider,
|
ValueProvider = actionBindingContext.ValueProvider,
|
||||||
OperationBindingContext = operationBindingContext,
|
OperationBindingContext = operationBindingContext,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// This attribute can be used on action parameters and types, to indicate model level metadata.
|
/// This attribute can be used on action parameters and types, to indicate model level metadata.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
|
||||||
public sealed class BindAttribute : Attribute, IModelNameProvider, IModelPropertyBindingInfo
|
public sealed class BindAttribute : Attribute, IModelNameProvider, IPropertyBindingInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Comma separated set of properties which are to be excluded during model binding.
|
/// Comma separated set of properties which are to be excluded during model binding.
|
||||||
|
|
@ -45,10 +45,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
IReadOnlyList<string> excludeProperties)
|
IReadOnlyList<string> excludeProperties)
|
||||||
{
|
{
|
||||||
// We allow a property to be bound if its both in the include list AND not in the exclude list.
|
// We allow a property to be bound if its both in the include list AND not in the exclude list.
|
||||||
// An empty include list implies all properties are allowed.
|
|
||||||
// An empty exclude list implies no properties are disallowed.
|
// An empty exclude list implies no properties are disallowed.
|
||||||
var includeProperty = (includeProperties == null) ||
|
var includeProperty = (includeProperties != null) &&
|
||||||
(includeProperties.Count == 0) ||
|
|
||||||
includeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);
|
includeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);
|
||||||
var excludeProperty = (excludeProperties != null) &&
|
var excludeProperty = (excludeProperties != null) &&
|
||||||
excludeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);
|
excludeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
|
||||||
|
|
@ -51,14 +51,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
var bindingContext = context.ModelBindingContext;
|
var bindingContext = context.ModelBindingContext;
|
||||||
var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;
|
var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;
|
||||||
var isThereAnExplicitAlias = bindingContext.ModelMetadata.ModelName != null;
|
var hasExplicitAlias = bindingContext.ModelMetadata.BinderModelName != null;
|
||||||
|
|
||||||
// The fact that this has reached here,
|
// The fact that this has reached here,
|
||||||
// it is a complex object which was not directly bound by any previous model binders.
|
// it is a complex object which was not directly bound by any previous model binders.
|
||||||
// Check if this was supposed to be handled by a non value provider based binder.
|
// Check if this was supposed to be handled by a non value provider based binder.
|
||||||
// if it was then it should be not be bound using mutable object binder.
|
// if it was then it should be not be bound using mutable object binder.
|
||||||
// This check would prevent it from recursing in if a model contains a property of its own type.
|
// This check would prevent it from recursing in if a model contains a property of its own type.
|
||||||
// We skip this check if it is a top level object because we want to always evaluate
|
// We skip this check if it is a top level object because we want to always evaluate
|
||||||
// the creation of top level object (this is also required for ModelBinderAttribute to work.)
|
// the creation of top level object (this is also required for ModelBinderAttribute to work.)
|
||||||
if (!isTopLevelObject &&
|
if (!isTopLevelObject &&
|
||||||
bindingContext.ModelMetadata.BinderMetadata != null &&
|
bindingContext.ModelMetadata.BinderMetadata != null &&
|
||||||
|
|
@ -68,14 +68,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the object if :
|
// Create the object if :
|
||||||
// 1. It is a top level model with an explicit user supplied prefix.
|
// 1. It is a top level model with an explicit user supplied prefix.
|
||||||
// In this case since it will never fallback to empty prefix, we need to create the model here.
|
// In this case since it will never fallback to empty prefix, we need to create the model here.
|
||||||
if (isTopLevelObject && isThereAnExplicitAlias)
|
if (isTopLevelObject && hasExplicitAlias)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. It is a top level object and there is no model name ( Fallback to empty prefix case ).
|
// 2. It is a top level object and there is no model name ( Fallback to empty prefix case ).
|
||||||
// This is necessary as we do not want to depend on a value provider to contain an empty prefix.
|
// This is necessary as we do not want to depend on a value provider to contain an empty prefix.
|
||||||
if (isTopLevelObject && bindingContext.ModelName == string.Empty)
|
if (isTopLevelObject && bindingContext.ModelName == string.Empty)
|
||||||
{
|
{
|
||||||
|
|
@ -83,9 +83,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. The model name is not prefixed and a value provider can directly provide a value for the model name.
|
// 3. The model name is not prefixed and a value provider can directly provide a value for the model name.
|
||||||
// The fact that it is not prefixed means that the containsPrefixAsync call checks for the exact model name
|
// The fact that it is not prefixed means that the containsPrefixAsync call checks for the exact
|
||||||
// instead of doing a prefix match.
|
// model name instead of doing a prefix match.
|
||||||
if (!bindingContext.ModelName.Contains(".") &&
|
if (!bindingContext.ModelName.Contains(".") &&
|
||||||
await bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName))
|
await bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -103,11 +103,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
private async Task<bool> CanValueBindAnyModelProperties(MutableObjectBinderContext context)
|
private async Task<bool> CanValueBindAnyModelProperties(MutableObjectBinderContext context)
|
||||||
{
|
{
|
||||||
// We need to enumerate the non marked properties and properties marked with IValueProviderMetadata
|
// We need to enumerate the non marked properties and properties marked with IValueProviderMetadata
|
||||||
// instead of checking bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName)
|
// instead of checking bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName)
|
||||||
// because there can be a case
|
// because there can be a case where a value provider might be willing to provide a marked property,
|
||||||
// where a value provider might be willing to provide a marked property, which might never be bound.
|
// which might never be bound.
|
||||||
// For example if person.Name is marked with FromQuery, and FormValueProvider has a key person.Name, and the
|
// For example if person.Name is marked with FromQuery, and FormValueProvider has a key person.Name,
|
||||||
// QueryValueProvider does not, we do not want to create Person.
|
// and the QueryValueProvider does not, we do not want to create Person.
|
||||||
var isAnyPropertyEnabledForValueProviderBasedBinding = false;
|
var isAnyPropertyEnabledForValueProviderBasedBinding = false;
|
||||||
foreach (var propertyMetadata in context.PropertyMetadata)
|
foreach (var propertyMetadata in context.PropertyMetadata)
|
||||||
{
|
{
|
||||||
|
|
@ -144,7 +144,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
if (valueProviderMetadata != null)
|
if (valueProviderMetadata != null)
|
||||||
{
|
{
|
||||||
// if there is a binder metadata and since the property can be bound using a value provider.
|
// if there is a binder metadata and since the property can be bound using a value provider.
|
||||||
var metadataAwareValueProvider = bindingContext.OperationBindingContext.ValueProvider as IMetadataAwareValueProvider;
|
var metadataAwareValueProvider =
|
||||||
|
bindingContext.OperationBindingContext.ValueProvider as IMetadataAwareValueProvider;
|
||||||
if (metadataAwareValueProvider != null)
|
if (metadataAwareValueProvider != null)
|
||||||
{
|
{
|
||||||
valueProvider = metadataAwareValueProvider.Filter(valueProviderMetadata);
|
valueProvider = metadataAwareValueProvider.Filter(valueProviderMetadata);
|
||||||
|
|
@ -268,19 +269,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
protected virtual IEnumerable<ModelMetadata> GetMetadataForProperties(ModelBindingContext bindingContext)
|
protected virtual IEnumerable<ModelMetadata> GetMetadataForProperties(ModelBindingContext bindingContext)
|
||||||
{
|
{
|
||||||
var validationInfo = GetPropertyValidationInfo(bindingContext);
|
var validationInfo = GetPropertyValidationInfo(bindingContext);
|
||||||
var propertyTypeMetadata = bindingContext.OperationBindingContext
|
|
||||||
.MetadataProvider
|
|
||||||
.GetMetadataForType(null, bindingContext.ModelType);
|
|
||||||
Predicate<string> newPropertyFilter =
|
|
||||||
propertyName => bindingContext.PropertyFilter(propertyName) &&
|
|
||||||
BindAttribute.IsPropertyAllowed(
|
|
||||||
propertyName,
|
|
||||||
propertyTypeMetadata.IncludedProperties,
|
|
||||||
propertyTypeMetadata.ExcludedProperties);
|
|
||||||
|
|
||||||
return bindingContext.ModelMetadata.Properties
|
return bindingContext.ModelMetadata.Properties
|
||||||
.Where(propertyMetadata =>
|
.Where(propertyMetadata =>
|
||||||
newPropertyFilter(propertyMetadata.PropertyName) &&
|
bindingContext.PropertyFilter(propertyMetadata.PropertyName) &&
|
||||||
(validationInfo.RequiredProperties.Contains(propertyMetadata.PropertyName) ||
|
(validationInfo.RequiredProperties.Contains(propertyMetadata.PropertyName) ||
|
||||||
!validationInfo.SkipProperties.Contains(propertyMetadata.PropertyName)) &&
|
!validationInfo.SkipProperties.Contains(propertyMetadata.PropertyName)) &&
|
||||||
CanUpdateProperty(propertyMetadata));
|
CanUpdateProperty(propertyMetadata));
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an entity which has binding information for a model.
|
/// Represents an entity which has binding information for a model.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IModelPropertyBindingInfo
|
public interface IPropertyBindingInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Comma separated set of properties which are to be excluded during model binding.
|
/// Comma separated set of properties which are to be excluded during model binding.
|
||||||
|
|
@ -49,9 +49,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public ModelMetadata GetMetadataForParameter(
|
public ModelMetadata GetMetadataForParameter(
|
||||||
Func<object> modelAccessor,
|
Func<object> modelAccessor,
|
||||||
[NotNull] MethodInfo methodInfo,
|
[NotNull] MethodInfo methodInfo,
|
||||||
[NotNull] string parameterName,
|
[NotNull] string parameterName)
|
||||||
IBinderMetadata binderMetadata)
|
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(parameterName))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "parameterName");
|
||||||
|
}
|
||||||
|
|
||||||
var parameter = methodInfo.GetParameters().FirstOrDefault(
|
var parameter = methodInfo.GetParameters().FirstOrDefault(
|
||||||
param => StringComparer.Ordinal.Equals(param.Name, parameterName));
|
param => StringComparer.Ordinal.Equals(param.Name, parameterName));
|
||||||
if (parameter == null)
|
if (parameter == null)
|
||||||
|
|
@ -60,11 +64,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
throw new ArgumentException(message, nameof(parameterName));
|
throw new ArgumentException(message, nameof(parameterName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetMetadataForParameterCore(modelAccessor, parameterName, parameter, binderMetadata);
|
return GetMetadataForParameterCore(modelAccessor, parameterName, parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override for creating the prototype metadata (without the accessor)
|
// Override for creating the prototype metadata (without the accessor)
|
||||||
protected abstract TModelMetadata CreateMetadataPrototype(IEnumerable<Attribute> attributes,
|
protected abstract TModelMetadata CreateMetadataPrototype(IEnumerable<object> attributes,
|
||||||
Type containerType,
|
Type containerType,
|
||||||
Type modelType,
|
Type modelType,
|
||||||
string propertyName);
|
string propertyName);
|
||||||
|
|
@ -72,27 +76,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
// Override for applying the prototype + modelAccess to yield the final metadata
|
// Override for applying the prototype + modelAccess to yield the final metadata
|
||||||
protected abstract TModelMetadata CreateMetadataFromPrototype(TModelMetadata prototype,
|
protected abstract TModelMetadata CreateMetadataFromPrototype(TModelMetadata prototype,
|
||||||
Func<object> modelAccessor);
|
Func<object> modelAccessor);
|
||||||
|
|
||||||
private ModelMetadata GetMetadataForParameterCore(Func<object> modelAccessor,
|
private ModelMetadata GetMetadataForParameterCore(Func<object> modelAccessor,
|
||||||
string parameterName,
|
string parameterName,
|
||||||
ParameterInfo parameter,
|
ParameterInfo parameter)
|
||||||
IBinderMetadata binderMetadata)
|
|
||||||
{
|
{
|
||||||
var parameterInfo =
|
var parameterInfo =
|
||||||
CreateParameterInfo(parameter.ParameterType,
|
CreateParameterInfo(parameter.ParameterType,
|
||||||
parameter.GetCustomAttributes(),
|
ModelAttributes.GetAttributesForParameter(parameter),
|
||||||
parameterName,
|
parameterName);
|
||||||
binderMetadata);
|
|
||||||
|
|
||||||
var metadata = CreateMetadataFromPrototype(parameterInfo.Prototype, modelAccessor);
|
var metadata = CreateMetadataFromPrototype(parameterInfo.Prototype, modelAccessor);
|
||||||
|
|
||||||
|
|
||||||
// If there is no metadata associated with the parameter itself get it from the type.
|
|
||||||
if (metadata != null && metadata.BinderMetadata == null)
|
|
||||||
{
|
|
||||||
var typeInfo = GetTypeInformation(parameter.ParameterType);
|
|
||||||
metadata.BinderMetadata = typeInfo.Prototype.BinderMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,18 +119,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
metadata.IsReadOnly = true;
|
metadata.IsReadOnly = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to update the property after the prototype creation because otherwise
|
|
||||||
// if the property type is same as the containing type, it would cause infinite recursion.
|
|
||||||
// If there is no metadata associated with the property itself get it from the type.
|
|
||||||
if (metadata != null && metadata.BinderMetadata == null)
|
|
||||||
{
|
|
||||||
if (propertyInfo.Prototype != null)
|
|
||||||
{
|
|
||||||
var typeInfo = GetTypeInformation(propertyInfo.Prototype.ModelType);
|
|
||||||
metadata.BinderMetadata = typeInfo.Prototype.BinderMetadata;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,7 +171,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
return new PropertyInformation
|
return new PropertyInformation
|
||||||
{
|
{
|
||||||
PropertyHelper = helper,
|
PropertyHelper = helper,
|
||||||
Prototype = CreateMetadataPrototype(property.GetCustomAttributes(),
|
Prototype = CreateMetadataPrototype(ModelAttributes.GetAttributesForProperty(property),
|
||||||
containerType,
|
containerType,
|
||||||
property.PropertyType,
|
property.PropertyType,
|
||||||
property.Name),
|
property.Name),
|
||||||
|
|
@ -199,26 +181,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
private ParameterInformation CreateParameterInfo(
|
private ParameterInformation CreateParameterInfo(
|
||||||
Type parameterType,
|
Type parameterType,
|
||||||
IEnumerable<Attribute> attributes,
|
IEnumerable<object> attributes,
|
||||||
string parameterName,
|
string parameterName)
|
||||||
IBinderMetadata binderMetadata)
|
|
||||||
{
|
{
|
||||||
var metadataProtoType = CreateMetadataPrototype(attributes: attributes,
|
var metadataProtoType = CreateMetadataPrototype(attributes: attributes,
|
||||||
containerType: null,
|
containerType: null,
|
||||||
modelType: parameterType,
|
modelType: parameterType,
|
||||||
propertyName: parameterName);
|
propertyName: parameterName);
|
||||||
|
|
||||||
if (binderMetadata != null)
|
|
||||||
{
|
|
||||||
metadataProtoType.BinderMetadata = binderMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
var nameProvider = binderMetadata as IModelNameProvider;
|
|
||||||
if (nameProvider != null && nameProvider.Name != null)
|
|
||||||
{
|
|
||||||
metadataProtoType.ModelName = nameProvider.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ParameterInformation
|
return new ParameterInformation
|
||||||
{
|
{
|
||||||
Prototype = metadataProtoType
|
Prototype = metadataProtoType
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
public class CachedDataAnnotationsMetadataAttributes
|
public class CachedDataAnnotationsMetadataAttributes
|
||||||
{
|
{
|
||||||
public CachedDataAnnotationsMetadataAttributes(IEnumerable<Attribute> attributes)
|
public CachedDataAnnotationsMetadataAttributes(IEnumerable<object> attributes)
|
||||||
{
|
{
|
||||||
DataType = attributes.OfType<DataTypeAttribute>().FirstOrDefault();
|
DataType = attributes.OfType<DataTypeAttribute>().FirstOrDefault();
|
||||||
Display = attributes.OfType<DisplayAttribute>().FirstOrDefault();
|
Display = attributes.OfType<DisplayAttribute>().FirstOrDefault();
|
||||||
|
|
@ -20,6 +20,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
HiddenInput = attributes.OfType<HiddenInputAttribute>().FirstOrDefault();
|
HiddenInput = attributes.OfType<HiddenInputAttribute>().FirstOrDefault();
|
||||||
Required = attributes.OfType<RequiredAttribute>().FirstOrDefault();
|
Required = attributes.OfType<RequiredAttribute>().FirstOrDefault();
|
||||||
ScaffoldColumn = attributes.OfType<ScaffoldColumnAttribute>().FirstOrDefault();
|
ScaffoldColumn = attributes.OfType<ScaffoldColumnAttribute>().FirstOrDefault();
|
||||||
|
BinderMetadata = attributes.OfType<IBinderMetadata>().FirstOrDefault();
|
||||||
|
PropertyBindingInfo = attributes.OfType<IPropertyBindingInfo>();
|
||||||
|
BinderModelNameProvider = attributes.OfType<IModelNameProvider>().FirstOrDefault();
|
||||||
|
|
||||||
// Special case the [DisplayFormat] attribute hanging off an applied [DataType] attribute. This property is
|
// Special case the [DisplayFormat] attribute hanging off an applied [DataType] attribute. This property is
|
||||||
// non-null for DataType.Currency, DataType.Date, DataType.Time, and potentially custom [DataType]
|
// non-null for DataType.Currency, DataType.Date, DataType.Time, and potentially custom [DataType]
|
||||||
|
|
@ -32,9 +35,21 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets (or sets in subclasses) <see cref="IBinderMetadata"/> found in collection passed to the
|
||||||
|
/// <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{object})"/> constructor, if any.
|
||||||
|
/// </summary>
|
||||||
|
public IBinderMetadata BinderMetadata { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets (or sets in subclasses) <see cref="IModelNameProvider"/> found in collection passed to the
|
||||||
|
/// <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{object})"/> constructor, if any.
|
||||||
|
/// </summary>
|
||||||
|
public IModelNameProvider BinderModelNameProvider { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets (or sets in subclasses) <see cref="DataTypeAttribute"/> found in collection passed to the
|
/// Gets (or sets in subclasses) <see cref="DataTypeAttribute"/> found in collection passed to the
|
||||||
/// <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{Attribute})"/> constructor, if any.
|
/// <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{object})"/> constructor, if any.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DataTypeAttribute DataType { get; protected set; }
|
public DataTypeAttribute DataType { get; protected set; }
|
||||||
|
|
||||||
|
|
@ -44,7 +59,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets (or sets in subclasses) <see cref="DisplayFormatAttribute"/> found in collection passed to the
|
/// Gets (or sets in subclasses) <see cref="DisplayFormatAttribute"/> found in collection passed to the
|
||||||
/// <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{Attribute})"/> constructor, if any.
|
/// <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{object})"/> constructor, if any.
|
||||||
/// If no such attribute was found but a <see cref="DataTypeAttribute"/> was, gets the
|
/// If no such attribute was found but a <see cref="DataTypeAttribute"/> was, gets the
|
||||||
/// <see cref="DataTypeAttribute.DisplayFormat"/> value.
|
/// <see cref="DataTypeAttribute.DisplayFormat"/> value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -54,10 +69,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets (or sets in subclasses) <see cref="HiddenInputAttribute"/> found in collection passed to the
|
/// Gets (or sets in subclasses) <see cref="HiddenInputAttribute"/> found in collection passed to the
|
||||||
/// <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{Attribute})"/> constructor, if any.
|
/// <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{object})"/> constructor, if any.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HiddenInputAttribute HiddenInput { get; protected set; }
|
public HiddenInputAttribute HiddenInput { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets (or sets in subclasses) <see cref="IEnumerable{IModelPropertyBindingInfo}"/> found in collection
|
||||||
|
/// passed to the <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{object})"/> constructor,
|
||||||
|
/// if any.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<IPropertyBindingInfo> PropertyBindingInfo { get; protected set; }
|
||||||
|
|
||||||
public RequiredAttribute Required { get; protected set; }
|
public RequiredAttribute Required { get; protected set; }
|
||||||
|
|
||||||
public ScaffoldColumnAttribute ScaffoldColumn { get; protected set; }
|
public ScaffoldColumnAttribute ScaffoldColumn { get; protected set; }
|
||||||
|
|
|
||||||
|
|
@ -26,20 +26,79 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Type containerType,
|
Type containerType,
|
||||||
Type modelType,
|
Type modelType,
|
||||||
string propertyName,
|
string propertyName,
|
||||||
IEnumerable<Attribute> attributes)
|
IEnumerable<object> attributes)
|
||||||
: base(provider,
|
: base(provider,
|
||||||
containerType,
|
containerType,
|
||||||
modelType,
|
modelType,
|
||||||
propertyName,
|
propertyName,
|
||||||
new CachedDataAnnotationsMetadataAttributes(attributes))
|
new CachedDataAnnotationsMetadataAttributes(attributes))
|
||||||
{
|
{
|
||||||
BinderMetadata = attributes.OfType<IBinderMetadata>().FirstOrDefault();
|
}
|
||||||
|
|
||||||
var modelNameProvider = attributes.OfType<IModelNameProvider>().FirstOrDefault();
|
protected override IBinderMetadata ComputeBinderMetadata()
|
||||||
ModelName = modelNameProvider?.Name;
|
{
|
||||||
|
return PrototypeCache.BinderMetadata != null
|
||||||
|
? PrototypeCache.BinderMetadata
|
||||||
|
: base.ComputeBinderMetadata();
|
||||||
|
}
|
||||||
|
|
||||||
var bindAttribute = attributes.OfType<BindAttribute>().FirstOrDefault();
|
protected override string ComputeBinderModelNamePrefix()
|
||||||
ReadSettingsFromBindAttribute(bindAttribute);
|
{
|
||||||
|
return PrototypeCache.BinderModelNameProvider != null
|
||||||
|
? PrototypeCache.BinderModelNameProvider.Name
|
||||||
|
: base.ComputeBinderModelNamePrefix();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IReadOnlyList<string> ComputeBinderIncludeProperties()
|
||||||
|
{
|
||||||
|
var propertyBindingInfo = PrototypeCache.PropertyBindingInfo?.ToList();
|
||||||
|
if (propertyBindingInfo != null && propertyBindingInfo.Count != 0)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(propertyBindingInfo[0].Include))
|
||||||
|
{
|
||||||
|
return Properties.Select(property => property.PropertyName).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
var includeFirst = SplitString(propertyBindingInfo[0].Include).ToList();
|
||||||
|
if (propertyBindingInfo.Count != 2)
|
||||||
|
{
|
||||||
|
return includeFirst;
|
||||||
|
}
|
||||||
|
|
||||||
|
var includedAtType = SplitString(propertyBindingInfo[1].Include).ToList();
|
||||||
|
|
||||||
|
if (includeFirst.Count == 0 && includedAtType.Count == 0)
|
||||||
|
{
|
||||||
|
// Need to include everything by default.
|
||||||
|
return Properties.Select(property => property.PropertyName).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return includeFirst.Intersect(includedAtType).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to include everything by default.
|
||||||
|
return Properties.Select(property => property.PropertyName).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IReadOnlyList<string> ComputeBinderExcludeProperties()
|
||||||
|
{
|
||||||
|
var propertyBindingInfo = PrototypeCache.PropertyBindingInfo?.ToList();
|
||||||
|
if (propertyBindingInfo != null && propertyBindingInfo.Count != 0)
|
||||||
|
{
|
||||||
|
var excludeFirst = SplitString(propertyBindingInfo[0].Exclude).ToList();
|
||||||
|
|
||||||
|
if (propertyBindingInfo.Count != 2)
|
||||||
|
{
|
||||||
|
return excludeFirst;
|
||||||
|
}
|
||||||
|
|
||||||
|
var excludedAtType = SplitString(propertyBindingInfo[1].Exclude).ToList();
|
||||||
|
return excludeFirst.Union(excludedAtType).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.ComputeBinderExcludeProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool ComputeConvertEmptyStringToNull()
|
protected override bool ComputeConvertEmptyStringToNull()
|
||||||
|
|
@ -291,17 +350,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadSettingsFromBindAttribute(BindAttribute bindAttribute)
|
|
||||||
{
|
|
||||||
if (bindAttribute == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExcludedProperties = SplitString(bindAttribute.Exclude).ToList();
|
|
||||||
IncludedProperties = SplitString(bindAttribute.Include).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<string> SplitString(string original)
|
private static IEnumerable<string> SplitString(string original)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(original))
|
if (string.IsNullOrEmpty(original))
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
|
|
@ -30,6 +31,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
private bool _isRequired;
|
private bool _isRequired;
|
||||||
private bool _showForDisplay;
|
private bool _showForDisplay;
|
||||||
private bool _showForEdit;
|
private bool _showForEdit;
|
||||||
|
private IBinderMetadata _binderMetadata;
|
||||||
|
private string _binderModelName;
|
||||||
|
private IReadOnlyList<string> _binderIncludeProperties;
|
||||||
|
private IReadOnlyList<string> _binderExcludeProperties;
|
||||||
|
|
||||||
private bool _convertEmptyStringToNullComputed;
|
private bool _convertEmptyStringToNullComputed;
|
||||||
private bool _nullDisplayTextComputed;
|
private bool _nullDisplayTextComputed;
|
||||||
|
|
@ -46,6 +51,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
private bool _isRequiredComputed;
|
private bool _isRequiredComputed;
|
||||||
private bool _showForDisplayComputed;
|
private bool _showForDisplayComputed;
|
||||||
private bool _showForEditComputed;
|
private bool _showForEditComputed;
|
||||||
|
private bool _isBinderMetadataComputed;
|
||||||
|
private bool _isBinderIncludePropertiesComputed;
|
||||||
|
private bool _isBinderModelNameComputed;
|
||||||
|
private bool _isBinderExcludePropertiesComputed;
|
||||||
|
|
||||||
// Constructor for creating real instances of the metadata class based on a prototype
|
// Constructor for creating real instances of the metadata class based on a prototype
|
||||||
protected CachedModelMetadata(CachedModelMetadata<TPrototypeCache> prototype, Func<object> modelAccessor)
|
protected CachedModelMetadata(CachedModelMetadata<TPrototypeCache> prototype, Func<object> modelAccessor)
|
||||||
|
|
@ -57,10 +66,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
CacheKey = prototype.CacheKey;
|
CacheKey = prototype.CacheKey;
|
||||||
PrototypeCache = prototype.PrototypeCache;
|
PrototypeCache = prototype.PrototypeCache;
|
||||||
BinderMetadata = prototype.BinderMetadata;
|
|
||||||
IncludedProperties = prototype.IncludedProperties;
|
|
||||||
ExcludedProperties = prototype.ExcludedProperties;
|
|
||||||
ModelName = prototype.ModelName;
|
|
||||||
_isComplexType = prototype.IsComplexType;
|
_isComplexType = prototype.IsComplexType;
|
||||||
_isComplexTypeComputed = true;
|
_isComplexTypeComputed = true;
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +81,91 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
PrototypeCache = prototypeCache;
|
PrototypeCache = prototypeCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public sealed override IBinderMetadata BinderMetadata
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_isBinderMetadataComputed)
|
||||||
|
{
|
||||||
|
_binderMetadata = ComputeBinderMetadata();
|
||||||
|
_isBinderMetadataComputed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _binderMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_binderMetadata = value;
|
||||||
|
_isBinderMetadataComputed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public sealed override IReadOnlyList<string> BinderIncludeProperties
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_isBinderIncludePropertiesComputed)
|
||||||
|
{
|
||||||
|
_binderIncludeProperties = ComputeBinderIncludeProperties();
|
||||||
|
_isBinderIncludePropertiesComputed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _binderIncludeProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_binderIncludeProperties = value;
|
||||||
|
_isBinderIncludePropertiesComputed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public sealed override IReadOnlyList<string> BinderExcludeProperties
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_isBinderExcludePropertiesComputed)
|
||||||
|
{
|
||||||
|
_binderExcludeProperties = ComputeBinderExcludeProperties();
|
||||||
|
_isBinderExcludePropertiesComputed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _binderExcludeProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_binderExcludeProperties = value;
|
||||||
|
_isBinderExcludePropertiesComputed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public sealed override string BinderModelName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_isBinderModelNameComputed)
|
||||||
|
{
|
||||||
|
_binderModelName = ComputeBinderModelNamePrefix();
|
||||||
|
_isBinderModelNameComputed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _binderModelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_binderModelName = value;
|
||||||
|
_isBinderModelNameComputed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public sealed override bool ConvertEmptyStringToNull
|
public sealed override bool ConvertEmptyStringToNull
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -94,24 +184,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed override string NullDisplayText
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (!_nullDisplayTextComputed)
|
|
||||||
{
|
|
||||||
_nullDisplayText = ComputeNullDisplayText();
|
|
||||||
_nullDisplayTextComputed = true;
|
|
||||||
}
|
|
||||||
return _nullDisplayText;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_nullDisplayText = value;
|
|
||||||
_nullDisplayTextComputed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public sealed override string DataTypeName
|
public sealed override string DataTypeName
|
||||||
{
|
{
|
||||||
|
|
@ -133,6 +205,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public sealed override string Description
|
public sealed override string Description
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -172,6 +245,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public sealed override string DisplayName
|
public sealed override string DisplayName
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -275,6 +349,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public sealed override bool IsReadOnly
|
public sealed override bool IsReadOnly
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -293,6 +368,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public sealed override bool IsRequired
|
public sealed override bool IsRequired
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -311,6 +387,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public sealed override bool IsComplexType
|
public sealed override bool IsComplexType
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -324,6 +401,26 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public sealed override string NullDisplayText
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_nullDisplayTextComputed)
|
||||||
|
{
|
||||||
|
_nullDisplayText = ComputeNullDisplayText();
|
||||||
|
_nullDisplayTextComputed = true;
|
||||||
|
}
|
||||||
|
return _nullDisplayText;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_nullDisplayText = value;
|
||||||
|
_nullDisplayTextComputed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public sealed override bool ShowForDisplay
|
public sealed override bool ShowForDisplay
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -342,6 +439,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public sealed override bool ShowForEdit
|
public sealed override bool ShowForEdit
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -377,16 +475,31 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
protected TPrototypeCache PrototypeCache { get; set; }
|
protected TPrototypeCache PrototypeCache { get; set; }
|
||||||
|
|
||||||
|
protected virtual IBinderMetadata ComputeBinderMetadata()
|
||||||
|
{
|
||||||
|
return base.BinderMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual IReadOnlyList<string> ComputeBinderIncludeProperties()
|
||||||
|
{
|
||||||
|
return base.BinderIncludeProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual IReadOnlyList<string> ComputeBinderExcludeProperties()
|
||||||
|
{
|
||||||
|
return base.BinderExcludeProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual string ComputeBinderModelNamePrefix()
|
||||||
|
{
|
||||||
|
return base.BinderModelName;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual bool ComputeConvertEmptyStringToNull()
|
protected virtual bool ComputeConvertEmptyStringToNull()
|
||||||
{
|
{
|
||||||
return base.ConvertEmptyStringToNull;
|
return base.ConvertEmptyStringToNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string ComputeNullDisplayText()
|
|
||||||
{
|
|
||||||
return base.NullDisplayText;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculate the <see cref="DataTypeName"/> value.
|
/// Calculate the <see cref="DataTypeName"/> value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -466,6 +579,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
return base.IsComplexType;
|
return base.IsComplexType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual string ComputeNullDisplayText()
|
||||||
|
{
|
||||||
|
return base.NullDisplayText;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual bool ComputeShowForDisplay()
|
protected virtual bool ComputeShowForDisplay()
|
||||||
{
|
{
|
||||||
return base.ShowForDisplay;
|
return base.ShowForDisplay;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public class DataAnnotationsModelMetadataProvider : AssociatedMetadataProvider<CachedDataAnnotationsModelMetadata>
|
public class DataAnnotationsModelMetadataProvider : AssociatedMetadataProvider<CachedDataAnnotationsModelMetadata>
|
||||||
{
|
{
|
||||||
protected override CachedDataAnnotationsModelMetadata CreateMetadataPrototype(
|
protected override CachedDataAnnotationsModelMetadata CreateMetadataPrototype(
|
||||||
IEnumerable<Attribute> attributes,
|
IEnumerable<object> attributes,
|
||||||
Type containerType,
|
Type containerType,
|
||||||
Type modelType,
|
Type modelType,
|
||||||
string propertyName)
|
string propertyName)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
public class EmptyModelMetadataProvider : AssociatedMetadataProvider<ModelMetadata>
|
public class EmptyModelMetadataProvider : AssociatedMetadataProvider<ModelMetadata>
|
||||||
{
|
{
|
||||||
protected override ModelMetadata CreateMetadataPrototype(IEnumerable<Attribute> attributes,
|
protected override ModelMetadata CreateMetadataPrototype(IEnumerable<object> attributes,
|
||||||
Type containerType,
|
Type containerType,
|
||||||
Type modelType,
|
Type modelType,
|
||||||
string propertyName)
|
string propertyName)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
ModelMetadata GetMetadataForParameter(
|
ModelMetadata GetMetadataForParameter(
|
||||||
Func<object> modelAccessor,
|
Func<object> modelAccessor,
|
||||||
[NotNull] MethodInfo methodInfo,
|
[NotNull] MethodInfo methodInfo,
|
||||||
[NotNull] string parameterName,
|
[NotNull] string parameterName);
|
||||||
IBinderMetadata binderMetadata);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides static methods which can be used to get a combined list of attributes associated
|
||||||
|
/// with a parameter or property.
|
||||||
|
/// </summary>
|
||||||
|
public static class ModelAttributes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the attributes for the given <paramref name="parameter"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameter">A <see cref="ParameterInfo"/> for which attributes need to be resolved.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{object}"/> containing the attributes on the
|
||||||
|
/// <paramref name="parameter"/> before the attributes on the <paramref name="parameter"/> type.</returns>
|
||||||
|
public static IEnumerable<object> GetAttributesForParameter(ParameterInfo parameter)
|
||||||
|
{
|
||||||
|
// Return the parameter attributes first.
|
||||||
|
var parameterAttributes = parameter.GetCustomAttributes();
|
||||||
|
var typeAttributes = parameter.ParameterType.GetTypeInfo().GetCustomAttributes();
|
||||||
|
|
||||||
|
return parameterAttributes.Concat(typeAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the attributes for the given <paramref name="property"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="property">A <see cref="ParameterInfo"/> for which attributes need to be resolved.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{object}"/> containing the attributes on the
|
||||||
|
/// <paramref name="property"/> before the attributes on the <paramref name="property"/> type.</returns>
|
||||||
|
public static IEnumerable<object> GetAttributesForProperty(PropertyInfo property)
|
||||||
|
{
|
||||||
|
// Return the property attributes first.
|
||||||
|
var propertyAttributes = property.GetCustomAttributes();
|
||||||
|
var typeAttributes = property.PropertyType.GetTypeInfo().GetCustomAttributes();
|
||||||
|
|
||||||
|
return propertyAttributes.Concat(typeAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -50,22 +50,22 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the name of a model if specified explicitly using <see cref="IModelNameProvider"/>.
|
/// Represents the name of a model if specified explicitly using <see cref="IModelNameProvider"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ModelName { get; set; }
|
public virtual string BinderModelName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Properties which are marked as Included for this model.
|
/// Properties which are to be included while binding this model.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IReadOnlyList<string> IncludedProperties { get; set; }
|
public virtual IReadOnlyList<string> BinderIncludeProperties { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Properties which are marked as Excluded for this model.
|
/// Properties which are to be excluded while binding this model.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IReadOnlyList<string> ExcludedProperties { get; set; }
|
public virtual IReadOnlyList<string> BinderExcludeProperties { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a binder metadata for this model.
|
/// Gets or sets a binder metadata for this model.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IBinderMetadata BinderMetadata { get; set; }
|
public virtual IBinderMetadata BinderMetadata { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A reference to the model's container <see cref="object"/>.
|
/// A reference to the model's container <see cref="object"/>.
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
@ -23,30 +24,115 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ParameterHasFieldPrefix([Bind(Prefix = "bar")] string foo)
|
public void ParameterWithNoBindAttribute(MySimpleModelWithTypeBasedBind parameter)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ParameterHasEmptyFieldPrefix([Bind(Prefix = "")] MySimpleModel foo,
|
public void ParameterHasFieldPrefix([Bind(Prefix = "simpleModelPrefix")] string parameter)
|
||||||
[Bind(Prefix = "")] MySimpleModelWithTypeBasedBind foo1)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ParameterHasPrefixAndComplexType([Bind(Prefix = "bar")] MySimpleModel foo,
|
public void ParameterHasEmptyFieldPrefix([Bind(Prefix = "")] MySimpleModel parameter,
|
||||||
[Bind(Prefix = "bar")] MySimpleModelWithTypeBasedBind foo1)
|
[Bind(Prefix = "")] MySimpleModelWithTypeBasedBind parameter1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ParameterHasEmptyBindAttribute([Bind] MySimpleModel foo,
|
public void ParameterHasPrefixAndComplexType(
|
||||||
[Bind] MySimpleModelWithTypeBasedBind foo1)
|
[Bind(Prefix = "simpleModelPrefix")] MySimpleModel parameter,
|
||||||
|
[Bind(Prefix = "simpleModelPrefix")] MySimpleModelWithTypeBasedBind parameter1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ParameterHasEmptyBindAttribute([Bind] MySimpleModel parameter,
|
||||||
|
[Bind] MySimpleModelWithTypeBasedBind parameter1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetModelBindingContext_DoesNotReturn_ExcludedProperties()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var actionContext = new ActionContext(new RouteContext(Mock.Of<HttpContext>()),
|
||||||
|
Mock.Of<ActionDescriptor>());
|
||||||
|
|
||||||
|
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
var modelMetadata = metadataProvider.GetMetadataForType(
|
||||||
|
modelAccessor: null, modelType: typeof(TypeWithExcludedPropertiesUsingBindAttribute));
|
||||||
|
|
||||||
|
var actionBindingContext = new ActionBindingContext(actionContext,
|
||||||
|
Mock.Of<IModelMetadataProvider>(),
|
||||||
|
Mock.Of<IModelBinder>(),
|
||||||
|
Mock.Of<IValueProvider>(),
|
||||||
|
Mock.Of<IInputFormatterSelector>(),
|
||||||
|
Mock.Of<IModelValidatorProvider>());
|
||||||
|
// Act
|
||||||
|
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||||
|
modelMetadata, actionBindingContext, Mock.Of<OperationBindingContext>());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(context.PropertyFilter("Excluded1"));
|
||||||
|
Assert.False(context.PropertyFilter("Excluded2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetModelBindingContext_ReturnsOnlyWhiteListedProperties_UsingBindAttributeInclude()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var actionContext = new ActionContext(new RouteContext(Mock.Of<HttpContext>()),
|
||||||
|
Mock.Of<ActionDescriptor>());
|
||||||
|
|
||||||
|
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
var modelMetadata = metadataProvider.GetMetadataForType(
|
||||||
|
modelAccessor: null, modelType: typeof(TypeWithIncludedPropertiesUsingBindAttribute));
|
||||||
|
|
||||||
|
var actionBindingContext = new ActionBindingContext(actionContext,
|
||||||
|
Mock.Of<IModelMetadataProvider>(),
|
||||||
|
Mock.Of<IModelBinder>(),
|
||||||
|
Mock.Of<IValueProvider>(),
|
||||||
|
Mock.Of<IInputFormatterSelector>(),
|
||||||
|
Mock.Of<IModelValidatorProvider>());
|
||||||
|
// Act
|
||||||
|
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||||
|
modelMetadata, actionBindingContext, Mock.Of<OperationBindingContext>());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(context.PropertyFilter("IncludedExplicitly1"));
|
||||||
|
Assert.True(context.PropertyFilter("IncludedExplicitly2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetModelBindingContext_UsesBindAttributeOnType_IfNoBindAttributeOnParameter_ForPrefix()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var type = typeof(ControllerActionArgumentBinderTests);
|
||||||
|
var methodInfo = type.GetMethod("ParameterWithNoBindAttribute");
|
||||||
|
var actionContext = new ActionContext(new RouteContext(Mock.Of<HttpContext>()),
|
||||||
|
Mock.Of<ActionDescriptor>());
|
||||||
|
|
||||||
|
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
var modelMetadata = metadataProvider.GetMetadataForParameter(modelAccessor: null,
|
||||||
|
methodInfo: methodInfo,
|
||||||
|
parameterName: "parameter");
|
||||||
|
|
||||||
|
var actionBindingContext = new ActionBindingContext(actionContext,
|
||||||
|
Mock.Of<IModelMetadataProvider>(),
|
||||||
|
Mock.Of<IModelBinder>(),
|
||||||
|
Mock.Of<IValueProvider>(),
|
||||||
|
Mock.Of<IInputFormatterSelector>(),
|
||||||
|
Mock.Of<IModelValidatorProvider>());
|
||||||
|
// Act
|
||||||
|
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||||
|
modelMetadata, actionBindingContext, Mock.Of<OperationBindingContext>());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("TypePrefix", context.ModelName);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("ParameterHasFieldPrefix", false, "bar")]
|
[InlineData("ParameterHasFieldPrefix", false, "simpleModelPrefix")]
|
||||||
[InlineData("ParameterHasEmptyFieldPrefix", false, "")]
|
[InlineData("ParameterHasEmptyFieldPrefix", false, "")]
|
||||||
[InlineData("ParameterHasPrefixAndComplexType", false, "bar")]
|
[InlineData("ParameterHasPrefixAndComplexType", false, "simpleModelPrefix")]
|
||||||
[InlineData("ParameterHasEmptyBindAttribute", true, "foo")]
|
[InlineData("ParameterHasEmptyBindAttribute", true, "parameter")]
|
||||||
public void GetModelBindingContext_ModelBindingContextIsSetWithModelName_ForParameters(
|
public void GetModelBindingContext_ModelBindingContextIsSetWithModelName_ForParameters(
|
||||||
string actionMethodName, bool expectedFallToEmptyPrefix, string expectedModelName)
|
string actionMethodName, bool expectedFallToEmptyPrefix, string expectedModelName)
|
||||||
{
|
{
|
||||||
|
|
@ -59,8 +145,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||||
var modelMetadata = metadataProvider.GetMetadataForParameter(modelAccessor: null,
|
var modelMetadata = metadataProvider.GetMetadataForParameter(modelAccessor: null,
|
||||||
methodInfo: methodInfo,
|
methodInfo: methodInfo,
|
||||||
parameterName: "foo",
|
parameterName: "parameter");
|
||||||
binderMetadata: null);
|
|
||||||
|
|
||||||
|
|
||||||
var actionBindingContext = new ActionBindingContext(actionContext,
|
var actionBindingContext = new ActionBindingContext(actionContext,
|
||||||
|
|
@ -70,8 +155,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
Mock.Of<IInputFormatterSelector>(),
|
Mock.Of<IInputFormatterSelector>(),
|
||||||
Mock.Of<IModelValidatorProvider>());
|
Mock.Of<IModelValidatorProvider>());
|
||||||
// Act
|
// Act
|
||||||
var context = DefaultControllerActionArgumentBinder
|
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||||
.GetModelBindingContext(modelMetadata, actionBindingContext, Mock.Of<OperationBindingContext>());
|
modelMetadata, actionBindingContext, Mock.Of<OperationBindingContext>());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedFallToEmptyPrefix, context.FallbackToEmptyPrefix);
|
Assert.Equal(expectedFallToEmptyPrefix, context.FallbackToEmptyPrefix);
|
||||||
|
|
@ -80,8 +165,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("ParameterHasEmptyFieldPrefix", false, "")]
|
[InlineData("ParameterHasEmptyFieldPrefix", false, "")]
|
||||||
[InlineData("ParameterHasPrefixAndComplexType", false, "bar")]
|
[InlineData("ParameterHasPrefixAndComplexType", false, "simpleModelPrefix")]
|
||||||
[InlineData("ParameterHasEmptyBindAttribute", true, "foo1")]
|
[InlineData("ParameterHasEmptyBindAttribute", true, "parameter1")]
|
||||||
public void GetModelBindingContext_ModelBindingContextIsNotSet_ForTypes(
|
public void GetModelBindingContext_ModelBindingContextIsNotSet_ForTypes(
|
||||||
string actionMethodName, bool expectedFallToEmptyPrefix, string expectedModelName)
|
string actionMethodName, bool expectedFallToEmptyPrefix, string expectedModelName)
|
||||||
{
|
{
|
||||||
|
|
@ -94,8 +179,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||||
var modelMetadata = metadataProvider.GetMetadataForParameter(modelAccessor: null,
|
var modelMetadata = metadataProvider.GetMetadataForParameter(modelAccessor: null,
|
||||||
methodInfo: methodInfo,
|
methodInfo: methodInfo,
|
||||||
parameterName: "foo1",
|
parameterName: "parameter1");
|
||||||
binderMetadata: null);
|
|
||||||
|
|
||||||
|
|
||||||
var actionBindingContext = new ActionBindingContext(actionContext,
|
var actionBindingContext = new ActionBindingContext(actionContext,
|
||||||
|
|
@ -105,8 +189,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
Mock.Of<IInputFormatterSelector>(),
|
Mock.Of<IInputFormatterSelector>(),
|
||||||
Mock.Of<IModelValidatorProvider>());
|
Mock.Of<IModelValidatorProvider>());
|
||||||
// Act
|
// Act
|
||||||
var context = DefaultControllerActionArgumentBinder
|
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||||
.GetModelBindingContext(modelMetadata, actionBindingContext, Mock.Of<OperationBindingContext>());
|
modelMetadata, actionBindingContext, Mock.Of<OperationBindingContext>());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedFallToEmptyPrefix, context.FallbackToEmptyPrefix);
|
Assert.Equal(expectedFallToEmptyPrefix, context.FallbackToEmptyPrefix);
|
||||||
|
|
@ -233,7 +317,6 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class NonValueProviderBinderMetadataAttribute : Attribute, IBinderMetadata
|
private class NonValueProviderBinderMetadataAttribute : Attribute, IBinderMetadata
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -241,5 +324,29 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
private class ValueProviderMetadataAttribute : Attribute, IValueProviderMetadata
|
private class ValueProviderMetadataAttribute : Attribute, IValueProviderMetadata
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Bind(Exclude = nameof(Excluded1) + "," + nameof(Excluded2))]
|
||||||
|
private class TypeWithExcludedPropertiesUsingBindAttribute
|
||||||
|
{
|
||||||
|
public int Excluded1 { get; set; }
|
||||||
|
|
||||||
|
public int Excluded2 { get; set; }
|
||||||
|
|
||||||
|
public int IncludedByDefault1 { get; set; }
|
||||||
|
|
||||||
|
public int IncludedByDefault2 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Bind(Include = nameof(IncludedExplicitly1) + "," + nameof(IncludedExplicitly2))]
|
||||||
|
private class TypeWithIncludedPropertiesUsingBindAttribute
|
||||||
|
{
|
||||||
|
public int ExcludedByDefault1 { get; set; }
|
||||||
|
|
||||||
|
public int ExcludedByDefault2 { get; set; }
|
||||||
|
|
||||||
|
public int IncludedExplicitly1 { get; set; }
|
||||||
|
|
||||||
|
public int IncludedExplicitly2 { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bindingContext.ModelBindingContext.ModelMetadata.ModelName = isPrefixProvided ? "prefix" : null;
|
bindingContext.ModelBindingContext.ModelMetadata.BinderModelName = isPrefixProvided ? "prefix" : null;
|
||||||
var mutableBinder = new TestableMutableObjectModelBinder();
|
var mutableBinder = new TestableMutableObjectModelBinder();
|
||||||
bindingContext.PropertyMetadata = mutableBinder.GetMetadataForProperties(
|
bindingContext.PropertyMetadata = mutableBinder.GetMetadataForProperties(
|
||||||
bindingContext.ModelBindingContext);
|
bindingContext.ModelBindingContext);
|
||||||
|
|
@ -603,79 +603,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.Equal(expectedPropertyNames, returnedPropertyNames);
|
Assert.Equal(expectedPropertyNames, returnedPropertyNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Bind(Exclude = nameof(Excluded1) + "," + nameof(Excluded2))]
|
|
||||||
private class TypeWithExcludedPropertiesUsingBindAttribute
|
|
||||||
{
|
|
||||||
public int Excluded1 { get; set; }
|
|
||||||
|
|
||||||
public int Excluded2 { get; set; }
|
|
||||||
|
|
||||||
public int IncludedByDefault1 { get; set; }
|
|
||||||
public int IncludedByDefault2 { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void GetMetadataForProperties_DoesNotReturn_ExcludedProperties()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var expectedPropertyNames = new[] { "IncludedByDefault1", "IncludedByDefault2" };
|
|
||||||
var bindingContext = new ModelBindingContext
|
|
||||||
{
|
|
||||||
ModelMetadata = GetMetadataForType(typeof(TypeWithExcludedPropertiesUsingBindAttribute)),
|
|
||||||
OperationBindingContext = new OperationBindingContext
|
|
||||||
{
|
|
||||||
ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
|
|
||||||
MetadataProvider = new DataAnnotationsModelMetadataProvider()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var testableBinder = new TestableMutableObjectModelBinder();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var propertyMetadatas = testableBinder.GetMetadataForProperties(bindingContext);
|
|
||||||
var returnedPropertyNames = propertyMetadatas.Select(o => o.PropertyName).ToArray();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(expectedPropertyNames, returnedPropertyNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Bind(Include = nameof(IncludedExplicitly1) + "," + nameof(IncludedExplicitly2))]
|
|
||||||
private class TypeWithIncludedPropertiesUsingBindAttribute
|
|
||||||
{
|
|
||||||
public int ExcludedByDefault1 { get; set; }
|
|
||||||
|
|
||||||
public int ExcludedByDefault2 { get; set; }
|
|
||||||
|
|
||||||
public int IncludedExplicitly1 { get; set; }
|
|
||||||
|
|
||||||
public int IncludedExplicitly2 { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void GetMetadataForProperties_ReturnsOnlyWhiteListedProperties_UsingBindAttributeInclude()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var expectedPropertyNames = new[] { "IncludedExplicitly1", "IncludedExplicitly2" };
|
|
||||||
var bindingContext = new ModelBindingContext
|
|
||||||
{
|
|
||||||
ModelMetadata = GetMetadataForType(typeof(TypeWithIncludedPropertiesUsingBindAttribute)),
|
|
||||||
OperationBindingContext = new OperationBindingContext
|
|
||||||
{
|
|
||||||
ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
|
|
||||||
MetadataProvider = new DataAnnotationsModelMetadataProvider()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var testableBinder = new TestableMutableObjectModelBinder();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var propertyMetadatas = testableBinder.GetMetadataForProperties(bindingContext);
|
|
||||||
var returnedPropertyNames = propertyMetadatas.Select(o => o.PropertyName).ToArray();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(expectedPropertyNames, returnedPropertyNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetRequiredPropertiesCollection_MixedAttributes()
|
public void GetRequiredPropertiesCollection_MixedAttributes()
|
||||||
{
|
{
|
||||||
|
|
@ -1274,8 +1201,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
return metadataProvider.GetMetadataForParameter(
|
return metadataProvider.GetMetadataForParameter(
|
||||||
modelAccessor: null,
|
modelAccessor: null,
|
||||||
methodInfo: methodInfo,
|
methodInfo: methodInfo,
|
||||||
parameterName: parameterName,
|
parameterName: parameterName);
|
||||||
binderMetadata: null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class EmptyModel
|
private class EmptyModel
|
||||||
|
|
|
||||||
|
|
@ -96,49 +96,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetMetadataForProperty_WithNoBinderMetadata_GetsItFromType()
|
public void GetMetadataForParameterNullOrEmptyPropertyNameThrows()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new DataAnnotationsModelMetadataProvider();
|
var provider = new TestableAssociatedMetadataProvider();
|
||||||
|
|
||||||
// Act
|
// Act & Assert
|
||||||
var propertyMetadata = provider.GetMetadataForProperty(null, typeof(Person), nameof(Person.Parent));
|
ExceptionAssert.ThrowsArgumentNullOrEmpty(
|
||||||
|
() => provider.GetMetadataForParameter(modelAccessor: null, methodInfo: null, parameterName: null),
|
||||||
// Assert
|
"parameterName");
|
||||||
Assert.NotNull(propertyMetadata.BinderMetadata);
|
ExceptionAssert.ThrowsArgumentNullOrEmpty(
|
||||||
Assert.IsType<TestBinderMetadataAttribute>(propertyMetadata.BinderMetadata);
|
() => provider.GetMetadataForParameter(modelAccessor: null, methodInfo: null, parameterName: null),
|
||||||
}
|
"parameterName");
|
||||||
|
|
||||||
#if ASPNET50
|
|
||||||
[Fact]
|
|
||||||
public void GetMetadataForParameter_WithNoBinderMetadata_GetsItFromType()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var provider = new DataAnnotationsModelMetadataProvider();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var parameterMetadata = provider.GetMetadataForParameter(null,
|
|
||||||
typeof(Person).GetMethod("Update"),
|
|
||||||
"person",
|
|
||||||
null);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.NotNull(parameterMetadata.BinderMetadata);
|
|
||||||
Assert.IsType<TestBinderMetadataAttribute>(parameterMetadata.BinderMetadata);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
public class TestBinderMetadataAttribute : Attribute, IBinderMetadata
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestBinderMetadata]
|
|
||||||
public class Person
|
|
||||||
{
|
|
||||||
public Person Parent { get; set; }
|
|
||||||
|
|
||||||
public void Update(Person person)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMetadataForProperty
|
// GetMetadataForProperty
|
||||||
|
|
@ -310,7 +279,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public ModelMetadata CreateMetadataPrototypeReturnValue = null;
|
public ModelMetadata CreateMetadataPrototypeReturnValue = null;
|
||||||
public ModelMetadata CreateMetadataFromPrototypeReturnValue = null;
|
public ModelMetadata CreateMetadataFromPrototypeReturnValue = null;
|
||||||
|
|
||||||
protected override ModelMetadata CreateMetadataPrototype(IEnumerable<Attribute> attributes, Type containerType, Type modelType, string propertyName)
|
protected override ModelMetadata CreateMetadataPrototype(IEnumerable<object> attributes, Type containerType, Type modelType, string propertyName)
|
||||||
{
|
{
|
||||||
CreateMetadataPrototypeLog.Add(new CreateMetadataPrototypeParams
|
CreateMetadataPrototypeLog.Add(new CreateMetadataPrototypeParams
|
||||||
{
|
{
|
||||||
|
|
@ -337,7 +306,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
private class CreateMetadataPrototypeParams
|
private class CreateMetadataPrototypeParams
|
||||||
{
|
{
|
||||||
public IEnumerable<Attribute> Attributes { get; set; }
|
public IEnumerable<object> Attributes { get; set; }
|
||||||
public Type ContainerType { get; set; }
|
public Type ContainerType { get; set; }
|
||||||
public Type ModelType { get; set; }
|
public Type ModelType { get; set; }
|
||||||
public string PropertyName { get; set; }
|
public string PropertyName { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -14,7 +15,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public class CachedDataAnnotationsMetadataAttributesTest
|
public class CachedDataAnnotationsMetadataAttributesTest
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Constructor_DefaultsAllPropertiesToNull()
|
public void Constructor_SetsDefaultValuesForAllProperties()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var attributes = Enumerable.Empty<Attribute>();
|
var attributes = Enumerable.Empty<Attribute>();
|
||||||
|
|
@ -31,14 +32,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.Null(cache.HiddenInput);
|
Assert.Null(cache.HiddenInput);
|
||||||
Assert.Null(cache.Required);
|
Assert.Null(cache.Required);
|
||||||
Assert.Null(cache.ScaffoldColumn);
|
Assert.Null(cache.ScaffoldColumn);
|
||||||
|
Assert.Null(cache.BinderMetadata);
|
||||||
|
Assert.Null(cache.BinderModelNameProvider);
|
||||||
|
Assert.Empty(cache.PropertyBindingInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TheoryData<Attribute, Func<CachedDataAnnotationsMetadataAttributes, Attribute>>
|
public static TheoryData<object, Func<CachedDataAnnotationsMetadataAttributes, object>>
|
||||||
ExpectedAttributeData
|
ExpectedAttributeData
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return new TheoryData<Attribute, Func<CachedDataAnnotationsMetadataAttributes, Attribute>>
|
return new TheoryData<object, Func<CachedDataAnnotationsMetadataAttributes, object>>
|
||||||
{
|
{
|
||||||
{ new DataTypeAttribute(DataType.Duration), cache => cache.DataType },
|
{ new DataTypeAttribute(DataType.Duration), cache => cache.DataType },
|
||||||
{ new DisplayAttribute(), cache => cache.Display },
|
{ new DisplayAttribute(), cache => cache.Display },
|
||||||
|
|
@ -47,7 +51,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{ new EditableAttribute(allowEdit: false), cache => cache.Editable },
|
{ new EditableAttribute(allowEdit: false), cache => cache.Editable },
|
||||||
{ new HiddenInputAttribute(), cache => cache.HiddenInput },
|
{ new HiddenInputAttribute(), cache => cache.HiddenInput },
|
||||||
{ new RequiredAttribute(), cache => cache.Required },
|
{ new RequiredAttribute(), cache => cache.Required },
|
||||||
{ new ScaffoldColumnAttribute(scaffold: false), cache => cache.ScaffoldColumn },
|
{ new TestBinderMetadata(), cache => cache.BinderMetadata },
|
||||||
|
{ new TestModelNameProvider(), cache => cache.BinderModelNameProvider },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -55,8 +60,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(ExpectedAttributeData))]
|
[MemberData(nameof(ExpectedAttributeData))]
|
||||||
public void Constructor_FindsExpectedAttribute(
|
public void Constructor_FindsExpectedAttribute(
|
||||||
Attribute attribute,
|
object attribute,
|
||||||
Func<CachedDataAnnotationsMetadataAttributes, Attribute> accessor)
|
Func<CachedDataAnnotationsMetadataAttributes, object> accessor)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var attributes = new[] { attribute };
|
var attributes = new[] { attribute };
|
||||||
|
|
@ -69,6 +74,24 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.Same(attribute, result);
|
Assert.Same(attribute, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_FindsPropertyBindingInfo()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var propertyBindingInfos =
|
||||||
|
new[] { new TestPropertyBindingInfo(), new TestPropertyBindingInfo() };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var cache = new CachedDataAnnotationsMetadataAttributes(propertyBindingInfos);
|
||||||
|
var result = cache.PropertyBindingInfo.ToArray();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
for (var index = 0; index < propertyBindingInfos.Length; index++)
|
||||||
|
{
|
||||||
|
Assert.Same(propertyBindingInfos[index], result[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Constructor_FindsDisplayFormat_FromDataType()
|
public void Constructor_FindsDisplayFormat_FromDataType()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
@ -45,12 +46,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var metadata = provider.GetMetadataForType(null, type);
|
var metadata = provider.GetMetadataForType(null, type);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedIncludedPropertyNames.ToList(), metadata.IncludedProperties);
|
Assert.Equal(expectedIncludedPropertyNames.ToList(), metadata.BinderIncludeProperties);
|
||||||
Assert.Equal(expectedExcludedPropertyNames.ToList(), metadata.ExcludedProperties);
|
Assert.Equal(expectedExcludedPropertyNames.ToList(), metadata.BinderExcludeProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ModelMetadataProvider_ReadsIncludedAndExcludedProperties_OnlyAtParameterLevel_ForParameters()
|
public void ModelMetadataProvider_ReadsIncludedAndExcludedProperties_AtParameterAndType_ForParameters()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var type = typeof(TypeWithExludedAndIncludedPropertiesUsingBindAttribute);
|
var type = typeof(TypeWithExludedAndIncludedPropertiesUsingBindAttribute);
|
||||||
|
|
@ -58,20 +59,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var provider = new DataAnnotationsModelMetadataProvider();
|
var provider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
|
||||||
// Note it does an intersection for included and a union for excluded.
|
// Note it does an intersection for included and a union for excluded.
|
||||||
var expectedIncludedPropertyNames = new[] { "Property1", "Property2", "IncludedAndExcludedExplicitly1" };
|
var expectedIncludedPropertyNames = new[] { "IncludedAndExcludedExplicitly1" };
|
||||||
var expectedExcludedPropertyNames = new[] {
|
var expectedExcludedPropertyNames = new[] {
|
||||||
"Property3", "Property4", "IncludedAndExcludedExplicitly1" };
|
"Property3", "Property4", "IncludedAndExcludedExplicitly1", "ExcludedExplicitly1" };
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var metadata = provider.GetMetadataForParameter(
|
var metadata = provider.GetMetadataForParameter(
|
||||||
modelAccessor: null,
|
modelAccessor: null,
|
||||||
methodInfo: methodInfo,
|
methodInfo: methodInfo,
|
||||||
parameterName: "param",
|
parameterName: "param");
|
||||||
binderMetadata: null);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedIncludedPropertyNames.ToList(), metadata.IncludedProperties);
|
Assert.Equal(expectedIncludedPropertyNames.ToList(), metadata.BinderIncludeProperties);
|
||||||
Assert.Equal(expectedExcludedPropertyNames.ToList(), metadata.ExcludedProperties);
|
Assert.Equal(expectedExcludedPropertyNames.ToList(), metadata.BinderExcludeProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -86,11 +86,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var metadata = provider.GetMetadataForParameter(
|
var metadata = provider.GetMetadataForParameter(
|
||||||
modelAccessor: null,
|
modelAccessor: null,
|
||||||
methodInfo: methodInfo,
|
methodInfo: methodInfo,
|
||||||
parameterName: "param",
|
parameterName: "param");
|
||||||
binderMetadata: null);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("ParameterPrefix", metadata.ModelName);
|
Assert.Equal("ParameterPrefix", metadata.BinderModelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -104,7 +103,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var metadata = provider.GetMetadataForType(null, type);
|
var metadata = provider.GetMetadataForType(null, type);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("TypePrefix", metadata.ModelName);
|
Assert.Equal("TypePrefix", metadata.BinderModelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -119,11 +118,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var metadata = provider.GetMetadataForParameter(
|
var metadata = provider.GetMetadataForParameter(
|
||||||
modelAccessor: null,
|
modelAccessor: null,
|
||||||
methodInfo: methodInfo,
|
methodInfo: methodInfo,
|
||||||
parameterName: "param",
|
parameterName: "param");
|
||||||
binderMetadata: null);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("ParameterPrefix", metadata.ModelName);
|
Assert.Equal("ParameterPrefix", metadata.BinderModelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -167,8 +165,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.True(result);
|
Assert.True(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO https://github.com/aspnet/Mvc/issues/1000
|
[Fact]
|
||||||
// Enable test once we detect attributes on the property's type
|
|
||||||
public void HiddenInputWorksOnPropertyType()
|
public void HiddenInputWorksOnPropertyType()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -183,6 +180,119 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.True(result);
|
Assert.True(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetMetadataForProperty_WithNoBinderMetadata_GetsItFromType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var propertyMetadata = provider.GetMetadataForProperty(null, typeof(Person), nameof(Person.Parent));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(propertyMetadata.BinderMetadata);
|
||||||
|
var attribute = Assert.IsType<TypeBasedBinderAttribute>(propertyMetadata.BinderMetadata);
|
||||||
|
Assert.Equal("PersonType", propertyMetadata.BinderModelName);
|
||||||
|
Assert.Equal(new[] { "IncludeAtType" }, propertyMetadata.BinderIncludeProperties.ToArray());
|
||||||
|
Assert.Equal(new[] { "ExcludeAtType" }, propertyMetadata.BinderExcludeProperties.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetMetadataForProperty_WithBinderMetadataOnPropertyAndType_GetsMetadataFromProperty()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var propertyMetadata = provider.GetMetadataForProperty(null, typeof(Person), nameof(Person.GrandParent));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(propertyMetadata.BinderMetadata);
|
||||||
|
var attribute = Assert.IsType<NonTypeBasedBinderAttribute>(propertyMetadata.BinderMetadata);
|
||||||
|
Assert.Equal("GrandParentProperty", propertyMetadata.BinderModelName);
|
||||||
|
Assert.Empty(propertyMetadata.BinderIncludeProperties);
|
||||||
|
Assert.Equal(new[] { "ExcludeAtProperty", "ExcludeAtType" },
|
||||||
|
propertyMetadata.BinderExcludeProperties.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ASPNET50
|
||||||
|
[Fact]
|
||||||
|
public void GetMetadataForParameter_WithNoBinderMetadata_GetsItFromType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var parameterMetadata = provider.GetMetadataForParameter(null,
|
||||||
|
typeof(Person).GetMethod("Update"),
|
||||||
|
"person");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(parameterMetadata.BinderMetadata);
|
||||||
|
var attribute = Assert.IsType<TypeBasedBinderAttribute>(parameterMetadata.BinderMetadata);
|
||||||
|
Assert.Equal("PersonType", parameterMetadata.BinderModelName);
|
||||||
|
Assert.Equal(new[] { "IncludeAtType" }, parameterMetadata.BinderIncludeProperties.ToArray());
|
||||||
|
Assert.Equal(new[] { "ExcludeAtType" }, parameterMetadata.BinderExcludeProperties.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetMetadataForParameter_WithBinderDataOnParameterAndType_GetsMetadataFromParameter()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var parameterMetadata = provider.GetMetadataForParameter(null,
|
||||||
|
typeof(Person).GetMethod("Save"),
|
||||||
|
"person");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(parameterMetadata.BinderMetadata);
|
||||||
|
var attribute = Assert.IsType<NonTypeBasedBinderAttribute>(parameterMetadata.BinderMetadata);
|
||||||
|
Assert.Equal("PersonParameter", parameterMetadata.BinderModelName);
|
||||||
|
Assert.Empty(parameterMetadata.BinderIncludeProperties);
|
||||||
|
Assert.Equal(new[] { "ExcludeAtParameter", "ExcludeAtType" },
|
||||||
|
parameterMetadata.BinderExcludeProperties.ToArray());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
public class TypeBasedBinderAttribute : Attribute,
|
||||||
|
IBinderMetadata, IModelNameProvider, IPropertyBindingInfo
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string Exclude { get; set; }
|
||||||
|
|
||||||
|
public string Include { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NonTypeBasedBinderAttribute : Attribute,
|
||||||
|
IBinderMetadata, IModelNameProvider, IPropertyBindingInfo
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string Exclude { get; set; }
|
||||||
|
|
||||||
|
public string Include { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[TypeBasedBinder(Name = "PersonType", Include = "IncludeAtType", Exclude = "ExcludeAtType")]
|
||||||
|
public class Person
|
||||||
|
{
|
||||||
|
public Person Parent { get; set; }
|
||||||
|
|
||||||
|
[NonTypeBasedBinder(Name = "GrandParentProperty", Include = "IncludeAtProperty", Exclude = "ExcludeAtProperty")]
|
||||||
|
public Person GrandParent { get; set; }
|
||||||
|
|
||||||
|
public void Update(Person person)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save([NonTypeBasedBinder(Name = "PersonParameter",
|
||||||
|
Include = "IncludeAtParameter", Exclude = "ExcludeAtParameter")] Person person)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class ScaffoldColumnModel
|
private class ScaffoldColumnModel
|
||||||
{
|
{
|
||||||
public int NoAttribute { get; set; }
|
public int NoAttribute { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -49,13 +49,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.Null(metadata.TemplateHint);
|
Assert.Null(metadata.TemplateHint);
|
||||||
|
|
||||||
Assert.Equal(ModelMetadata.DefaultOrder, metadata.Order);
|
Assert.Equal(ModelMetadata.DefaultOrder, metadata.Order);
|
||||||
|
|
||||||
|
Assert.Null(metadata.BinderModelName);
|
||||||
|
Assert.Null(metadata.BinderMetadata);
|
||||||
|
Assert.Empty(metadata.BinderIncludeProperties);
|
||||||
|
Assert.Null(metadata.BinderExcludeProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TheoryData<Attribute, Func<ModelMetadata, string>> ExpectedAttributeDataStrings
|
public static TheoryData<object, Func<ModelMetadata, string>> ExpectedAttributeDataStrings
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return new TheoryData<Attribute, Func<ModelMetadata, string>>
|
return new TheoryData<object, Func<ModelMetadata, string>>
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
new DataTypeAttribute("value"), metadata => metadata.DataTypeName
|
new DataTypeAttribute("value"), metadata => metadata.DataTypeName
|
||||||
|
|
@ -91,13 +96,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
new DisplayFormatAttribute { NullDisplayText = "value" }, metadata => metadata.NullDisplayText
|
new DisplayFormatAttribute { NullDisplayText = "value" }, metadata => metadata.NullDisplayText
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
new TestModelNameProvider() { Name = "value" }, metadata => metadata.BinderModelName
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(ExpectedAttributeDataStrings))]
|
[MemberData(nameof(ExpectedAttributeDataStrings))]
|
||||||
public void AttributesOverrideMetadataStrings(Attribute attribute, Func<ModelMetadata, string> accessor)
|
public void AttributesOverrideMetadataStrings(object attribute, Func<ModelMetadata, string> accessor)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var attributes = new[] { attribute };
|
var attributes = new[] { attribute };
|
||||||
|
|
@ -221,6 +229,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.Equal(expectedResult, result);
|
Assert.Equal(expectedResult, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BinderMetadataIfPresent_Overrides_DefaultBinderMetadata()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var firstBinderMetadata = new TestBinderMetadata();
|
||||||
|
var secondBinderMetadata = new TestBinderMetadata();
|
||||||
|
var provider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
var metadata = new CachedDataAnnotationsModelMetadata(
|
||||||
|
provider,
|
||||||
|
containerType: null,
|
||||||
|
modelType: typeof(object),
|
||||||
|
propertyName: null,
|
||||||
|
attributes: new object[] { firstBinderMetadata, secondBinderMetadata });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = metadata.BinderMetadata;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(firstBinderMetadata, result);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void DataTypeName_Null_IfHtmlEncodeTrue()
|
public void DataTypeName_Null_IfHtmlEncodeTrue()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var contactModel = new DummyContactModel { FirstName = "test" };
|
var contactModel = new DummyContactModel { FirstName = "test" };
|
||||||
var nonEmptycontainerModel = new DummyModelContainer { Model = contactModel };
|
var nonEmptycontainerModel = new DummyModelContainer { Model = contactModel };
|
||||||
|
|
||||||
|
var binderMetadata = new TestBinderMetadata();
|
||||||
|
var emptyPropertyList = new List<string>();
|
||||||
|
var nonEmptyPropertyList = new List<string>() { "SomeProperty" };
|
||||||
return new TheoryData<Action<ModelMetadata>, Func<ModelMetadata, object>, object>
|
return new TheoryData<Action<ModelMetadata>, Func<ModelMetadata, object>, object>
|
||||||
{
|
{
|
||||||
{ m => m.ConvertEmptyStringToNull = false, m => m.ConvertEmptyStringToNull, false },
|
{ m => m.ConvertEmptyStringToNull = false, m => m.ConvertEmptyStringToNull, false },
|
||||||
|
|
@ -45,21 +48,49 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{ m => m.Container = null, m => m.Container, null },
|
{ m => m.Container = null, m => m.Container, null },
|
||||||
{ m => m.Container = emptycontainerModel, m => m.Container, emptycontainerModel },
|
{ m => m.Container = emptycontainerModel, m => m.Container, emptycontainerModel },
|
||||||
{ m => m.Container = nonEmptycontainerModel, m => m.Container, nonEmptycontainerModel },
|
{ m => m.Container = nonEmptycontainerModel, m => m.Container, nonEmptycontainerModel },
|
||||||
|
|
||||||
|
{ m => m.BinderMetadata = null, m => m.BinderMetadata, null },
|
||||||
|
{ m => m.BinderMetadata = binderMetadata, m => m.BinderMetadata, binderMetadata },
|
||||||
|
{ m => m.BinderModelName = null, m => m.BinderModelName, null },
|
||||||
|
{ m => m.BinderModelName = "newModelName", m => m.BinderModelName, "newModelName" },
|
||||||
|
{ m => m.BinderModelName = string.Empty, m => m.BinderModelName, string.Empty },
|
||||||
|
{ m => m.BinderIncludeProperties = null, m => m.BinderIncludeProperties, null },
|
||||||
|
{
|
||||||
|
m => m.BinderIncludeProperties = emptyPropertyList,
|
||||||
|
m => m.BinderIncludeProperties,
|
||||||
|
emptyPropertyList
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m => m.BinderIncludeProperties = nonEmptyPropertyList,
|
||||||
|
m => m.BinderIncludeProperties,
|
||||||
|
nonEmptyPropertyList
|
||||||
|
},
|
||||||
|
{ m => m.BinderExcludeProperties = null, m => m.BinderExcludeProperties, null },
|
||||||
|
{
|
||||||
|
m => m.BinderExcludeProperties = emptyPropertyList,
|
||||||
|
m => m.BinderExcludeProperties,
|
||||||
|
emptyPropertyList
|
||||||
|
},
|
||||||
|
{
|
||||||
|
m => m.BinderExcludeProperties = nonEmptyPropertyList,
|
||||||
|
m => m.BinderExcludeProperties,
|
||||||
|
nonEmptyPropertyList
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ASPNET50
|
|
||||||
// Constructor
|
// Constructor
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void DefaultValues()
|
public void DefaultValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new Mock<IModelMetadataProvider>();
|
var provider = new EmptyModelMetadataProvider();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var metadata = new ModelMetadata(provider.Object, typeof(Exception), () => "model", typeof(string), "propertyName");
|
var metadata =
|
||||||
|
new ModelMetadata(provider, typeof(Exception), () => "model", typeof(string), "propertyName");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(typeof(Exception), metadata.ContainerType);
|
Assert.Equal(typeof(Exception), metadata.ContainerType);
|
||||||
|
|
@ -91,8 +122,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.Equal("propertyName", metadata.PropertyName);
|
Assert.Equal("propertyName", metadata.PropertyName);
|
||||||
|
|
||||||
Assert.Equal(ModelMetadata.DefaultOrder, metadata.Order);
|
Assert.Equal(ModelMetadata.DefaultOrder, metadata.Order);
|
||||||
|
|
||||||
|
Assert.Null(metadata.BinderModelName);
|
||||||
|
Assert.Null(metadata.BinderMetadata);
|
||||||
|
Assert.Null(metadata.BinderIncludeProperties);
|
||||||
|
Assert.Null(metadata.BinderExcludeProperties);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// IsComplexType
|
// IsComplexType
|
||||||
|
|
||||||
|
|
@ -100,7 +135,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ASPNET50
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(typeof(string))]
|
[InlineData(typeof(string))]
|
||||||
[InlineData(typeof(Nullable<int>))]
|
[InlineData(typeof(Nullable<int>))]
|
||||||
|
|
@ -108,10 +142,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public void IsComplexTypeTestsReturnsFalseForSimpleTypes(Type type)
|
public void IsComplexTypeTestsReturnsFalseForSimpleTypes(Type type)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new Mock<IModelMetadataProvider>();
|
var provider = new EmptyModelMetadataProvider();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var modelMetadata = new ModelMetadata(provider.Object, null, null, type, null);
|
var modelMetadata = new ModelMetadata(provider, null, null, type, null);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.False(modelMetadata.IsComplexType);
|
Assert.False(modelMetadata.IsComplexType);
|
||||||
|
|
@ -125,10 +159,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public void IsComplexTypeTestsReturnsTrueForComplexTypes(Type type)
|
public void IsComplexTypeTestsReturnsTrueForComplexTypes(Type type)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new Mock<IModelMetadataProvider>();
|
var provider = new EmptyModelMetadataProvider();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var modelMetadata = new ModelMetadata(provider.Object, null, null, type, null);
|
var modelMetadata = new ModelMetadata(provider, null, null, type, null);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(modelMetadata.IsComplexType);
|
Assert.True(modelMetadata.IsComplexType);
|
||||||
|
|
@ -140,13 +174,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public void IsNullableValueTypeTests()
|
public void IsNullableValueTypeTests()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new Mock<IModelMetadataProvider>();
|
var provider = new EmptyModelMetadataProvider();
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
Assert.False(new ModelMetadata(provider.Object, null, null, typeof(string), null).IsNullableValueType);
|
Assert.False(new ModelMetadata(provider, null, null, typeof(string), null).IsNullableValueType);
|
||||||
Assert.False(new ModelMetadata(provider.Object, null, null, typeof(IDisposable), null).IsNullableValueType);
|
Assert.False(new ModelMetadata(provider, null, null, typeof(IDisposable), null).IsNullableValueType);
|
||||||
Assert.True(new ModelMetadata(provider.Object, null, null, typeof(Nullable<int>), null).IsNullableValueType);
|
Assert.True(new ModelMetadata(provider, null, null, typeof(Nullable<int>), null).IsNullableValueType);
|
||||||
Assert.False(new ModelMetadata(provider.Object, null, null, typeof(int), null).IsNullableValueType);
|
Assert.False(new ModelMetadata(provider, null, null, typeof(int), null).IsNullableValueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsRequired
|
// IsRequired
|
||||||
|
|
@ -158,8 +192,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public void IsRequired_ReturnsFalse_ForNullableTypes(Type modelType)
|
public void IsRequired_ReturnsFalse_ForNullableTypes(Type modelType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new Mock<IModelMetadataProvider>();
|
var provider = new EmptyModelMetadataProvider();
|
||||||
var metadata = new ModelMetadata(provider.Object,
|
var metadata = new ModelMetadata(provider,
|
||||||
containerType: null,
|
containerType: null,
|
||||||
modelAccessor: null,
|
modelAccessor: null,
|
||||||
modelType: modelType,
|
modelType: modelType,
|
||||||
|
|
@ -178,8 +212,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public void IsRequired_ReturnsTrue_ForNonNullableTypes(Type modelType)
|
public void IsRequired_ReturnsTrue_ForNonNullableTypes(Type modelType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new Mock<IModelMetadataProvider>();
|
var provider = new EmptyModelMetadataProvider();
|
||||||
var metadata = new ModelMetadata(provider.Object,
|
var metadata = new ModelMetadata(provider,
|
||||||
containerType: null,
|
containerType: null,
|
||||||
modelAccessor: null,
|
modelAccessor: null,
|
||||||
modelType: modelType,
|
modelType: modelType,
|
||||||
|
|
@ -193,7 +227,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
|
#if ASPNET50
|
||||||
[Fact]
|
[Fact]
|
||||||
public void PropertiesCallsProvider()
|
public void PropertiesCallsProvider()
|
||||||
{
|
{
|
||||||
|
|
@ -215,6 +249,61 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(MetadataModifierData))]
|
||||||
|
public void PropertiesPropertyChangesPersist(
|
||||||
|
Action<ModelMetadata> setter,
|
||||||
|
Func<ModelMetadata, object> getter,
|
||||||
|
object expected)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = new EmptyModelMetadataProvider();
|
||||||
|
var metadata = new ModelMetadata(
|
||||||
|
provider,
|
||||||
|
containerType: null,
|
||||||
|
modelAccessor: () => new Class1(),
|
||||||
|
modelType: typeof(Class1),
|
||||||
|
propertyName: null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
foreach (var property in metadata.Properties)
|
||||||
|
{
|
||||||
|
setter(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
foreach (var property in metadata.Properties)
|
||||||
|
{
|
||||||
|
// Due to boxing of structs, can't Assert.Same().
|
||||||
|
Assert.Equal(expected, getter(property));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(MetadataModifierData))]
|
||||||
|
public void PropertyChangesPersist(
|
||||||
|
Action<ModelMetadata> setter,
|
||||||
|
Func<ModelMetadata, object> getter,
|
||||||
|
object expected)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = new EmptyModelMetadataProvider();
|
||||||
|
var metadata = new ModelMetadata(
|
||||||
|
provider,
|
||||||
|
containerType: null,
|
||||||
|
modelAccessor: () => new Class1(),
|
||||||
|
modelType: typeof(Class1),
|
||||||
|
propertyName: null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
setter(metadata);
|
||||||
|
var result = getter(metadata);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
// Due to boxing of structs, can't Assert.Same().
|
||||||
|
Assert.Equal(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void PropertiesListGetsResetWhenModelGetsReset()
|
public void PropertiesListGetsResetWhenModelGetsReset()
|
||||||
{
|
{
|
||||||
|
|
@ -278,36 +367,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.Equal(firstPropertiesEvaluation, secondPropertiesEvaluation);
|
Assert.Equal(firstPropertiesEvaluation, secondPropertiesEvaluation);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[MemberData(nameof(MetadataModifierData))]
|
|
||||||
public void PropertiesPropertyChangesPersist(
|
|
||||||
Action<ModelMetadata> setter,
|
|
||||||
Func<ModelMetadata, object> getter,
|
|
||||||
object expected)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var provider = new EmptyModelMetadataProvider();
|
|
||||||
var metadata = new ModelMetadata(
|
|
||||||
provider,
|
|
||||||
containerType: null,
|
|
||||||
modelAccessor: () => new Class1(),
|
|
||||||
modelType: typeof(Class1),
|
|
||||||
propertyName: null);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
foreach (var property in metadata.Properties)
|
|
||||||
{
|
|
||||||
setter(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
foreach (var property in metadata.Properties)
|
|
||||||
{
|
|
||||||
// Due to boxing of structs, can't Assert.Same().
|
|
||||||
Assert.Equal(expected, getter(property));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Class1
|
private class Class1
|
||||||
{
|
{
|
||||||
public string Prop1 { get; set; }
|
public string Prop1 { get; set; }
|
||||||
|
|
@ -341,13 +400,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.Equal("displayName", result);
|
Assert.Equal("displayName", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ASPNET50
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ReturnsPropertyNameWhenSetAndDisplayNameIsNull()
|
public void ReturnsPropertyNameWhenSetAndDisplayNameIsNull()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new Mock<IModelMetadataProvider>();
|
var provider = new EmptyModelMetadataProvider();
|
||||||
var metadata = new ModelMetadata(provider.Object, null, null, typeof(object), "PropertyName");
|
var metadata = new ModelMetadata(provider, null, null, typeof(object), "PropertyName");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = metadata.GetDisplayName();
|
var result = metadata.GetDisplayName();
|
||||||
|
|
@ -360,8 +418,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public void ReturnsTypeNameWhenPropertyNameAndDisplayNameAreNull()
|
public void ReturnsTypeNameWhenPropertyNameAndDisplayNameAreNull()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new Mock<IModelMetadataProvider>();
|
var provider = new EmptyModelMetadataProvider();
|
||||||
var metadata = new ModelMetadata(provider.Object, null, null, typeof(object), null);
|
var metadata = new ModelMetadata(provider, null, null, typeof(object), null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = metadata.GetDisplayName();
|
var result = metadata.GetDisplayName();
|
||||||
|
|
@ -369,7 +427,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("Object", result);
|
Assert.Equal("Object", result);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// SimpleDisplayText
|
// SimpleDisplayText
|
||||||
|
|
||||||
|
|
@ -435,33 +492,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public Class1 Prop1 { get; set; }
|
public Class1 Prop1 { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[MemberData(nameof(MetadataModifierData))]
|
|
||||||
public void PropertyChangesPersist(
|
|
||||||
Action<ModelMetadata> setter,
|
|
||||||
Func<ModelMetadata, object> getter,
|
|
||||||
object expected)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var provider = new EmptyModelMetadataProvider();
|
|
||||||
var metadata = new ModelMetadata(
|
|
||||||
provider,
|
|
||||||
containerType: null,
|
|
||||||
modelAccessor: () => new Class1(),
|
|
||||||
modelType: typeof(Class1),
|
|
||||||
propertyName: null);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
setter(metadata);
|
|
||||||
var result = getter(metadata);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
// Due to boxing of structs, can't Assert.Same().
|
|
||||||
Assert.Equal(expected, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
private class DummyContactModel
|
private class DummyContactModel
|
||||||
{
|
{
|
||||||
public int IntField = 0;
|
public int IntField = 0;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
public class TestBinderMetadata : IBinderMetadata
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
|
||||||
|
public class TestModelNameProvider : IModelNameProvider
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
public class TestPropertyBindingInfo : IPropertyBindingInfo
|
||||||
|
{
|
||||||
|
public string Exclude { get; set; }
|
||||||
|
|
||||||
|
public string Include { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue