Cleaning up StyleCop errors

This commit is contained in:
Pranav K 2014-06-04 12:59:06 -07:00
parent b96da245cb
commit 97e06138ed
39 changed files with 427 additions and 341 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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>

View File

@ -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;

View File

@ -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
}

View File

@ -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;

View File

@ -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));
}
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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))

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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; }

View File

@ -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");
}

View File

@ -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));
}

View File

@ -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)
{

View File

@ -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);
}
}
}

View File

@ -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));
}

View File

@ -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 };
}
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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; }

View File

@ -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]

View File

@ -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)
};
}
}

View File

@ -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; }
}
}
}
}

View File

@ -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; }

View File

@ -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; }
}
}
}
}

View File

@ -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");

View File

@ -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")
};
}
}