Cleaning up StyleCop errors
This commit is contained in:
parent
b96da245cb
commit
97e06138ed
|
|
@ -19,7 +19,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return base.BindModelAsync(bindingContext);
|
||||
}
|
||||
|
||||
protected override bool CreateOrReplaceCollection(ModelBindingContext bindingContext, IList<TElement> newCollection)
|
||||
protected override bool CreateOrReplaceCollection(ModelBindingContext bindingContext,
|
||||
IList<TElement> newCollection)
|
||||
{
|
||||
bindingContext.Model = newCollection.ToArray();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -23,38 +23,38 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName);
|
||||
var boundCollection = await ((valueProviderResult != null) ?
|
||||
BindSimpleCollection(bindingContext, valueProviderResult.RawValue, valueProviderResult.Culture) :
|
||||
BindComplexCollection(bindingContext));
|
||||
var bindCollectionTask = valueProviderResult != null ?
|
||||
BindSimpleCollection(bindingContext, valueProviderResult.RawValue, valueProviderResult.Culture) :
|
||||
BindComplexCollection(bindingContext);
|
||||
var boundCollection = await bindCollectionTask;
|
||||
|
||||
return CreateOrReplaceCollection(bindingContext, boundCollection);
|
||||
}
|
||||
|
||||
// TODO: Make this method internal
|
||||
// Used when the ValueProvider contains the collection to be bound as a single element, e.g. the raw value
|
||||
// is [ "1", "2" ] and needs to be converted to an int[].
|
||||
public async Task<List<TElement>> BindSimpleCollection(ModelBindingContext bindingContext,
|
||||
object rawValue,
|
||||
CultureInfo culture)
|
||||
internal async Task<List<TElement>> BindSimpleCollection(ModelBindingContext bindingContext,
|
||||
object rawValue,
|
||||
CultureInfo culture)
|
||||
{
|
||||
if (rawValue == null)
|
||||
{
|
||||
return null; // nothing to do
|
||||
}
|
||||
|
||||
List<TElement> boundCollection = new List<TElement>();
|
||||
var boundCollection = new List<TElement>();
|
||||
|
||||
object[] rawValueArray = RawValueToObjectArray(rawValue);
|
||||
foreach (object rawValueElement in rawValueArray)
|
||||
var rawValueArray = RawValueToObjectArray(rawValue);
|
||||
foreach (var rawValueElement in rawValueArray)
|
||||
{
|
||||
ModelBindingContext innerBindingContext = new ModelBindingContext(bindingContext)
|
||||
var innerBindingContext = new ModelBindingContext(bindingContext)
|
||||
{
|
||||
ModelMetadata = bindingContext.MetadataProvider.GetMetadataForType(null, typeof(TElement)),
|
||||
ModelName = bindingContext.ModelName,
|
||||
ValueProvider = new CompositeValueProvider
|
||||
{
|
||||
// our temporary provider goes at the front of the list
|
||||
new ElementalValueProvider(bindingContext.ModelName, rawValueElement, culture),
|
||||
new ElementalValueProvider(bindingContext.ModelName, rawValueElement, culture),
|
||||
bindingContext.ValueProvider
|
||||
}
|
||||
};
|
||||
|
|
@ -74,15 +74,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Used when the ValueProvider contains the collection to be bound as multiple elements, e.g. foo[0], foo[1].
|
||||
private async Task<List<TElement>> BindComplexCollection(ModelBindingContext bindingContext)
|
||||
{
|
||||
string indexPropertyName = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName, "index");
|
||||
ValueProviderResult valueProviderResultIndex = await bindingContext.ValueProvider.GetValueAsync(indexPropertyName);
|
||||
IEnumerable<string> indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(valueProviderResultIndex);
|
||||
var indexPropertyName = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName, "index");
|
||||
var valueProviderResultIndex = await bindingContext.ValueProvider.GetValueAsync(indexPropertyName);
|
||||
var indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(valueProviderResultIndex);
|
||||
return await BindComplexCollectionFromIndexes(bindingContext, indexNames);
|
||||
}
|
||||
|
||||
// TODO: Convert to internal
|
||||
public async Task<List<TElement>> BindComplexCollectionFromIndexes(ModelBindingContext bindingContext,
|
||||
IEnumerable<string> indexNames)
|
||||
internal async Task<List<TElement>> BindComplexCollectionFromIndexes(ModelBindingContext bindingContext,
|
||||
IEnumerable<string> indexNames)
|
||||
{
|
||||
bool indexNamesIsFinite;
|
||||
if (indexNames != null)
|
||||
|
|
@ -96,20 +95,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
.Select(i => i.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
List<TElement> boundCollection = new List<TElement>();
|
||||
foreach (string indexName in indexNames)
|
||||
var boundCollection = new List<TElement>();
|
||||
foreach (var indexName in indexNames)
|
||||
{
|
||||
string fullChildName = ModelBindingHelper.CreateIndexModelName(bindingContext.ModelName, indexName);
|
||||
var fullChildName = ModelBindingHelper.CreateIndexModelName(bindingContext.ModelName, indexName);
|
||||
var childBindingContext = new ModelBindingContext(bindingContext)
|
||||
{
|
||||
ModelMetadata = bindingContext.MetadataProvider.GetMetadataForType(null, typeof(TElement)),
|
||||
ModelName = fullChildName
|
||||
};
|
||||
|
||||
bool didBind = false;
|
||||
var didBind = false;
|
||||
object boundValue = null;
|
||||
|
||||
Type modelType = bindingContext.ModelType;
|
||||
var modelType = bindingContext.ModelType;
|
||||
|
||||
if (await bindingContext.ModelBinder.BindModelAsync(childBindingContext))
|
||||
{
|
||||
|
|
@ -134,7 +133,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Extensibility point that allows the bound collection to be manipulated or transformed before
|
||||
// being returned from the binder.
|
||||
protected virtual bool CreateOrReplaceCollection(ModelBindingContext bindingContext, IList<TElement> newCollection)
|
||||
protected virtual bool CreateOrReplaceCollection(ModelBindingContext bindingContext,
|
||||
IList<TElement> newCollection)
|
||||
{
|
||||
CreateOrReplaceCollection(bindingContext, newCollection, () => new List<TElement>());
|
||||
return true;
|
||||
|
|
@ -150,13 +150,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return new[] { rawValue };
|
||||
}
|
||||
|
||||
object[] rawValueAsObjectArray = rawValue as object[];
|
||||
var rawValueAsObjectArray = rawValue as object[];
|
||||
if (rawValueAsObjectArray != null)
|
||||
{
|
||||
return rawValueAsObjectArray;
|
||||
}
|
||||
|
||||
IEnumerable rawValueAsEnumerable = rawValue as IEnumerable;
|
||||
var rawValueAsEnumerable = rawValue as IEnumerable;
|
||||
if (rawValueAsEnumerable != null)
|
||||
{
|
||||
return rawValueAsEnumerable.Cast<object>().ToArray();
|
||||
|
|
@ -170,7 +170,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
IEnumerable<TElement> incomingElements,
|
||||
Func<ICollection<TElement>> creator)
|
||||
{
|
||||
ICollection<TElement> collection = bindingContext.Model as ICollection<TElement>;
|
||||
var collection = bindingContext.Model as ICollection<TElement>;
|
||||
if (collection == null || collection.IsReadOnly)
|
||||
{
|
||||
collection = creator();
|
||||
|
|
@ -178,7 +178,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
collection.Clear();
|
||||
foreach (TElement element in incomingElements)
|
||||
foreach (var element in incomingElements)
|
||||
{
|
||||
collection.Add(element);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,22 +12,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
if (bindingContext.ModelType == typeof(ComplexModelDto))
|
||||
{
|
||||
ModelBindingHelper.ValidateBindingContext(bindingContext, typeof(ComplexModelDto), allowNullModel: false);
|
||||
ModelBindingHelper.ValidateBindingContext(bindingContext,
|
||||
typeof(ComplexModelDto),
|
||||
allowNullModel: false);
|
||||
|
||||
ComplexModelDto dto = (ComplexModelDto)bindingContext.Model;
|
||||
foreach (ModelMetadata propertyMetadata in dto.PropertyMetadata)
|
||||
var dto = (ComplexModelDto)bindingContext.Model;
|
||||
foreach (var propertyMetadata in dto.PropertyMetadata)
|
||||
{
|
||||
ModelBindingContext propertyBindingContext = new ModelBindingContext(bindingContext)
|
||||
var propertyBindingContext = new ModelBindingContext(bindingContext)
|
||||
{
|
||||
ModelMetadata = propertyMetadata,
|
||||
ModelName = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName, propertyMetadata.PropertyName)
|
||||
ModelName = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName,
|
||||
propertyMetadata.PropertyName)
|
||||
};
|
||||
|
||||
// bind and propagate the values
|
||||
// If we can't bind, then leave the result missing (don't add a null).
|
||||
if (await bindingContext.ModelBinder.BindModelAsync(propertyBindingContext))
|
||||
{
|
||||
dto.Results[propertyMetadata] = new ComplexModelDtoResult(propertyBindingContext.Model, propertyBindingContext.ValidationNode);
|
||||
var result = new ComplexModelDtoResult(propertyBindingContext.Model,
|
||||
propertyBindingContext.ValidationNode);
|
||||
dto.Results[propertyMetadata] = result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// </remarks>
|
||||
public class CompositeModelBinder : IModelBinder
|
||||
{
|
||||
public CompositeModelBinder(IEnumerable<IModelBinder> binders)
|
||||
public CompositeModelBinder([NotNull] IEnumerable<IModelBinder> binders)
|
||||
: this(binders.ToArray())
|
||||
{
|
||||
}
|
||||
|
|
@ -31,8 +31,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
public virtual async Task<bool> BindModelAsync([NotNull] ModelBindingContext bindingContext)
|
||||
{
|
||||
var newBindingContext = CreateNewBindingContext(bindingContext,
|
||||
bindingContext.ModelName,
|
||||
var newBindingContext = CreateNewBindingContext(bindingContext,
|
||||
bindingContext.ModelName,
|
||||
reuseValidationNode: true);
|
||||
|
||||
var boundSuccessfully = await TryBind(newBindingContext);
|
||||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
&& bindingContext.FallbackToEmptyPrefix)
|
||||
{
|
||||
// fallback to empty prefix?
|
||||
newBindingContext = CreateNewBindingContext(bindingContext,
|
||||
newBindingContext = CreateNewBindingContext(bindingContext,
|
||||
modelName: string.Empty,
|
||||
reuseValidationNode: false);
|
||||
boundSuccessfully = await TryBind(newBindingContext);
|
||||
|
|
@ -53,16 +53,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Only perform validation at the root of the object graph. ValidationNode will recursively walk the graph.
|
||||
// Ignore ComplexModelDto since it essentially wraps the primary object.
|
||||
if (newBindingContext.ModelMetadata.ContainerType == null &&
|
||||
if (newBindingContext.ModelMetadata.ContainerType == null &&
|
||||
newBindingContext.ModelMetadata.ModelType != typeof(ComplexModelDto))
|
||||
{
|
||||
// run validation and return the model
|
||||
// If we fell back to an empty prefix above and are dealing with simple types,
|
||||
// propagate the non-blank model name through for user clarity in validation errors.
|
||||
// Complex types will reveal their individual properties as model names and do not require this.
|
||||
if (!newBindingContext.ModelMetadata.IsComplexType && string.IsNullOrEmpty(newBindingContext.ModelName))
|
||||
if (!newBindingContext.ModelMetadata.IsComplexType &&
|
||||
string.IsNullOrEmpty(newBindingContext.ModelName))
|
||||
{
|
||||
newBindingContext.ValidationNode = new ModelValidationNode(newBindingContext.ModelMetadata,
|
||||
newBindingContext.ValidationNode = new ModelValidationNode(newBindingContext.ModelMetadata,
|
||||
bindingContext.ModelName);
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +75,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
newBindingContext.ValidationNode.Validate(validationContext, parentNode: null);
|
||||
}
|
||||
|
||||
|
||||
bindingContext.Model = newBindingContext.Model;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -97,7 +98,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return false;
|
||||
}
|
||||
|
||||
private static ModelBindingContext CreateNewBindingContext(ModelBindingContext oldBindingContext,
|
||||
private static ModelBindingContext CreateNewBindingContext(ModelBindingContext oldBindingContext,
|
||||
string modelName,
|
||||
bool reuseValidationNode)
|
||||
{
|
||||
|
|
@ -110,7 +111,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
ValidatorProviders = oldBindingContext.ValidatorProviders,
|
||||
MetadataProvider = oldBindingContext.MetadataProvider,
|
||||
ModelBinder = oldBindingContext.ModelBinder,
|
||||
HttpContext = oldBindingContext.HttpContext
|
||||
HttpContext = oldBindingContext.HttpContext
|
||||
};
|
||||
|
||||
// validation is expensive to create, so copy it over if we can
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
public Task<bool> BindModelAsync(ModelBindingContext bindingContext)
|
||||
{
|
||||
Type binderType = ResolveBinderType(bindingContext.ModelType);
|
||||
var binderType = ResolveBinderType(bindingContext.ModelType);
|
||||
if (binderType != null)
|
||||
{
|
||||
var binder = (IModelBinder)_activator.CreateInstance(_serviceProvider, binderType);
|
||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
if (modelType.IsArray)
|
||||
{
|
||||
Type elementType = modelType.GetElementType();
|
||||
var elementType = modelType.GetElementType();
|
||||
return typeof(ArrayModelBinder<>).MakeGenericType(elementType);
|
||||
}
|
||||
return null;
|
||||
|
|
@ -78,27 +78,29 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
openBinderType: typeof(KeyValuePairModelBinder<,>));
|
||||
}
|
||||
|
||||
|
||||
/// <remarks>
|
||||
/// Example: GetGenericBinder(typeof(IList<>), typeof(List<>), typeof(ListBinder<>), ...) means that the ListBinder<T>
|
||||
/// type can update models that implement IList<T>, and if for some reason the existing model instance is not
|
||||
/// updatable the binder will create a List<T> object and bind to that instead. This method will return ListBinder<T>
|
||||
/// or null, depending on whether the type and updatability checks succeed.
|
||||
/// Example: GetGenericBinder(typeof(IList<>), typeof(List<>), typeof(ListBinder<>), ...) means that the
|
||||
/// ListBinder<T> type can update models that implement IList<T>, and if for some reason the existing model
|
||||
/// instance is not updatable the binder will create a List<T> object and bind to that instead. This method
|
||||
/// will return ListBinder<T> or null, depending on whether the type and updatability checks succeed.
|
||||
/// </remarks>
|
||||
private static Type GetGenericBinderType(Type supportedInterfaceType, Type newInstanceType, Type openBinderType, Type modelType)
|
||||
private static Type GetGenericBinderType(Type supportedInterfaceType,
|
||||
Type newInstanceType,
|
||||
Type openBinderType,
|
||||
Type modelType)
|
||||
{
|
||||
Contract.Assert(supportedInterfaceType != null);
|
||||
Contract.Assert(openBinderType != null);
|
||||
Contract.Assert(modelType != null);
|
||||
|
||||
Type[] modelTypeArguments = GetGenericBinderTypeArgs(supportedInterfaceType, modelType);
|
||||
var modelTypeArguments = GetGenericBinderTypeArgs(supportedInterfaceType, modelType);
|
||||
|
||||
if (modelTypeArguments == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Type closedNewInstanceType = newInstanceType.MakeGenericType(modelTypeArguments);
|
||||
var closedNewInstanceType = newInstanceType.MakeGenericType(modelTypeArguments);
|
||||
if (!modelType.GetTypeInfo().IsAssignableFrom(closedNewInstanceType.GetTypeInfo()))
|
||||
{
|
||||
return null;
|
||||
|
|
@ -110,14 +112,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Get the generic arguments for the binder, based on the model type. Or null if not compatible.
|
||||
private static Type[] GetGenericBinderTypeArgs(Type supportedInterfaceType, Type modelType)
|
||||
{
|
||||
TypeInfo modelTypeInfo = modelType.GetTypeInfo();
|
||||
var modelTypeInfo = modelType.GetTypeInfo();
|
||||
if (!modelTypeInfo.IsGenericType || modelTypeInfo.IsGenericTypeDefinition)
|
||||
{
|
||||
// not a closed generic type
|
||||
return null;
|
||||
}
|
||||
|
||||
Type[] modelTypeArguments = modelTypeInfo.GenericTypeArguments;
|
||||
var modelTypeArguments = modelTypeInfo.GenericTypeArguments;
|
||||
if (modelTypeArguments.Length != supportedInterfaceType.GetTypeInfo().GenericTypeParameters.Length)
|
||||
{
|
||||
// wrong number of generic type arguments
|
||||
|
|
@ -126,6 +128,5 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
return modelTypeArguments;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
||||
|
|
@ -12,10 +11,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
public async Task<bool> BindModelAsync(ModelBindingContext bindingContext)
|
||||
{
|
||||
ModelBindingHelper.ValidateBindingContext(bindingContext, typeof(KeyValuePair<TKey, TValue>), allowNullModel: true);
|
||||
ModelBindingHelper.ValidateBindingContext(bindingContext,
|
||||
typeof(KeyValuePair<TKey, TValue>),
|
||||
allowNullModel: true);
|
||||
|
||||
var keyResult = await TryBindStrongModel<TKey>(bindingContext, "key");
|
||||
var valueResult = await TryBindStrongModel<TValue>(bindingContext, "value");
|
||||
var valueResult = await TryBindStrongModel<TValue>(bindingContext, "value");
|
||||
|
||||
if (keyResult.Success && valueResult.Success)
|
||||
{
|
||||
|
|
@ -27,21 +28,22 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
internal async Task<BindResult<TModel>> TryBindStrongModel<TModel>(ModelBindingContext parentBindingContext,
|
||||
string propertyName)
|
||||
{
|
||||
ModelBindingContext propertyBindingContext = new ModelBindingContext(parentBindingContext)
|
||||
var propertyBindingContext = new ModelBindingContext(parentBindingContext)
|
||||
{
|
||||
ModelMetadata = parentBindingContext.MetadataProvider.GetMetadataForType(modelAccessor: null, modelType: typeof(TModel)),
|
||||
ModelMetadata = parentBindingContext.MetadataProvider.GetMetadataForType(modelAccessor: null,
|
||||
modelType: typeof(TModel)),
|
||||
ModelName = ModelBindingHelper.CreatePropertyModelName(parentBindingContext.ModelName, propertyName)
|
||||
};
|
||||
|
||||
if (await propertyBindingContext.ModelBinder.BindModelAsync(propertyBindingContext))
|
||||
{
|
||||
object untypedModel = propertyBindingContext.Model;
|
||||
var untypedModel = propertyBindingContext.Model;
|
||||
var model = ModelBindingHelper.CastOrDefault<TModel>(untypedModel);
|
||||
parentBindingContext.ValidationNode.ChildNodes.Add(propertyBindingContext.ValidationNode);
|
||||
return new BindResult<TModel>(true, model);
|
||||
return new BindResult<TModel>(success: true, model: model);
|
||||
}
|
||||
|
||||
return new BindResult<TModel>(false, default(TModel));
|
||||
return new BindResult<TModel>(success: false, model: default(TModel));
|
||||
}
|
||||
|
||||
internal sealed class BindResult<TModel>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -88,13 +87,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return true;
|
||||
}
|
||||
|
||||
private ComplexModelDto CreateAndPopulateDto(ModelBindingContext bindingContext, IEnumerable<ModelMetadata> propertyMetadatas)
|
||||
private ComplexModelDto CreateAndPopulateDto(ModelBindingContext bindingContext,
|
||||
IEnumerable<ModelMetadata> propertyMetadatas)
|
||||
{
|
||||
// create a DTO and call into the DTO binder
|
||||
var originalDto = new ComplexModelDto(bindingContext.ModelMetadata, propertyMetadatas);
|
||||
var dtoBindingContext = new ModelBindingContext(bindingContext)
|
||||
{
|
||||
ModelMetadata = bindingContext.MetadataProvider.GetMetadataForType(() => originalDto, typeof(ComplexModelDto)),
|
||||
ModelMetadata = bindingContext.MetadataProvider.GetMetadataForType(() => originalDto,
|
||||
typeof(ComplexModelDto)),
|
||||
ModelName = bindingContext.ModelName
|
||||
};
|
||||
|
||||
|
|
@ -104,13 +105,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
protected virtual object CreateModel(ModelBindingContext bindingContext)
|
||||
{
|
||||
// If the Activator throws an exception, we want to propagate it back up the call stack, since the application
|
||||
// developer should know that this was an invalid type to try to bind to.
|
||||
// If the Activator throws an exception, we want to propagate it back up the call stack, since the
|
||||
// application developer should know that this was an invalid type to try to bind to.
|
||||
return Activator.CreateInstance(bindingContext.ModelType);
|
||||
}
|
||||
|
||||
// Called when the property setter null check failed, allows us to add our own error message to ModelState.
|
||||
internal static EventHandler<ModelValidatedEventArgs> CreateNullCheckFailedHandler(ModelMetadata modelMetadata, object incomingValue)
|
||||
internal static EventHandler<ModelValidatedEventArgs> CreateNullCheckFailedHandler(ModelMetadata modelMetadata,
|
||||
object incomingValue)
|
||||
{
|
||||
return (sender, e) =>
|
||||
{
|
||||
|
|
@ -120,8 +122,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
if (validationState == ModelValidationState.Unvalidated)
|
||||
{
|
||||
// Tracked via https://github.com/aspnet/Mvc/issues/450
|
||||
// TODO: Revive ModelBinderConfig
|
||||
// string errorMessage = ModelBinderConfig.ValueRequiredErrorMessageProvider(e.ValidationContext, modelMetadata, incomingValue);
|
||||
// var errorMessage = ModelBinderConfig.ValueRequiredErrorMessageProvider(e.ValidationContext,
|
||||
// modelMetadata,
|
||||
// incomingValue);
|
||||
var errorMessage = "A value is required.";
|
||||
if (errorMessage != null)
|
||||
{
|
||||
|
|
@ -145,7 +150,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return bindingContext.ModelMetadata.Properties
|
||||
.Where(propertyMetadata =>
|
||||
(validationInfo.RequiredProperties.Contains(propertyMetadata.PropertyName) ||
|
||||
!validationInfo.SkipProperties.Contains(propertyMetadata.PropertyName)) &&
|
||||
!validationInfo.SkipProperties.Contains(propertyMetadata.PropertyName)) &&
|
||||
CanUpdateProperty(propertyMetadata));
|
||||
}
|
||||
|
||||
|
|
@ -199,7 +204,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
internal void ProcessDto(ModelBindingContext bindingContext, ComplexModelDto dto)
|
||||
{
|
||||
var validationInfo = GetPropertyValidationInfo(bindingContext);
|
||||
|
||||
|
||||
// Eliminate provided properties from requiredProperties; leaving just *missing* required properties.
|
||||
validationInfo.RequiredProperties.ExceptWith(dto.Results.Select(r => r.Key.PropertyName));
|
||||
|
||||
|
|
@ -240,21 +245,22 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
if (dtoResult != null)
|
||||
{
|
||||
IModelValidator requiredValidator;
|
||||
validationInfo.RequiredValidators.TryGetValue(propertyMetadata.PropertyName, out requiredValidator);
|
||||
validationInfo.RequiredValidators.TryGetValue(propertyMetadata.PropertyName,
|
||||
out requiredValidator);
|
||||
SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator);
|
||||
bindingContext.ValidationNode.ChildNodes.Add(dtoResult.ValidationNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We're recording this exception so that we can act on it later.")]
|
||||
protected virtual void SetProperty(ModelBindingContext bindingContext,
|
||||
ModelMetadata propertyMetadata,
|
||||
ComplexModelDtoResult dtoResult,
|
||||
IModelValidator requiredValidator)
|
||||
{
|
||||
var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase;
|
||||
var property = bindingContext.ModelType
|
||||
.GetProperty(propertyMetadata.PropertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
|
||||
.GetProperty(propertyMetadata.PropertyName, bindingFlags);
|
||||
|
||||
if (property == null || !property.CanWrite)
|
||||
{
|
||||
|
|
@ -265,7 +271,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var value = dtoResult.Model ?? GetPropertyDefaultValue(property);
|
||||
propertyMetadata.Model = value;
|
||||
|
||||
|
||||
// 'Required' validators need to run first so that we can provide useful error messages if
|
||||
// the property setters throw, e.g. if we're setting entity keys to null.
|
||||
if (value == null)
|
||||
|
|
@ -295,7 +300,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// don't display a duplicate error message if a binding error has already occurred for this field
|
||||
var targetInvocationException = ex as TargetInvocationException;
|
||||
if (targetInvocationException != null &&
|
||||
if (targetInvocationException != null &&
|
||||
targetInvocationException.InnerException != null)
|
||||
{
|
||||
ex = targetInvocationException.InnerException;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// 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.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
||||
|
||||
|
|
@ -11,7 +10,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
public async Task<bool> BindModelAsync(ModelBindingContext bindingContext)
|
||||
{
|
||||
ValueProviderResult valueProviderResult = await GetCompatibleValueProviderResult(bindingContext);
|
||||
var valueProviderResult = await GetCompatibleValueProviderResult(bindingContext);
|
||||
if (valueProviderResult == null)
|
||||
{
|
||||
// conversion would have failed
|
||||
|
|
@ -19,25 +18,25 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
|
||||
object model = valueProviderResult.RawValue;
|
||||
var model = valueProviderResult.RawValue;
|
||||
ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref model);
|
||||
bindingContext.Model = model;
|
||||
|
||||
|
||||
// TODO: Determine if we need IBodyValidator here.
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static async Task<ValueProviderResult> GetCompatibleValueProviderResult(ModelBindingContext bindingContext)
|
||||
internal static async Task<ValueProviderResult> GetCompatibleValueProviderResult(ModelBindingContext context)
|
||||
{
|
||||
ModelBindingHelper.ValidateBindingContext(bindingContext);
|
||||
ModelBindingHelper.ValidateBindingContext(context);
|
||||
|
||||
var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName);
|
||||
var valueProviderResult = await context.ValueProvider.GetValueAsync(context.ModelName);
|
||||
if (valueProviderResult == null)
|
||||
{
|
||||
return null; // the value doesn't exist
|
||||
}
|
||||
|
||||
if (!bindingContext.ModelType.IsCompatibleWith(valueProviderResult.RawValue))
|
||||
if (!context.ModelType.IsCompatibleWith(valueProviderResult.RawValue))
|
||||
{
|
||||
return null; // value is of incompatible type
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
_supportedMediaTypes = new List<string>
|
||||
{
|
||||
"application/json",
|
||||
"application/json",
|
||||
"text/json"
|
||||
};
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var modelType = context.Metadata.ModelType;
|
||||
context.Model = modelType.GetTypeInfo().IsValueType ? Activator.CreateInstance(modelType) :
|
||||
null;
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the character encoding for the content
|
||||
|
|
@ -115,7 +115,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return new JsonTextReader(new StreamReader(readStream, effectiveEncoding));
|
||||
}
|
||||
|
||||
// <summary>
|
||||
/// <summary>
|
||||
/// Called during deserialization to get the <see cref="JsonSerializer"/>.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="JsonSerializer"/> used during serialization and deserialization.</returns>
|
||||
|
|
@ -150,8 +150,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var exception = e.ErrorContext.Error;
|
||||
context.ModelState.AddModelError(e.ErrorContext.Path, e.ErrorContext.Error);
|
||||
// Error must always be marked as handled
|
||||
// Failure to do so can cause the exception to be rethrown at every recursive level and overflow the
|
||||
// stack for x64 CLR processes
|
||||
// Failure to do so can cause the exception to be rethrown at every recursive level and
|
||||
// overflow the stack for x64 CLR processes
|
||||
e.ErrorContext.Handled = true;
|
||||
};
|
||||
jsonSerializer.Error += errorHandler;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
// TODO: Http exception
|
||||
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "415: Unsupported content type {0}", contentType));
|
||||
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
|
||||
"415: Unsupported content type {0}",
|
||||
contentType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,14 +10,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
public static class CollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert an ICollection to an array, removing null values. Fast path for case where there are no null values.
|
||||
/// Convert an ICollection to an array, removing null values. Fast path for case where
|
||||
/// there are no null values.
|
||||
/// </summary>
|
||||
public static T[] ToArrayWithoutNulls<T>(this ICollection<T> collection) where T : class
|
||||
{
|
||||
Contract.Assert(collection != null);
|
||||
|
||||
T[] result = new T[collection.Count];
|
||||
int count = 0;
|
||||
var result = new T[collection.Count];
|
||||
var count = 0;
|
||||
foreach (T value in collection)
|
||||
{
|
||||
if (value != null)
|
||||
|
|
@ -32,7 +33,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
}
|
||||
else
|
||||
{
|
||||
T[] trimmedResult = new T[count];
|
||||
var trimmedResult = new T[count];
|
||||
Array.Copy(result, trimmedResult, count);
|
||||
return trimmedResult;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
{
|
||||
public static class CollectionModelBinderUtil
|
||||
{
|
||||
public static IEnumerable<string> GetIndexNamesFromValueProviderResult(ValueProviderResult valueProviderResultIndex)
|
||||
public static IEnumerable<string> GetIndexNamesFromValueProviderResult(ValueProviderResult valueProviderResult)
|
||||
{
|
||||
IEnumerable<string> indexNames = null;
|
||||
if (valueProviderResultIndex != null)
|
||||
if (valueProviderResult != null)
|
||||
{
|
||||
string[] indexes = (string[])valueProviderResultIndex.ConvertTo(typeof(string[]));
|
||||
var indexes = (string[])valueProviderResult.ConvertTo(typeof(string[]));
|
||||
if (indexes != null && indexes.Length > 0)
|
||||
{
|
||||
indexNames = indexes;
|
||||
|
|
@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
}
|
||||
|
||||
collection.Clear();
|
||||
foreach (TElement element in incomingElements)
|
||||
foreach (var element in incomingElements)
|
||||
{
|
||||
collection.Add(element);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
{
|
||||
public static class DictionaryHelper
|
||||
{
|
||||
public static IEnumerable<KeyValuePair<string, TValue>> FindKeysWithPrefix<TValue>([NotNull] IDictionary<string, TValue> dictionary,
|
||||
[NotNull] string prefix)
|
||||
public static IEnumerable<KeyValuePair<string, TValue>> FindKeysWithPrefix<TValue>(
|
||||
[NotNull] IDictionary<string, TValue> dictionary,
|
||||
[NotNull] string prefix)
|
||||
{
|
||||
TValue exactMatchValue;
|
||||
if (dictionary.TryGetValue(prefix, out exactMatchValue))
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
var tokens = headerValue.Split(new[] { ';' }, 2);
|
||||
string charSet = null;
|
||||
if (tokens.Length > 1 && tokens[1].TrimStart().StartsWith(CharSetToken, StringComparison.OrdinalIgnoreCase))
|
||||
if (tokens.Length > 1 &&
|
||||
tokens[1].TrimStart().StartsWith(CharSetToken, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
charSet = tokens[1].TrimStart().Substring(CharSetToken.Length);
|
||||
}
|
||||
return new ContentTypeHeaderValue(tokens[0], charSet);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,13 +26,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
|
||||
internal static string CreatePropertyModelName(string prefix, string propertyName)
|
||||
{
|
||||
if (String.IsNullOrEmpty(prefix))
|
||||
if (string.IsNullOrEmpty(prefix))
|
||||
{
|
||||
return propertyName ?? String.Empty;
|
||||
return propertyName ?? string.Empty;
|
||||
}
|
||||
else if (String.IsNullOrEmpty(propertyName))
|
||||
else if (string.IsNullOrEmpty(propertyName))
|
||||
{
|
||||
return prefix ?? String.Empty;
|
||||
return prefix ?? string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -40,9 +40,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
}
|
||||
}
|
||||
|
||||
internal static Type GetPossibleBinderInstanceType(Type closedModelType, Type openModelType, Type openBinderType)
|
||||
internal static Type GetPossibleBinderInstanceType(Type closedModelType,
|
||||
Type openModelType,
|
||||
Type openBinderType)
|
||||
{
|
||||
Type[] typeArguments = TypeExtensions.GetTypeArgumentsIfMatch(closedModelType, openModelType);
|
||||
var typeArguments = TypeExtensions.GetTypeArgumentsIfMatch(closedModelType, openModelType);
|
||||
return (typeArguments != null) ? openBinderType.MakeGenericType(typeArguments) : null;
|
||||
}
|
||||
|
||||
|
|
@ -50,7 +52,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
{
|
||||
if (model is string &&
|
||||
modelMetadata.ConvertEmptyStringToNull &&
|
||||
String.IsNullOrWhiteSpace(model as string))
|
||||
string.IsNullOrWhiteSpace(model as string))
|
||||
{
|
||||
model = null;
|
||||
}
|
||||
|
|
@ -64,7 +66,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
}
|
||||
}
|
||||
|
||||
internal static void ValidateBindingContext(ModelBindingContext bindingContext, Type requiredType, bool allowNullModel)
|
||||
internal static void ValidateBindingContext(ModelBindingContext bindingContext,
|
||||
Type requiredType,
|
||||
bool allowNullModel)
|
||||
{
|
||||
ValidateBindingContext(bindingContext);
|
||||
|
||||
|
|
@ -80,10 +84,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
throw new ArgumentException(message, "bindingContext");
|
||||
}
|
||||
|
||||
if (bindingContext.Model != null && !bindingContext.ModelType.GetTypeInfo().IsAssignableFrom(requiredType.GetTypeInfo()))
|
||||
if (bindingContext.Model != null &&
|
||||
!bindingContext.ModelType.GetTypeInfo().IsAssignableFrom(requiredType.GetTypeInfo()))
|
||||
{
|
||||
var message = Resources.FormatModelBinderUtil_ModelInstanceIsWrong(
|
||||
bindingContext.Model.GetType(),
|
||||
bindingContext.Model.GetType(),
|
||||
requiredType);
|
||||
throw new ArgumentException(message, "bindingContext");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
return _sortedValues.Length > 0; // only match empty string when we have some value
|
||||
}
|
||||
|
||||
PrefixComparer prefixComparer = new PrefixComparer(prefix);
|
||||
bool containsPrefix = Array.BinarySearch(_sortedValues, prefix, prefixComparer) > -1;
|
||||
var prefixComparer = new PrefixComparer(prefix);
|
||||
var containsPrefix = Array.BinarySearch(_sortedValues, prefix, prefixComparer) > -1;
|
||||
if (!containsPrefix)
|
||||
{
|
||||
// If there's something in the search boundary that starts with the same name
|
||||
|
|
@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
// - "abc"/"foo[abc]"
|
||||
internal IDictionary<string, string> GetKeysFromPrefix(string prefix)
|
||||
{
|
||||
IDictionary<string, string> result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var entry in _originalValues)
|
||||
{
|
||||
|
|
@ -79,10 +79,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
|
||||
private static void GetKeyFromEmptyPrefix(string entry, IDictionary<string, string> results)
|
||||
{
|
||||
string key;
|
||||
int dotPosition = entry.IndexOf('.');
|
||||
int bracketPosition = entry.IndexOf('[');
|
||||
int delimiterPosition = -1;
|
||||
var dotPosition = entry.IndexOf('.');
|
||||
var bracketPosition = entry.IndexOf('[');
|
||||
var delimiterPosition = -1;
|
||||
|
||||
if (dotPosition == -1)
|
||||
{
|
||||
|
|
@ -103,20 +102,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
}
|
||||
}
|
||||
|
||||
key = delimiterPosition == -1 ? entry : entry.Substring(0, delimiterPosition);
|
||||
var key = delimiterPosition == -1 ? entry : entry.Substring(0, delimiterPosition);
|
||||
results[key] = key;
|
||||
}
|
||||
|
||||
private static void GetKeyFromNonEmptyPrefix(string prefix, string entry, IDictionary<string, string> results)
|
||||
{
|
||||
string key = null;
|
||||
string fullName = null;
|
||||
int keyPosition = prefix.Length + 1;
|
||||
string key;
|
||||
string fullName;
|
||||
var keyPosition = prefix.Length + 1;
|
||||
|
||||
switch (entry[prefix.Length])
|
||||
{
|
||||
case '.':
|
||||
int dotPosition = entry.IndexOf('.', keyPosition);
|
||||
var dotPosition = entry.IndexOf('.', keyPosition);
|
||||
if (dotPosition == -1)
|
||||
{
|
||||
dotPosition = entry.Length;
|
||||
|
|
@ -127,7 +126,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
break;
|
||||
|
||||
case '[':
|
||||
int bracketPosition = entry.IndexOf(']', keyPosition);
|
||||
var bracketPosition = entry.IndexOf(']', keyPosition);
|
||||
if (bracketPosition == -1)
|
||||
{
|
||||
// Malformed for dictionary
|
||||
|
|
@ -189,7 +188,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
|
||||
private sealed class PrefixComparer : IComparer<String>
|
||||
{
|
||||
private string _prefix;
|
||||
private readonly string _prefix;
|
||||
|
||||
public PrefixComparer(string prefix)
|
||||
{
|
||||
|
|
@ -198,7 +197,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
|
||||
public int Compare(string x, string y)
|
||||
{
|
||||
string testString = Object.ReferenceEquals(x, _prefix) ? y : x;
|
||||
var testString = object.ReferenceEquals(x, _prefix) ? y : x;
|
||||
if (IsPrefixMatch(_prefix, testString))
|
||||
{
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -14,14 +14,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public abstract class AssociatedMetadataProvider<TModelMetadata> : IModelMetadataProvider
|
||||
where TModelMetadata : ModelMetadata
|
||||
{
|
||||
private readonly ConcurrentDictionary<Type, TypeInformation> _typeInfoCache = new ConcurrentDictionary<Type, TypeInformation>();
|
||||
private readonly ConcurrentDictionary<Type, TypeInformation> _typeInfoCache =
|
||||
new ConcurrentDictionary<Type, TypeInformation>();
|
||||
|
||||
public IEnumerable<ModelMetadata> GetMetadataForProperties(object container, [NotNull] Type containerType)
|
||||
{
|
||||
return GetMetadataForPropertiesCore(container, containerType);
|
||||
}
|
||||
|
||||
public ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, [NotNull] Type containerType, [NotNull] string propertyName)
|
||||
public ModelMetadata GetMetadataForProperty(Func<object> modelAccessor,
|
||||
[NotNull] Type containerType,
|
||||
[NotNull] string propertyName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(propertyName))
|
||||
{
|
||||
|
|
@ -32,7 +35,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
PropertyInformation propertyInfo;
|
||||
if (!typeInfo.Properties.TryGetValue(propertyName, out propertyInfo))
|
||||
{
|
||||
throw new ArgumentException(Resources.FormatCommon_PropertyNotFound(containerType, propertyName), "propertyName");
|
||||
var message = Resources.FormatCommon_PropertyNotFound(containerType, propertyName);
|
||||
throw new ArgumentException(message, "propertyName");
|
||||
}
|
||||
|
||||
return CreatePropertyMetadata(modelAccessor, propertyInfo);
|
||||
|
|
@ -40,7 +44,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
public ModelMetadata GetMetadataForType(Func<object> modelAccessor, [NotNull] Type modelType)
|
||||
{
|
||||
TModelMetadata prototype = GetTypeInformation(modelType).Prototype;
|
||||
var prototype = GetTypeInformation(modelType).Prototype;
|
||||
return CreateMetadataFromPrototype(prototype, modelAccessor);
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +55,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
string propertyName);
|
||||
|
||||
// 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);
|
||||
|
||||
private IEnumerable<ModelMetadata> GetMetadataForPropertiesCore(object container, Type containerType)
|
||||
|
|
@ -82,7 +86,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
private TypeInformation GetTypeInformation(Type type, IEnumerable<Attribute> associatedAttributes = null)
|
||||
{
|
||||
// This retrieval is implemented as a TryGetValue/TryAdd instead of a GetOrAdd to avoid the performance cost of creating instance delegates
|
||||
// This retrieval is implemented as a TryGetValue/TryAdd instead of a GetOrAdd
|
||||
// to avoid the performance cost of creating instance delegates
|
||||
TypeInformation typeInfo;
|
||||
if (!_typeInfoCache.TryGetValue(type, out typeInfo))
|
||||
{
|
||||
|
|
@ -102,7 +107,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
var info = new TypeInformation
|
||||
{
|
||||
Prototype = CreateMetadataPrototype(attributes, containerType: null, modelType: type, propertyName: null)
|
||||
Prototype = CreateMetadataPrototype(attributes,
|
||||
containerType: null,
|
||||
modelType: type,
|
||||
propertyName: null)
|
||||
};
|
||||
|
||||
var properties = new Dictionary<string, PropertyInformation>();
|
||||
|
|
@ -155,15 +163,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Uses Lightweight Code Gen to generate a tiny delegate that gets the property value
|
||||
// This is an optimization to avoid having to go through the much slower System.Reflection APIs
|
||||
// e.g. generates (object o) => (Person)o.Id
|
||||
private static Func<object, object> CreateDynamicValueAccessor(MethodInfo getMethodInfo, Type declaringType, string propertyName)
|
||||
private static Func<object, object> CreateDynamicValueAccessor(MethodInfo getMethodInfo,
|
||||
Type declaringType,
|
||||
string propertyName)
|
||||
{
|
||||
Contract.Assert(getMethodInfo != null && getMethodInfo.IsPublic && !getMethodInfo.IsStatic);
|
||||
|
||||
var declaringTypeInfo = declaringType.GetTypeInfo();
|
||||
var propertyType = getMethodInfo.ReturnType;
|
||||
var dynamicMethod = new DynamicMethod("Get" + propertyName + "From" + declaringType.Name,
|
||||
typeof(object),
|
||||
new [] { typeof(object) });
|
||||
var dynamicMethod = new DynamicMethod("Get" + propertyName + "From" + declaringType.Name,
|
||||
typeof(object),
|
||||
new[] { typeof(object) });
|
||||
var ilg = dynamicMethod.GetILGenerator();
|
||||
|
||||
// Load the container onto the stack, convert from object => declaring type for the property
|
||||
|
|
|
|||
|
|
@ -2,10 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
|
|
@ -33,7 +29,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Constructor for creating real instances of the metadata class based on a prototype
|
||||
protected CachedModelMetadata(CachedModelMetadata<TPrototypeCache> prototype, Func<object> modelAccessor)
|
||||
: base(prototype.Provider, prototype.ContainerType, modelAccessor, prototype.ModelType, prototype.PropertyName)
|
||||
: base(prototype.Provider,
|
||||
prototype.ContainerType,
|
||||
modelAccessor,
|
||||
prototype.ModelType,
|
||||
prototype.PropertyName)
|
||||
{
|
||||
CacheKey = prototype.CacheKey;
|
||||
PrototypeCache = prototype.PrototypeCache;
|
||||
|
|
@ -43,8 +43,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
// Constructor for creating the prototype instances of the metadata class
|
||||
protected CachedModelMetadata(DataAnnotationsModelMetadataProvider provider, Type containerType, Type modelType, string propertyName, TPrototypeCache prototypeCache)
|
||||
: base(provider, containerType, null /* modelAccessor */, modelType, propertyName)
|
||||
protected CachedModelMetadata(DataAnnotationsModelMetadataProvider provider,
|
||||
Type containerType,
|
||||
Type modelType,
|
||||
string propertyName,
|
||||
TPrototypeCache prototypeCache)
|
||||
: base(provider, containerType, modelAccessor: null, modelType: modelType, propertyName: propertyName)
|
||||
{
|
||||
PrototypeCache = prototypeCache;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,17 +8,22 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
public class EmptyModelMetadataProvider : AssociatedMetadataProvider<ModelMetadata>
|
||||
{
|
||||
protected override ModelMetadata CreateMetadataPrototype(IEnumerable<Attribute> attributes,
|
||||
Type containerType,
|
||||
Type modelType,
|
||||
protected override ModelMetadata CreateMetadataPrototype(IEnumerable<Attribute> attributes,
|
||||
Type containerType,
|
||||
Type modelType,
|
||||
string propertyName)
|
||||
{
|
||||
return new ModelMetadata(this, containerType, null, modelType, propertyName);
|
||||
}
|
||||
|
||||
protected override ModelMetadata CreateMetadataFromPrototype(ModelMetadata prototype, Func<object> modelAccessor)
|
||||
protected override ModelMetadata CreateMetadataFromPrototype(ModelMetadata prototype,
|
||||
Func<object> modelAccessor)
|
||||
{
|
||||
return new ModelMetadata(this, prototype.ContainerType, modelAccessor, prototype.ModelType, prototype.PropertyName);
|
||||
return new ModelMetadata(this,
|
||||
prototype.ContainerType,
|
||||
modelAccessor,
|
||||
prototype.ModelType,
|
||||
prototype.PropertyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
||||
|
|
@ -27,10 +26,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private Type _realModelType;
|
||||
private string _simpleDisplayText;
|
||||
|
||||
public ModelMetadata([NotNull] IModelMetadataProvider provider,
|
||||
Type containerType,
|
||||
public ModelMetadata([NotNull] IModelMetadataProvider provider,
|
||||
Type containerType,
|
||||
Func<object> modelAccessor,
|
||||
[NotNull] Type modelType,
|
||||
[NotNull] Type modelType,
|
||||
string propertyName)
|
||||
{
|
||||
Provider = provider;
|
||||
|
|
@ -181,7 +180,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "The method is a delegating helper to choose among multiple property values")]
|
||||
public virtual string GetDisplayName()
|
||||
{
|
||||
return PropertyName ?? ModelType.Name;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
|
|
@ -57,14 +56,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
if (_modelName == null)
|
||||
{
|
||||
_modelName = String.Empty;
|
||||
_modelName = string.Empty;
|
||||
}
|
||||
return _modelName;
|
||||
}
|
||||
set { _modelName = value; }
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This is writeable to support unit testing")]
|
||||
public ModelStateDictionary ModelState
|
||||
{
|
||||
get
|
||||
|
|
@ -121,7 +119,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
if (_propertyMetadata == null)
|
||||
{
|
||||
_propertyMetadata = ModelMetadata.Properties.ToDictionary(m => m.PropertyName, StringComparer.OrdinalIgnoreCase);
|
||||
_propertyMetadata = ModelMetadata.Properties
|
||||
.ToDictionary(m => m.PropertyName,
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
return _propertyMetadata;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
public ModelError(string errorMessage)
|
||||
{
|
||||
ErrorMessage = errorMessage ?? String.Empty;
|
||||
ErrorMessage = errorMessage ?? string.Empty;
|
||||
}
|
||||
|
||||
public Exception Exception { get; private set; }
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
public class ModelStateDictionary : IDictionary<string, ModelState>
|
||||
{
|
||||
private readonly IDictionary<string, ModelState> _innerDictionary = new Dictionary<string, ModelState>(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly IDictionary<string, ModelState> _innerDictionary =
|
||||
new Dictionary<string, ModelState>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public ModelStateDictionary()
|
||||
{
|
||||
|
|
@ -54,7 +55,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
public ModelValidationState ValidationState
|
||||
{
|
||||
get { return GetValidity(_innerDictionary); }
|
||||
get { return GetValidity(_innerDictionary); }
|
||||
}
|
||||
|
||||
public ModelState this[[NotNull] string key]
|
||||
|
|
@ -67,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
set
|
||||
{
|
||||
if(value == null)
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
[NotNull] ClientModelValidationContext context)
|
||||
{
|
||||
var errorMessage = ((CompareAttributeWrapper)Attribute).FormatErrorMessage(context);
|
||||
var clientRule = new ModelClientValidationEqualToRule(errorMessage,
|
||||
var clientRule = new ModelClientValidationEqualToRule(errorMessage,
|
||||
FormatPropertyForClientValidation(Attribute.OtherProperty));
|
||||
return new [] { clientRule };
|
||||
return new[] { clientRule };
|
||||
}
|
||||
|
||||
private static string FormatPropertyForClientValidation(string property)
|
||||
|
|
@ -50,9 +50,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public string FormatErrorMessage(ClientModelValidationContext context)
|
||||
{
|
||||
var displayName = context.ModelMetadata.GetDisplayName();
|
||||
return string.Format(CultureInfo.CurrentCulture,
|
||||
ErrorMessageString,
|
||||
displayName,
|
||||
return string.Format(CultureInfo.CurrentCulture,
|
||||
ErrorMessageString,
|
||||
displayName,
|
||||
GetOtherPropertyDisplayName(context));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
_errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
public bool IsRequired { get { return false; } }
|
||||
public bool IsRequired
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,42 +11,51 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
public class InvalidModelValidatorProvider : AssociatedValidatorProvider
|
||||
{
|
||||
protected override IEnumerable<IModelValidator> GetValidators(ModelMetadata metadata,
|
||||
protected override IEnumerable<IModelValidator> GetValidators(ModelMetadata metadata,
|
||||
IEnumerable<Attribute> attributes)
|
||||
{
|
||||
if (metadata.ContainerType == null || String.IsNullOrEmpty(metadata.PropertyName))
|
||||
if (metadata.ContainerType == null || string.IsNullOrEmpty(metadata.PropertyName))
|
||||
{
|
||||
// Validate that the type's fields and nonpublic properties don't have any validation attributes on them
|
||||
// Validation only runs against public properties
|
||||
// Validate that the type's fields and nonpublic properties don't have any validation attributes on
|
||||
// them. Validation only runs against public properties
|
||||
var type = metadata.ModelType;
|
||||
var nonPublicProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
foreach (var nonPublicProperty in nonPublicProperties)
|
||||
{
|
||||
if (nonPublicProperty.GetCustomAttributes(typeof(ValidationAttribute), inherit: true).Any())
|
||||
{
|
||||
yield return new ErrorModelValidator(Resources.FormatValidationAttributeOnNonPublicProperty(nonPublicProperty.Name, type));
|
||||
var message = Resources.FormatValidationAttributeOnNonPublicProperty(nonPublicProperty.Name,
|
||||
type);
|
||||
yield return new ErrorModelValidator(message);
|
||||
}
|
||||
}
|
||||
|
||||
var allFields = metadata.ModelType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||
var allFields = metadata.ModelType.GetFields(bindingFlags);
|
||||
foreach (var field in allFields)
|
||||
{
|
||||
if (field.GetCustomAttributes(typeof(ValidationAttribute), inherit: true).Any())
|
||||
{
|
||||
yield return new ErrorModelValidator(Resources.FormatValidationAttributeOnField(field.Name, type));
|
||||
var message = Resources.FormatValidationAttributeOnField(field.Name, type);
|
||||
yield return new ErrorModelValidator(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Validate that value-typed properties marked as [Required] are also marked as [DataMember(IsRequired=true)]
|
||||
// Certain formatters may not recognize a member as required if it's marked as [Required] but not [DataMember(IsRequired=true)]
|
||||
// This is not a problem for reference types because [Required] will still cause a model error to be raised after a null value is deserialized
|
||||
if (metadata.ModelType.GetTypeInfo().IsValueType && attributes.Any(attribute => attribute is RequiredAttribute))
|
||||
// Validate that value-typed properties marked as [Required] are also marked as
|
||||
// [DataMember(IsRequired=true)]. Certain formatters may not recognize a member as required if it's
|
||||
// marked as [Required] but not [DataMember(IsRequired=true)]. This is not a problem for reference
|
||||
// types because [Required] will still cause a model error to be raised after a null value is
|
||||
// deserialized.
|
||||
if (metadata.ModelType.GetTypeInfo().IsValueType &&
|
||||
attributes.Any(attribute => attribute is RequiredAttribute))
|
||||
{
|
||||
if (!DataMemberModelValidatorProvider.IsRequiredDataMember(metadata.ContainerType, attributes))
|
||||
{
|
||||
yield return new ErrorModelValidator(Resources.FormatMissingDataMemberIsRequired(metadata.PropertyName, metadata.ContainerType));
|
||||
var message = Resources.FormatMissingDataMemberIsRequired(metadata.PropertyName,
|
||||
metadata.ContainerType);
|
||||
yield return new ErrorModelValidator(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
}
|
||||
|
||||
public ModelValidationNode([NotNull] ModelMetadata modelMetadata,
|
||||
[NotNull] string modelStateKey,
|
||||
public ModelValidationNode([NotNull] ModelMetadata modelMetadata,
|
||||
[NotNull] string modelStateKey,
|
||||
IEnumerable<ModelValidationNode> childNodes)
|
||||
{
|
||||
ModelMetadata = modelMetadata;
|
||||
|
|
@ -151,13 +151,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var modelState = validationContext.ModelState;
|
||||
|
||||
var model = ModelMetadata.Model;
|
||||
var updatedMetadata = validationContext.MetadataProvider.GetMetadataForType(() => model, ModelMetadata.ModelType);
|
||||
var updatedMetadata = validationContext.MetadataProvider.GetMetadataForType(() => model,
|
||||
ModelMetadata.ModelType);
|
||||
|
||||
foreach (var propertyMetadata in updatedMetadata.Properties)
|
||||
{
|
||||
// Only want to add errors to ModelState if something doesn't already exist for the property node,
|
||||
// else we could end up with duplicate or irrelevant error messages.
|
||||
var propertyKeyRoot = ModelBindingHelper.CreatePropertyModelName(ModelStateKey, propertyMetadata.PropertyName);
|
||||
var propertyKeyRoot = ModelBindingHelper.CreatePropertyModelName(ModelStateKey,
|
||||
propertyMetadata.PropertyName);
|
||||
|
||||
if (modelState.GetFieldValidationState(propertyKeyRoot) == ModelValidationState.Unvalidated)
|
||||
{
|
||||
|
|
@ -167,7 +169,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
foreach (var propertyResult in propertyValidator.Validate(propertyValidationContext))
|
||||
{
|
||||
var thisErrorKey = ModelBindingHelper.CreatePropertyModelName(propertyKeyRoot, propertyResult.MemberName);
|
||||
var thisErrorKey = ModelBindingHelper.CreatePropertyModelName(propertyKeyRoot,
|
||||
propertyResult.MemberName);
|
||||
modelState.AddModelError(thisErrorKey, propertyResult.Message);
|
||||
}
|
||||
}
|
||||
|
|
@ -187,7 +190,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// If the Model at the current node is null and there is no parent, we cannot validate, and the
|
||||
// DataAnnotationsModelValidator will throw. So we intercept here to provide a catch-all value-required
|
||||
// validation error
|
||||
var modelStateKey = ModelBindingHelper.CreatePropertyModelName(ModelStateKey, ModelMetadata.GetDisplayName());
|
||||
var modelStateKey = ModelBindingHelper.CreatePropertyModelName(ModelStateKey,
|
||||
ModelMetadata.GetDisplayName());
|
||||
if (parentNode == null && ModelMetadata.Model == null)
|
||||
{
|
||||
modelState.AddModelError(modelStateKey, Resources.Validation_ValueNotFound);
|
||||
|
|
@ -201,13 +205,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var validator = validators[i];
|
||||
foreach (var validationResult in validator.Validate(validationContext))
|
||||
{
|
||||
var currentModelStateKey = ModelBindingHelper.CreatePropertyModelName(ModelStateKey, validationResult.MemberName);
|
||||
var currentModelStateKey = ModelBindingHelper.CreatePropertyModelName(ModelStateKey,
|
||||
validationResult.MemberName);
|
||||
modelState.AddModelError(currentModelStateKey, validationResult.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<IModelValidator> GetValidators(ModelValidationContext validationContext, ModelMetadata metadata)
|
||||
private static IEnumerable<IModelValidator> GetValidators(ModelValidationContext validationContext,
|
||||
ModelMetadata metadata)
|
||||
{
|
||||
return validationContext.ValidatorProviders.SelectMany(vp => vp.GetValidators(metadata));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
[NotNull] ClientModelValidationContext context)
|
||||
{
|
||||
var errorMessage = GetErrorMessage(context.ModelMetadata);
|
||||
return new[] { new ModelClientValidationStringLengthRule(errorMessage,
|
||||
Attribute.MinimumLength,
|
||||
Attribute.MaximumLength) };
|
||||
var rule = new ModelClientValidationStringLengthRule(errorMessage,
|
||||
Attribute.MinimumLength,
|
||||
Attribute.MaximumLength);
|
||||
return new[] { rule };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,16 +4,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "It is more fundamentally a value provider than a collection")]
|
||||
public class CompositeValueProvider : Collection<IValueProvider>, IEnumerableValueProvider
|
||||
{
|
||||
public CompositeValueProvider()
|
||||
public CompositeValueProvider()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
|
@ -65,7 +63,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static Task<IDictionary<string, string>> GetKeysFromPrefixFromProvider(IValueProvider provider,
|
||||
private static Task<IDictionary<string, string>> GetKeysFromPrefixFromProvider(IValueProvider provider,
|
||||
string prefix)
|
||||
{
|
||||
var enumeratedProvider = provider as IEnumerableValueProvider;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
|
|
@ -15,7 +14,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public IValueProvider GetValueProvider(RequestContext requestContext)
|
||||
{
|
||||
var request = requestContext.HttpContext.Request;
|
||||
|
||||
|
||||
if (IsSupportedContentType(request))
|
||||
{
|
||||
var culture = GetCultureInfo(request);
|
||||
|
|
@ -34,8 +33,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
private static CultureInfo GetCultureInfo(HttpRequest request)
|
||||
{
|
||||
// TODO: Tracked via https://github.com/aspnet/HttpAbstractions/issues/10. Determine what's the right way to
|
||||
// map Accept-Language to culture.
|
||||
// TODO: Tracked via https://github.com/aspnet/HttpAbstractions/issues/10.
|
||||
// Determine what's the right way to map Accept-Language to culture.
|
||||
return CultureInfo.CurrentCulture;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var type = value.GetType();
|
||||
if (type != typeof(string))
|
||||
{
|
||||
string message = Resources.FormatValueProviderResult_NoConverterExists(type, destinationType);
|
||||
var message = Resources.FormatValueProviderResult_NoConverterExists(type, destinationType);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,50 +8,35 @@ using System.Linq;
|
|||
using Microsoft.AspNet.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Test.Binders
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class AssociatedMetadataProviderTest
|
||||
{
|
||||
// GetMetadataForProperties
|
||||
|
||||
//[Fact]
|
||||
//public void GetMetadataForPropertiesNullContainerTypeThrows()
|
||||
//{
|
||||
// // Arrange
|
||||
// TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
|
||||
|
||||
// // Act & Assert
|
||||
// ExceptionAssert.ThrowsArgumentNull(
|
||||
// () => provider.GetMetadataForProperties(new Object(), containerType: null),
|
||||
// "containerType");
|
||||
//}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForPropertiesCreatesMetadataForAllPropertiesOnModelWithPropertyValues()
|
||||
{
|
||||
// Arrange
|
||||
PropertyModel model = new PropertyModel { LocalAttributes = 42, MetadataAttributes = "hello", MixedAttributes = 21.12 };
|
||||
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
|
||||
var model = new PropertyModel { LocalAttributes = 42, MetadataAttributes = "hello", MixedAttributes = 21.12 };
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
|
||||
// Act
|
||||
provider.GetMetadataForProperties(model, typeof(PropertyModel)).ToList(); // Call ToList() to force the lazy evaluation to evaluate
|
||||
// Call ToList() to force the lazy evaluation to evaluate
|
||||
provider.GetMetadataForProperties(model, typeof(PropertyModel)).ToList();
|
||||
|
||||
// Assert
|
||||
CreateMetadataPrototypeParams local =
|
||||
provider.CreateMetadataPrototypeLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
|
||||
m.PropertyName == "LocalAttributes");
|
||||
var local = provider.CreateMetadataPrototypeLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
|
||||
m.PropertyName == "LocalAttributes");
|
||||
Assert.Equal(typeof(int), local.ModelType);
|
||||
Assert.True(local.Attributes.Any(a => a is RequiredAttribute));
|
||||
|
||||
CreateMetadataPrototypeParams metadata =
|
||||
provider.CreateMetadataPrototypeLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
|
||||
m.PropertyName == "MetadataAttributes");
|
||||
var metadata = provider.CreateMetadataPrototypeLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
|
||||
m.PropertyName == "MetadataAttributes");
|
||||
Assert.Equal(typeof(string), metadata.ModelType);
|
||||
Assert.True(metadata.Attributes.Any(a => a is RangeAttribute));
|
||||
|
||||
CreateMetadataPrototypeParams mixed =
|
||||
provider.CreateMetadataPrototypeLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
|
||||
m.PropertyName == "MixedAttributes");
|
||||
var mixed = provider.CreateMetadataPrototypeLog.Single(m => m.ContainerType == typeof(PropertyModel) &&
|
||||
m.PropertyName == "MixedAttributes");
|
||||
Assert.Equal(typeof(double), mixed.ModelType);
|
||||
Assert.True(mixed.Attributes.Any(a => a is RequiredAttribute));
|
||||
Assert.True(mixed.Attributes.Any(a => a is RangeAttribute));
|
||||
|
|
@ -61,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test.Binders
|
|||
public void GetMetadataForPropertyWithNullContainerReturnsMetadataWithNullValuesForProperties()
|
||||
{
|
||||
// Arrange
|
||||
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
|
||||
// Act
|
||||
provider.GetMetadataForProperties(null, typeof(PropertyModel)).ToList(); // Call ToList() to force the lazy evaluation to evaluate
|
||||
|
|
@ -80,7 +65,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test.Binders
|
|||
public void GetMetadataForPropertyNullOrEmptyPropertyNameThrows()
|
||||
{
|
||||
// Arrange
|
||||
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsArgument(
|
||||
|
|
@ -97,7 +82,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test.Binders
|
|||
public void GetMetadataForPropertyInvalidPropertyNameThrows()
|
||||
{
|
||||
// Arrange
|
||||
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsArgument(
|
||||
|
|
@ -110,67 +95,57 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test.Binders
|
|||
public void GetMetadataForPropertyWithLocalAttributes()
|
||||
{
|
||||
// Arrange
|
||||
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
|
||||
ModelMetadata metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(int), "LocalAttributes");
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(int), "LocalAttributes");
|
||||
provider.CreateMetadataFromPrototypeReturnValue = metadata;
|
||||
|
||||
// Act
|
||||
ModelMetadata result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "LocalAttributes");
|
||||
var result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "LocalAttributes");
|
||||
|
||||
// Assert
|
||||
Assert.Same(metadata, result);
|
||||
Assert.True(provider.CreateMetadataPrototypeLog.Single(parameters => parameters.PropertyName == "LocalAttributes").Attributes.Any(a => a is RequiredAttribute));
|
||||
Assert.True(provider.CreateMetadataPrototypeLog
|
||||
.Single(parameters => parameters.PropertyName == "LocalAttributes")
|
||||
.Attributes.Any(a => a is RequiredAttribute));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForPropertyWithMetadataAttributes()
|
||||
{
|
||||
// Arrange
|
||||
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
|
||||
ModelMetadata metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(string), "MetadataAttributes");
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(string), "MetadataAttributes");
|
||||
provider.CreateMetadataFromPrototypeReturnValue = metadata;
|
||||
|
||||
// Act
|
||||
ModelMetadata result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "MetadataAttributes");
|
||||
var result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "MetadataAttributes");
|
||||
|
||||
// Assert
|
||||
Assert.Same(metadata, result);
|
||||
CreateMetadataPrototypeParams parms = provider.CreateMetadataPrototypeLog.Single(p => p.PropertyName == "MetadataAttributes");
|
||||
Assert.True(parms.Attributes.Any(a => a is RangeAttribute));
|
||||
var parmaters = provider.CreateMetadataPrototypeLog.Single(p => p.PropertyName == "MetadataAttributes");
|
||||
Assert.True(parmaters.Attributes.Any(a => a is RangeAttribute));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForPropertyWithMixedAttributes()
|
||||
{
|
||||
// Arrange
|
||||
TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
|
||||
ModelMetadata metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(double), "MixedAttributes");
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(double), "MixedAttributes");
|
||||
provider.CreateMetadataFromPrototypeReturnValue = metadata;
|
||||
|
||||
// Act
|
||||
ModelMetadata result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "MixedAttributes");
|
||||
var result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "MixedAttributes");
|
||||
|
||||
// Assert
|
||||
Assert.Same(metadata, result);
|
||||
CreateMetadataPrototypeParams parms = provider.CreateMetadataPrototypeLog.Single(p => p.PropertyName == "MixedAttributes");
|
||||
var parms = provider.CreateMetadataPrototypeLog.Single(p => p.PropertyName == "MixedAttributes");
|
||||
Assert.True(parms.Attributes.Any(a => a is RequiredAttribute));
|
||||
Assert.True(parms.Attributes.Any(a => a is RangeAttribute));
|
||||
}
|
||||
|
||||
// GetMetadataForType
|
||||
|
||||
//[Fact]
|
||||
//public void GetMetadataForTypeNullModelTypeThrows()
|
||||
//{
|
||||
// // Arrange
|
||||
// TestableAssociatedMetadataProvider provider = new TestableAssociatedMetadataProvider();
|
||||
|
||||
// // Act & Assert
|
||||
// ExceptionAssert.ThrowsArgumentNull(
|
||||
// () => provider.GetMetadataForType(() => new Object(), modelType: null),
|
||||
// "modelType");
|
||||
//}
|
||||
|
||||
#if NET45 // No ReadOnlyAttribute in K
|
||||
[Fact]
|
||||
public void GetMetadataForTypeIncludesAttributesOnType()
|
||||
|
|
@ -207,7 +182,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test.Binders
|
|||
}
|
||||
|
||||
private sealed class RequiredAttribute : Attribute
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
private sealed class RangeAttribute : Attribute
|
||||
{
|
||||
|
|
@ -228,7 +204,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test.Binders
|
|||
}
|
||||
#endif
|
||||
|
||||
class TestableAssociatedMetadataProvider : AssociatedMetadataProvider<ModelMetadata>
|
||||
private class TestableAssociatedMetadataProvider : AssociatedMetadataProvider<ModelMetadata>
|
||||
{
|
||||
public List<CreateMetadataPrototypeParams> CreateMetadataPrototypeLog = new List<CreateMetadataPrototypeParams>();
|
||||
public List<CreateMetadataFromPrototypeParams> CreateMetadataFromPrototypeLog = new List<CreateMetadataFromPrototypeParams>();
|
||||
|
|
@ -260,7 +236,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test.Binders
|
|||
}
|
||||
}
|
||||
|
||||
class CreateMetadataPrototypeParams
|
||||
private class CreateMetadataPrototypeParams
|
||||
{
|
||||
public IEnumerable<Attribute> Attributes { get; set; }
|
||||
public Type ContainerType { get; set; }
|
||||
|
|
@ -268,7 +244,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test.Binders
|
|||
public string PropertyName { get; set; }
|
||||
}
|
||||
|
||||
class CreateMetadataFromPrototypeParams
|
||||
private class CreateMetadataFromPrototypeParams
|
||||
{
|
||||
public ModelMetadata Prototype { get; set; }
|
||||
public object Model { get; set; }
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ using Moq;
|
|||
#endif
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class ModelMetadataTest
|
||||
{
|
||||
|
|
@ -20,10 +20,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void DefaultValues()
|
||||
{
|
||||
// Arrange
|
||||
Mock<IModelMetadataProvider> provider = new Mock<IModelMetadataProvider>();
|
||||
var provider = new Mock<IModelMetadataProvider>();
|
||||
|
||||
// Act
|
||||
ModelMetadata metadata = new ModelMetadata(provider.Object, typeof(Exception), () => "model", typeof(string), "propertyName");
|
||||
var metadata = new ModelMetadata(provider.Object, typeof(Exception), () => "model", typeof(string), "propertyName");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(Exception), metadata.ContainerType);
|
||||
|
|
@ -39,7 +39,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
|
||||
// IsComplexType
|
||||
|
||||
struct IsComplexTypeModel
|
||||
private struct IsComplexTypeModel
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void IsComplexTypeTestsReturnsFalseForSimpleTypes(Type type)
|
||||
{
|
||||
// Arrange
|
||||
Mock<IModelMetadataProvider> provider = new Mock<IModelMetadataProvider>();
|
||||
var provider = new Mock<IModelMetadataProvider>();
|
||||
|
||||
// Act
|
||||
var modelMetadata = new ModelMetadata(provider.Object, null, null, type, null);
|
||||
|
|
@ -68,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void IsComplexTypeTestsReturnsTrueForComplexTypes(Type type)
|
||||
{
|
||||
// Arrange
|
||||
Mock<IModelMetadataProvider> provider = new Mock<IModelMetadataProvider>();
|
||||
var provider = new Mock<IModelMetadataProvider>();
|
||||
|
||||
// Act
|
||||
var modelMetadata = new ModelMetadata(provider.Object, null, null, type, null);
|
||||
|
|
@ -83,7 +83,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void IsNullableValueTypeTests()
|
||||
{
|
||||
// Arrange
|
||||
Mock<IModelMetadataProvider> provider = new Mock<IModelMetadataProvider>();
|
||||
var provider = new Mock<IModelMetadataProvider>();
|
||||
|
||||
// Act & Assert
|
||||
Assert.False(new ModelMetadata(provider.Object, null, null, typeof(string), null).IsNullableValueType);
|
||||
|
|
@ -98,16 +98,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void PropertiesCallsProvider()
|
||||
{
|
||||
// Arrange
|
||||
Type modelType = typeof(string);
|
||||
List<ModelMetadata> propertyMetadata = new List<ModelMetadata>();
|
||||
Mock<IModelMetadataProvider> provider = new Mock<IModelMetadataProvider>();
|
||||
ModelMetadata metadata = new ModelMetadata(provider.Object, null, null, modelType, null);
|
||||
var modelType = typeof(string);
|
||||
var propertyMetadata = new List<ModelMetadata>();
|
||||
var provider = new Mock<IModelMetadataProvider>();
|
||||
var metadata = new ModelMetadata(provider.Object, null, null, modelType, null);
|
||||
provider.Setup(p => p.GetMetadataForProperties(null, modelType))
|
||||
.Returns(propertyMetadata)
|
||||
.Verifiable();
|
||||
|
||||
// Act
|
||||
IEnumerable<ModelMetadata> result = metadata.Properties;
|
||||
var result = metadata.Properties;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(propertyMetadata, result.ToList());
|
||||
|
|
@ -118,31 +118,30 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
[Fact]
|
||||
public void PropertiesListGetsResetWhenModelGetsReset()
|
||||
{
|
||||
// Dev10 Bug #923263
|
||||
// Arrange
|
||||
IModelMetadataProvider provider = new EmptyModelMetadataProvider();
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, null, () => new Class1(), typeof(Class1), null);
|
||||
|
||||
// Act
|
||||
ModelMetadata[] originalProps = metadata.Properties.ToArray();
|
||||
var originalProps = metadata.Properties.ToArray();
|
||||
metadata.Model = new Class2();
|
||||
ModelMetadata[] newProps = metadata.Properties.ToArray();
|
||||
var newProps = metadata.Properties.ToArray();
|
||||
|
||||
// Assert
|
||||
ModelMetadata originalProp = Assert.Single(originalProps);
|
||||
var originalProp = Assert.Single(originalProps);
|
||||
Assert.Equal(typeof(string), originalProp.ModelType);
|
||||
Assert.Equal("Prop1", originalProp.PropertyName);
|
||||
ModelMetadata newProp = Assert.Single(newProps);
|
||||
var newProp = Assert.Single(newProps);
|
||||
Assert.Equal(typeof(int), newProp.ModelType);
|
||||
Assert.Equal("Prop2", newProp.PropertyName);
|
||||
}
|
||||
|
||||
class Class1
|
||||
private class Class1
|
||||
{
|
||||
public string Prop1 { get; set; }
|
||||
}
|
||||
|
||||
class Class2
|
||||
private class Class2
|
||||
{
|
||||
public int Prop2 { get; set; }
|
||||
}
|
||||
|
|
@ -154,11 +153,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void ReturnsPropertyNameWhenSetAndDisplayNameIsNull()
|
||||
{
|
||||
// Arrange
|
||||
Mock<IModelMetadataProvider> provider = new Mock<IModelMetadataProvider>();
|
||||
ModelMetadata metadata = new ModelMetadata(provider.Object, null, null, typeof(object), "PropertyName");
|
||||
var provider = new Mock<IModelMetadataProvider>();
|
||||
var metadata = new ModelMetadata(provider.Object, null, null, typeof(object), "PropertyName");
|
||||
|
||||
// Act
|
||||
string result = metadata.GetDisplayName();
|
||||
var result = metadata.GetDisplayName();
|
||||
|
||||
// Assert
|
||||
Assert.Equal("PropertyName", result);
|
||||
|
|
@ -168,11 +167,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void ReturnsTypeNameWhenPropertyNameAndDisplayNameAreNull()
|
||||
{
|
||||
// Arrange
|
||||
Mock<IModelMetadataProvider> provider = new Mock<IModelMetadataProvider>();
|
||||
ModelMetadata metadata = new ModelMetadata(provider.Object, null, null, typeof(object), null);
|
||||
var provider = new Mock<IModelMetadataProvider>();
|
||||
var metadata = new ModelMetadata(provider.Object, null, null, typeof(object), null);
|
||||
|
||||
// Act
|
||||
string result = metadata.GetDisplayName();
|
||||
var result = metadata.GetDisplayName();
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Object", result);
|
||||
|
|
@ -186,7 +185,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public int IntField = 0;
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public Nullable<int> NullableIntValue { get; set; }
|
||||
public int? NullableIntValue { get; set; }
|
||||
public int[] Array { get; set; }
|
||||
|
||||
public string this[int index]
|
||||
|
|
|
|||
|
|
@ -20,23 +20,41 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
get
|
||||
{
|
||||
yield return new object[] { new RegularExpressionAttribute("abc"),
|
||||
typeof(RegularExpressionAttributeAdapter) };
|
||||
yield return new object[]
|
||||
{
|
||||
new RegularExpressionAttribute("abc"),
|
||||
typeof(RegularExpressionAttributeAdapter)
|
||||
};
|
||||
|
||||
yield return new object[] { new MaxLengthAttribute(),
|
||||
typeof(MaxLengthAttributeAdapter) };
|
||||
yield return new object[]
|
||||
{
|
||||
new MaxLengthAttribute(),
|
||||
typeof(MaxLengthAttributeAdapter)
|
||||
};
|
||||
|
||||
yield return new object[] { new MinLengthAttribute(1),
|
||||
typeof(MinLengthAttributeAdapter) };
|
||||
yield return new object[]
|
||||
{
|
||||
new MinLengthAttribute(1),
|
||||
typeof(MinLengthAttributeAdapter)
|
||||
};
|
||||
|
||||
yield return new object[] { new RangeAttribute(1, 100),
|
||||
typeof(RangeAttributeAdapter) };
|
||||
yield return new object[]
|
||||
{
|
||||
new RangeAttribute(1, 100),
|
||||
typeof(RangeAttributeAdapter)
|
||||
};
|
||||
|
||||
yield return new object[] { new StringLengthAttribute(6),
|
||||
typeof(StringLengthAttributeAdapter) };
|
||||
yield return new object[]
|
||||
{
|
||||
new StringLengthAttribute(6),
|
||||
typeof(StringLengthAttributeAdapter)
|
||||
};
|
||||
|
||||
yield return new object[] { new RequiredAttribute(),
|
||||
typeof(RequiredAttributeAdapter) };
|
||||
yield return new object[]
|
||||
{
|
||||
new RequiredAttribute(),
|
||||
typeof(RequiredAttributeAdapter)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Testing;
|
||||
#if NET45
|
||||
using Moq;
|
||||
using Moq.Protected;
|
||||
|
|
@ -15,7 +14,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
public class DataAnnotationsModelValidatorTest
|
||||
{
|
||||
private static DataAnnotationsModelMetadataProvider _metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
private static DataAnnotationsModelMetadataProvider _metadataProvider =
|
||||
new DataAnnotationsModelMetadataProvider();
|
||||
|
||||
[Fact]
|
||||
public void ValuesSet()
|
||||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
get
|
||||
{
|
||||
yield return new object[]
|
||||
yield return new object[]
|
||||
{
|
||||
_metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length"),
|
||||
"Length"
|
||||
|
|
@ -52,7 +52,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
#if NET45
|
||||
[Theory]
|
||||
[MemberData("ValidateSetsMemberNamePropertyDataSet")]
|
||||
public void ValidateSetsMemberNamePropertyOfValidationContextForProperties(ModelMetadata metadata, string expectedMemberName)
|
||||
public void ValidateSetsMemberNamePropertyOfValidationContextForProperties(ModelMetadata metadata,
|
||||
string expectedMemberName)
|
||||
{
|
||||
// Arrange
|
||||
var attribute = new Mock<ValidationAttribute> { CallBase = true };
|
||||
|
|
@ -120,7 +121,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
attribute.Protected()
|
||||
.Setup<ValidationResult>("IsValid", ItExpr.IsAny<object>(), ItExpr.IsAny<ValidationContext>())
|
||||
.Returns(ValidationResult.Success);
|
||||
DataAnnotationsModelValidator validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validationContext = CreateValidationContext(metadata);
|
||||
|
||||
// Act
|
||||
|
|
@ -212,14 +213,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return new ModelValidationContext(null, null, null, metadata, null);
|
||||
}
|
||||
|
||||
class DerivedRequiredAttribute : RequiredAttribute
|
||||
private class DerivedRequiredAttribute : RequiredAttribute
|
||||
{
|
||||
}
|
||||
|
||||
class SampleModel
|
||||
private class SampleModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.Empty(validators);
|
||||
}
|
||||
|
||||
class ClassWithoutAttributes
|
||||
private class ClassWithoutAttributes
|
||||
{
|
||||
public int TheProperty { get; set; }
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
[DataContract]
|
||||
class ClassWithDataMemberIsRequiredTrue
|
||||
private class ClassWithDataMemberIsRequiredTrue
|
||||
{
|
||||
[DataMember(IsRequired = true)]
|
||||
public int TheProperty { get; set; }
|
||||
|
|
@ -66,7 +66,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
[DataContract]
|
||||
class ClassWithDataMemberIsRequiredFalse
|
||||
private class ClassWithDataMemberIsRequiredFalse
|
||||
{
|
||||
[DataMember(IsRequired = false)]
|
||||
public int TheProperty { get; set; }
|
||||
|
|
@ -86,7 +86,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.Empty(validators);
|
||||
}
|
||||
|
||||
class ClassWithDataMemberIsRequiredTrueWithoutDataContract
|
||||
private class ClassWithDataMemberIsRequiredTrueWithoutDataContract
|
||||
{
|
||||
[DataMember(IsRequired = true)]
|
||||
public int TheProperty { get; set; }
|
||||
|
|
|
|||
|
|
@ -51,6 +51,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void CombineWith()
|
||||
{
|
||||
// Arrange
|
||||
var expected = new[]
|
||||
{
|
||||
"Validating parent1.",
|
||||
"Validating parent2.",
|
||||
"Validated parent1.",
|
||||
"Validated parent2."
|
||||
};
|
||||
var log = new List<string>();
|
||||
|
||||
var allChildNodes = new[]
|
||||
|
|
@ -77,7 +84,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
parentNode1.Validate(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(new[] { "Validating parent1.", "Validating parent2.", "Validated parent1.", "Validated parent2." }, log.ToArray());
|
||||
Assert.Equal(expected, log);
|
||||
Assert.Equal(allChildNodes, parentNode1.ChildNodes.ToArray());
|
||||
}
|
||||
|
||||
|
|
@ -131,10 +138,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// 4. OnValidated()
|
||||
|
||||
// Arrange
|
||||
var expected = new[]
|
||||
{
|
||||
"In OnValidating()",
|
||||
"In LoggingValidatonAttribute.IsValid()",
|
||||
"In IValidatableObject.Validate()",
|
||||
"In OnValidated()"
|
||||
};
|
||||
var log = new List<string>();
|
||||
var model = new LoggingValidatableObject(log);
|
||||
var modelMetadata = GetModelMetadata(model);
|
||||
var childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "ValidStringProperty");
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var childMetadata = provider.GetMetadataForProperty(() => model, model.GetType(), "ValidStringProperty");
|
||||
var node = new ModelValidationNode(modelMetadata, "theKey");
|
||||
node.Validating += (sender, e) => log.Add("In OnValidating()");
|
||||
node.Validated += (sender, e) => log.Add("In OnValidated()");
|
||||
|
|
@ -145,7 +160,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
node.Validate(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(new[] { "In OnValidating()", "In LoggingValidatonAttribute.IsValid()", "In IValidatableObject.Validate()", "In OnValidated()" }, log.ToArray());
|
||||
Assert.Equal(expected, log);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -154,10 +169,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Because a property validator fails, the model validator shouldn't run
|
||||
|
||||
// Arrange
|
||||
var expected = new[]
|
||||
{
|
||||
"In OnValidating()",
|
||||
"In IValidatableObject.Validate()",
|
||||
"In OnValidated()"
|
||||
};
|
||||
var log = new List<string>();
|
||||
var model = new LoggingValidatableObject(log);
|
||||
var modelMetadata = GetModelMetadata(model);
|
||||
var childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "InvalidStringProperty");
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var childMetadata = provider.GetMetadataForProperty(() => model,
|
||||
model.GetType(),
|
||||
"InvalidStringProperty");
|
||||
var node = new ModelValidationNode(modelMetadata, "theKey");
|
||||
node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.InvalidStringProperty"));
|
||||
node.Validating += (sender, e) => log.Add("In OnValidating()");
|
||||
|
|
@ -168,8 +192,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
node.Validate(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(new[] { "In OnValidating()", "In IValidatableObject.Validate()", "In OnValidated()" }, log.ToArray());
|
||||
Assert.Equal("Sample error message", context.ModelState["theKey.InvalidStringProperty"].Errors[0].ErrorMessage);
|
||||
Assert.Equal(expected, log);
|
||||
Assert.Equal("Sample error message",
|
||||
context.ModelState["theKey.InvalidStringProperty"].Errors[0].ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -243,8 +268,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Assert
|
||||
Assert.False(context.ModelState.ContainsKey("theKey.RequiredString"));
|
||||
Assert.Equal("existing Error Text", context.ModelState["theKey.RequiredString.Dummy"].Errors[0].ErrorMessage);
|
||||
Assert.Equal("The field RangedInt must be between 10 and 30.", context.ModelState["theKey.RangedInt"].Errors[0].ErrorMessage);
|
||||
Assert.Equal("existing Error Text",
|
||||
context.ModelState["theKey.RequiredString.Dummy"].Errors[0].ErrorMessage);
|
||||
Assert.Equal("The field RangedInt must be between 10 and 30.",
|
||||
context.ModelState["theKey.RangedInt"].Errors[0].ErrorMessage);
|
||||
Assert.False(context.ModelState.ContainsKey("theKey.ValidString"));
|
||||
Assert.False(context.ModelState.ContainsKey("theKey"));
|
||||
}
|
||||
|
|
@ -261,7 +288,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
private static ModelValidationContext CreateContext(ModelMetadata metadata = null)
|
||||
{
|
||||
var providers = new IModelValidatorProvider[] {
|
||||
var providers = new IModelValidatorProvider[]
|
||||
{
|
||||
new DataAnnotationsModelValidatorProvider(),
|
||||
new DataMemberModelValidatorProvider()
|
||||
};
|
||||
|
|
@ -315,4 +343,4 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public string ValidString { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,13 +16,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
private static readonly IReadableStringCollection _backingStore = new ReadableStringCollection(
|
||||
new Dictionary<string, string[]>
|
||||
{
|
||||
{"foo", new[] { "fooValue1", "fooValue2"} },
|
||||
{"bar.baz", new[] {"someOtherValue" }},
|
||||
{"null_value", null},
|
||||
{"prefix.null_value", null}
|
||||
{ "foo", new[] { "fooValue1", "fooValue2"} },
|
||||
{ "bar.baz", new[] {"someOtherValue" } },
|
||||
{ "null_value", null },
|
||||
{ "prefix.null_value", null }
|
||||
});
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task ContainsPrefixAsync_WithEmptyCollection_ReturnsFalseForEmptyPrefix()
|
||||
{
|
||||
|
|
@ -79,15 +78,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public async Task GetKeysFromPrefixAsync_EmptyPrefix_ReturnsAllPrefixes()
|
||||
{
|
||||
// Arrange
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null);
|
||||
var expected = new Dictionary<string, string>
|
||||
{
|
||||
{ "bar", "bar" },
|
||||
{ "foo", "foo" },
|
||||
{ "null_value", "null_value" },
|
||||
{ "prefix", "prefix" }
|
||||
};
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, culture: null);
|
||||
|
||||
// Act
|
||||
var result = await valueProvider.GetKeysFromPrefixAsync("");
|
||||
|
||||
// Assert
|
||||
Assert.Equal<KeyValuePair<string, string>>(
|
||||
result.OrderBy(kvp => kvp.Key),
|
||||
new Dictionary<string, string> { { "bar", "bar" }, { "foo", "foo" }, { "null_value", "null_value" }, { "prefix", "prefix" } });
|
||||
Assert.Equal(expected, result.OrderBy(kvp => kvp.Key));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -147,7 +151,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
|
||||
// Assert
|
||||
Assert.NotNull(vpResult);
|
||||
Assert.Equal(new [] { "fooValue1", "fooValue2" }, (IList<string>)vpResult.RawValue);
|
||||
Assert.Equal(new[] { "fooValue1", "fooValue2" }, (IList<string>)vpResult.RawValue);
|
||||
Assert.Equal("fooValue1,fooValue2", vpResult.AttemptedValue);
|
||||
Assert.Equal(culture, vpResult.Culture);
|
||||
}
|
||||
|
|
@ -179,7 +183,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
// Arrange
|
||||
var backingStore = new ReadableStringCollection(
|
||||
new Dictionary<string, string[]>
|
||||
{
|
||||
{
|
||||
{ "key", new string[] { null, null, "value" } }
|
||||
});
|
||||
var culture = new CultureInfo("fr-FR");
|
||||
|
|
|
|||
|
|
@ -145,7 +145,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void ConvertToReturnsNullIfTrimmedValueIsEmptyString()
|
||||
{
|
||||
// Arrange
|
||||
var vpr = new ValueProviderResult(rawValue: null, attemptedValue: null, culture: CultureInfo.InvariantCulture);
|
||||
var vpr = new ValueProviderResult(rawValue: null,
|
||||
attemptedValue: null,
|
||||
culture: CultureInfo.InvariantCulture);
|
||||
|
||||
// Act
|
||||
var outValue = vpr.ConvertTo(typeof(int[]));
|
||||
|
|
@ -285,8 +287,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new[] { 1, 0 }})]
|
||||
[InlineData(new object[] { new[] {"Value1", "Value0" }})]
|
||||
[InlineData(new object[] { new[] { 1, 0 } })]
|
||||
[InlineData(new object[] { new[] { "Value1", "Value0" } })]
|
||||
public void ConvertTo_ConvertsEnumArrays(object value)
|
||||
{
|
||||
// Arrange
|
||||
|
|
@ -395,8 +397,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
yield return new object[] { (double)42.0, 42 };
|
||||
yield return new object[] { "2008-01-01", new DateTime(2008, 01, 01) };
|
||||
yield return new object[] { "00:00:20", TimeSpan.FromSeconds(20) };
|
||||
yield return new object[] { "c6687d3a-51f9-4159-8771-a66d2b7d7038",
|
||||
Guid.Parse("c6687d3a-51f9-4159-8771-a66d2b7d7038") };
|
||||
yield return new object[]
|
||||
{
|
||||
"c6687d3a-51f9-4159-8771-a66d2b7d7038",
|
||||
Guid.Parse("c6687d3a-51f9-4159-8771-a66d2b7d7038")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue