From b0c7dc9220eff0d34d9170d228d51a141d3ca89f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 24 Apr 2014 06:45:53 -0700 Subject: [PATCH] Make IModelBinder and IValueProvider methods async --- .../DefaultActionSelector.cs | 2 +- .../ReflectedActionInvoker.cs | 2 +- .../Binders/ArrayModelBinder.cs | 7 +- .../Binders/CollectionModelBinder.cs | 36 +++--- .../Binders/ComplexModelDtoModelBinder.cs | 8 +- .../Binders/CompositeModelBinder.cs | 11 +- .../Binders/GenericModelBinder.cs | 7 +- .../Binders/IModelBinder.cs | 4 +- .../Binders/KeyValuePairModelBinder.cs | 47 +++++--- .../Binders/MutableObjectModelBinder.cs | 7 +- .../Binders/TypeConverterModelBinder.cs | 8 +- .../Binders/TypeMatchModelBinder.cs | 9 +- .../ValueProviders/CompositeValueProvider.cs | 9 +- .../DictionaryBasedValueProvider.cs | 13 +- .../ValueProviders/ElementalValueProvider.cs | 14 ++- .../ValueProviders/IValueProviders.cs | 7 +- .../ReadableStringCollectionValueProvider.cs | 19 +-- .../Binders/ArrayModelBinderTest.cs | 19 +-- .../Binders/CollectionModelBinderTest.cs | 39 +++--- .../Binders/CompositeModelBinderTest.cs | 113 ++++-------------- .../Binders/DictionaryModelBinderTest.cs | 11 +- .../Binders/KeyValuePairModelBinderTest.cs | 47 ++++---- .../Binders/MutableObjectModelBinderTest.cs | 13 +- .../Binders/TypeConverterModelBinderTest.cs | 25 ++-- .../Utils/SimpleHttpValueProvider.cs | 23 ++-- ...dableStringCollectionValueProviderTests.cs | 39 +++--- 26 files changed, 251 insertions(+), 288 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Core/DefaultActionSelector.cs b/src/Microsoft.AspNet.Mvc.Core/DefaultActionSelector.cs index a064c29e49..e0cc095b1d 100644 --- a/src/Microsoft.AspNet.Mvc.Core/DefaultActionSelector.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DefaultActionSelector.cs @@ -78,7 +78,7 @@ namespace Microsoft.AspNet.Mvc foreach (var parameter in action.Parameters.Where(p => p.ParameterBindingInfo != null)) { - if (actionBindingContext.ValueProvider.ContainsPrefix(parameter.ParameterBindingInfo.Prefix)) + if (await actionBindingContext.ValueProvider.ContainsPrefixAsync(parameter.ParameterBindingInfo.Prefix)) { candidate.FoundParameters++; if (parameter.IsOptional) diff --git a/src/Microsoft.AspNet.Mvc.Core/ReflectedActionInvoker.cs b/src/Microsoft.AspNet.Mvc.Core/ReflectedActionInvoker.cs index a602506e05..6f0a168925 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ReflectedActionInvoker.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ReflectedActionInvoker.cs @@ -278,7 +278,7 @@ namespace Microsoft.AspNet.Mvc HttpContext = actionBindingContext.ActionContext.HttpContext, FallbackToEmptyPrefix = true }; - actionBindingContext.ModelBinder.BindModel(modelBindingContext); + await actionBindingContext.ModelBinder.BindModelAsync(modelBindingContext); parameterValues[parameter.Name] = modelBindingContext.Model; } } diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ArrayModelBinder.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ArrayModelBinder.cs index 5e8bcdfd46..a76da1e1ee 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ArrayModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ArrayModelBinder.cs @@ -1,18 +1,19 @@ using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace Microsoft.AspNet.Mvc.ModelBinding { public class ArrayModelBinder : CollectionModelBinder { - public override bool BindModel(ModelBindingContext bindingContext) + public override Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext.ModelMetadata.IsReadOnly) { - return false; + return Task.FromResult(false); } - return base.BindModel(bindingContext); + return base.BindModelAsync(bindingContext); } protected override bool CreateOrReplaceCollection(ModelBindingContext bindingContext, IList newCollection) diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/CollectionModelBinder.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/CollectionModelBinder.cs index 4e09660bff..8be713bc78 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/CollectionModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/CollectionModelBinder.cs @@ -3,36 +3,36 @@ using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding { public class CollectionModelBinder : IModelBinder { - public virtual bool BindModel(ModelBindingContext bindingContext) + public virtual async Task BindModelAsync(ModelBindingContext bindingContext) { ModelBindingHelper.ValidateBindingContext(bindingContext); - if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName)) + if (!await bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName)) { return false; } - ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); - List boundCollection = (valueProviderResult != null) - ? BindSimpleCollection(bindingContext, valueProviderResult.RawValue, valueProviderResult.Culture) - : BindComplexCollection(bindingContext); + var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName); + var boundCollection = await ((valueProviderResult != null) ? + BindSimpleCollection(bindingContext, valueProviderResult.RawValue, valueProviderResult.Culture) : + BindComplexCollection(bindingContext)); - bool retVal = CreateOrReplaceCollection(bindingContext, boundCollection); - return retVal; + 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 List BindSimpleCollection(ModelBindingContext bindingContext, - object rawValue, - CultureInfo culture) + public async Task> BindSimpleCollection(ModelBindingContext bindingContext, + object rawValue, + CultureInfo culture) { if (rawValue == null) { @@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding }; object boundValue = null; - if (bindingContext.ModelBinder.BindModel(innerBindingContext)) + if (await bindingContext.ModelBinder.BindModelAsync(innerBindingContext)) { boundValue = innerBindingContext.Model; bindingContext.ValidationNode.ChildNodes.Add(innerBindingContext.ValidationNode); @@ -69,17 +69,17 @@ 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 List BindComplexCollection(ModelBindingContext bindingContext) + private async Task> BindComplexCollection(ModelBindingContext bindingContext) { string indexPropertyName = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName, "index"); - ValueProviderResult valueProviderResultIndex = bindingContext.ValueProvider.GetValue(indexPropertyName); + ValueProviderResult valueProviderResultIndex = await bindingContext.ValueProvider.GetValueAsync(indexPropertyName); IEnumerable indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(valueProviderResultIndex); - return BindComplexCollectionFromIndexes(bindingContext, indexNames); + return await BindComplexCollectionFromIndexes(bindingContext, indexNames); } // TODO: Convert to internal - public List BindComplexCollectionFromIndexes(ModelBindingContext bindingContext, - IEnumerable indexNames) + public async Task> BindComplexCollectionFromIndexes(ModelBindingContext bindingContext, + IEnumerable indexNames) { bool indexNamesIsFinite; if (indexNames != null) @@ -108,7 +108,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding Type modelType = bindingContext.ModelType; - if (bindingContext.ModelBinder.BindModel(childBindingContext)) + if (await bindingContext.ModelBinder.BindModelAsync(childBindingContext)) { didBind = true; boundValue = childBindingContext.Model; diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ComplexModelDtoModelBinder.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ComplexModelDtoModelBinder.cs index b2aa242998..9aaf0180c1 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ComplexModelDtoModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/ComplexModelDtoModelBinder.cs @@ -1,10 +1,11 @@ -using Microsoft.AspNet.Mvc.ModelBinding.Internal; +using System.Threading.Tasks; +using Microsoft.AspNet.Mvc.ModelBinding.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding { public sealed class ComplexModelDtoModelBinder : IModelBinder { - public bool BindModel(ModelBindingContext bindingContext) + public async Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext.ModelType == typeof(ComplexModelDto)) { @@ -21,8 +22,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding // bind and propagate the values // If we can't bind, then leave the result missing (don't add a null). - - if (bindingContext.ModelBinder.BindModel(propertyBindingContext)) + if (await bindingContext.ModelBinder.BindModelAsync(propertyBindingContext)) { dto.Results[propertyMetadata] = new ComplexModelDtoResult(propertyBindingContext.Model, propertyBindingContext.ValidationNode); } diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/CompositeModelBinder.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/CompositeModelBinder.cs index d2fc553a3e..4a125dc5ab 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/CompositeModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/CompositeModelBinder.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace Microsoft.AspNet.Mvc.ModelBinding { @@ -26,13 +27,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding private IModelBinder[] Binders { get; set; } - public virtual bool BindModel(ModelBindingContext bindingContext) + public virtual async Task BindModelAsync(ModelBindingContext bindingContext) { var newBindingContext = CreateNewBindingContext(bindingContext, bindingContext.ModelName, reuseValidationNode: true); - bool boundSuccessfully = TryBind(newBindingContext); + var boundSuccessfully = await TryBind(newBindingContext); if (!boundSuccessfully && !string.IsNullOrEmpty(bindingContext.ModelName) && bindingContext.FallbackToEmptyPrefix) { @@ -40,7 +41,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding newBindingContext = CreateNewBindingContext(bindingContext, modelName: string.Empty, reuseValidationNode: false); - boundSuccessfully = TryBind(newBindingContext); + boundSuccessfully = await TryBind(newBindingContext); } if (!boundSuccessfully) @@ -68,7 +69,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return true; } - private bool TryBind([NotNull] ModelBindingContext bindingContext) + private async Task TryBind([NotNull] ModelBindingContext bindingContext) { // TODO: RuntimeHelpers.EnsureSufficientExecutionStack does not exist in the CoreCLR. // Protects against stack overflow for deeply nested model binding @@ -76,7 +77,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding foreach (var binder in Binders) { - if (binder.BindModel(bindingContext)) + if (await binder.BindModelAsync(bindingContext)) { return true; } diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/GenericModelBinder.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/GenericModelBinder.cs index a9d614e22a..a6a189eaff 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/GenericModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/GenericModelBinder.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Reflection; +using System.Threading.Tasks; using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.Mvc.ModelBinding.Internal; @@ -18,16 +19,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding _activator = activator; } - public bool BindModel(ModelBindingContext bindingContext) + public Task BindModelAsync(ModelBindingContext bindingContext) { Type binderType = ResolveBinderType(bindingContext.ModelType); if (binderType != null) { var binder = (IModelBinder)_activator.CreateInstance(_serviceProvider, binderType); - return binder.BindModel(bindingContext); + return binder.BindModelAsync(bindingContext); } - return false; + return Task.FromResult(false); } private static Type ResolveBinderType(Type modelType) diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/IModelBinder.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/IModelBinder.cs index 4be6c8d05b..c366cfeda2 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/IModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/IModelBinder.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNet.Abstractions; +using System.Threading.Tasks; namespace Microsoft.AspNet.Mvc.ModelBinding { @@ -7,6 +7,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// public interface IModelBinder { - bool BindModel(ModelBindingContext bindingContext); + Task BindModelAsync(ModelBindingContext bindingContext); } } diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/KeyValuePairModelBinder.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/KeyValuePairModelBinder.cs index 34c581e08b..40bca55d7c 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/KeyValuePairModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/KeyValuePairModelBinder.cs @@ -1,31 +1,28 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding { public sealed class KeyValuePairModelBinder : IModelBinder { - public bool BindModel(ModelBindingContext bindingContext) + public async Task BindModelAsync(ModelBindingContext bindingContext) { ModelBindingHelper.ValidateBindingContext(bindingContext, typeof(KeyValuePair), allowNullModel: true); - TKey key; - bool keyBindingSucceeded = TryBindStrongModel(bindingContext, "key", out key); + var keyResult = await TryBindStrongModel(bindingContext, "key"); + var valueResult = await TryBindStrongModel(bindingContext, "value"); - TValue value; - bool valueBindingSucceeded = TryBindStrongModel(bindingContext, "value", out value); - - if (keyBindingSucceeded && valueBindingSucceeded) + if (keyResult.Success && valueResult.Success) { - bindingContext.Model = new KeyValuePair(key, value); + bindingContext.Model = new KeyValuePair(keyResult.Model, valueResult.Model); } - return keyBindingSucceeded || valueBindingSucceeded; + return keyResult.Success || valueResult.Success; } - // TODO: Make this internal - public bool TryBindStrongModel(ModelBindingContext parentBindingContext, - string propertyName, - out TModel model) + internal async Task> TryBindStrongModel(ModelBindingContext parentBindingContext, + string propertyName) { ModelBindingContext propertyBindingContext = new ModelBindingContext(parentBindingContext) { @@ -33,16 +30,28 @@ namespace Microsoft.AspNet.Mvc.ModelBinding ModelName = ModelBindingHelper.CreatePropertyModelName(parentBindingContext.ModelName, propertyName) }; - if (propertyBindingContext.ModelBinder.BindModel(propertyBindingContext)) + if (await propertyBindingContext.ModelBinder.BindModelAsync(propertyBindingContext)) { object untypedModel = propertyBindingContext.Model; - model = ModelBindingHelper.CastOrDefault(untypedModel); + var model = ModelBindingHelper.CastOrDefault(untypedModel); parentBindingContext.ValidationNode.ChildNodes.Add(propertyBindingContext.ValidationNode); - return true; + return new BindResult(true, model); } - model = default(TModel); - return false; + return new BindResult(false, default(TModel)); + } + + internal sealed class BindResult + { + public BindResult(bool success, TModel model) + { + Success = success; + Model = model; + } + + public bool Success { get; private set; } + + public TModel Model { get; private set; } } } } diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/MutableObjectModelBinder.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/MutableObjectModelBinder.cs index 452e897f14..e6c8106a2e 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/MutableObjectModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/MutableObjectModelBinder.cs @@ -4,18 +4,19 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding { public class MutableObjectModelBinder : IModelBinder { - public virtual bool BindModel(ModelBindingContext bindingContext) + public virtual async Task BindModelAsync(ModelBindingContext bindingContext) { ModelBindingHelper.ValidateBindingContext(bindingContext); if (!CanBindType(bindingContext.ModelType) || - !bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName)) + !await bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName)) { return false; } @@ -94,7 +95,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding ModelName = bindingContext.ModelName }; - bindingContext.ModelBinder.BindModel(dtoBindingContext); + bindingContext.ModelBinder.BindModelAsync(dtoBindingContext); return (ComplexModelDto)dtoBindingContext.Model; } diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/TypeConverterModelBinder.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/TypeConverterModelBinder.cs index db7311338c..f527a403b6 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/TypeConverterModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/TypeConverterModelBinder.cs @@ -1,15 +1,13 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; +using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding { public sealed class TypeConverterModelBinder : IModelBinder { - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "The exception is recorded to be acted upon later.")] - [SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.Web.Http.ValueProviders.ValueProviderResult.ConvertTo(System.Type)", Justification = "The ValueProviderResult already has the necessary context to perform a culture-aware conversion.")] - public bool BindModel(ModelBindingContext bindingContext) + public async Task BindModelAsync(ModelBindingContext bindingContext) { ModelBindingHelper.ValidateBindingContext(bindingContext); @@ -19,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return false; } - var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); + var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName); if (valueProviderResult == null) { return false; // no entry diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/TypeMatchModelBinder.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/TypeMatchModelBinder.cs index 23e5d71b1a..fe394e17a1 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/TypeMatchModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/Binders/TypeMatchModelBinder.cs @@ -1,13 +1,14 @@ using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding { public sealed class TypeMatchModelBinder : IModelBinder { - public bool BindModel(ModelBindingContext bindingContext) + public async Task BindModelAsync(ModelBindingContext bindingContext) { - ValueProviderResult valueProviderResult = GetCompatibleValueProviderResult(bindingContext); + ValueProviderResult valueProviderResult = await GetCompatibleValueProviderResult(bindingContext); if (valueProviderResult == null) { // conversion would have failed @@ -23,11 +24,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return true; } - internal static ValueProviderResult GetCompatibleValueProviderResult(ModelBindingContext bindingContext) + internal static async Task GetCompatibleValueProviderResult(ModelBindingContext bindingContext) { ModelBindingHelper.ValidateBindingContext(bindingContext); - ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); + var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName); if (valueProviderResult == null) { return null; // the value doesn't exist diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/CompositeValueProvider.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/CompositeValueProvider.cs index 07a61554c1..8c901768f0 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/CompositeValueProvider.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/CompositeValueProvider.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Threading.Tasks; namespace Microsoft.AspNet.Mvc.ModelBinding { @@ -19,11 +20,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding { } - public virtual bool ContainsPrefix(string prefix) + public virtual async Task ContainsPrefixAsync(string prefix) { for (int i = 0; i < Count; i++) { - if (this[i].ContainsPrefix(prefix)) + if (await this[i].ContainsPrefixAsync(prefix)) { return true; } @@ -31,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return false; } - public virtual ValueProviderResult GetValue(string key) + public virtual async Task GetValueAsync(string key) { // Performance-sensitive // Caching the count is faster for IList @@ -39,7 +40,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding for (int i = 0; i < itemCount; i++) { IValueProvider vp = Items[i]; - ValueProviderResult result = vp.GetValue(key); + ValueProviderResult result = await vp.GetValueAsync(key); if (result != null) { return result; diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/DictionaryBasedValueProvider.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/DictionaryBasedValueProvider.cs index 88c7eb5cf5..bb2392d5fe 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/DictionaryBasedValueProvider.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/DictionaryBasedValueProvider.cs @@ -1,6 +1,6 @@ - -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; +using System.Threading.Tasks; namespace Microsoft.AspNet.Mvc.ModelBinding { @@ -13,17 +13,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding _values = values; } - public bool ContainsPrefix(string key) + public Task ContainsPrefixAsync(string key) { - return _values.ContainsKey(key); + return Task.FromResult(_values.ContainsKey(key)); } - public ValueProviderResult GetValue([NotNull] string key) + public Task GetValueAsync([NotNull] string key) { object value; if (_values.TryGetValue(key, out value)) { - return new ValueProviderResult(value, value.ToString(), CultureInfo.InvariantCulture); + var result = new ValueProviderResult(value, value.ToString(), CultureInfo.InvariantCulture); + return Task.FromResult(result); } return null; diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/ElementalValueProvider.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/ElementalValueProvider.cs index b966e7d13c..1a4d04c576 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/ElementalValueProvider.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/ElementalValueProvider.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding @@ -20,16 +21,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public object RawValue { get; private set; } - public bool ContainsPrefix(string prefix) + public Task ContainsPrefixAsync(string prefix) { - return PrefixContainer.IsPrefixMatch(Name, prefix); + return Task.FromResult(PrefixContainer.IsPrefixMatch(Name, prefix)); } - public ValueProviderResult GetValue(string key) + public Task GetValueAsync(string key) { - return string.Equals(key, Name, StringComparison.OrdinalIgnoreCase) - ? new ValueProviderResult(RawValue, Convert.ToString(RawValue, Culture), Culture) - : null; + var result = string.Equals(key, Name, StringComparison.OrdinalIgnoreCase) ? + new ValueProviderResult(RawValue, Convert.ToString(RawValue, Culture), Culture) : + null; + return Task.FromResult(result); } } } diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/IValueProviders.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/IValueProviders.cs index 36a0a238fb..2f1b539c86 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/IValueProviders.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/IValueProviders.cs @@ -1,4 +1,5 @@ - +using System.Threading.Tasks; + namespace Microsoft.AspNet.Mvc.ModelBinding { /// @@ -11,13 +12,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// The prefix to search for. /// true if the collection contains the specified prefix; otherwise, false. - bool ContainsPrefix(string prefix); + Task ContainsPrefixAsync(string prefix); /// /// Retrieves a value object using the specified key. /// /// The key of the value object to retrieve. /// The value object for the specified key. If the exact key is not found, null. - ValueProviderResult GetValue(string key); + Task GetValueAsync(string key); } } diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/ReadableStringCollectionValueProvider.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/ReadableStringCollectionValueProvider.cs index 888600328e..6073427e9a 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/ReadableStringCollectionValueProvider.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/ReadableStringCollectionValueProvider.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Mvc.ModelBinding.Internal; @@ -46,9 +47,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding } } - public virtual bool ContainsPrefix(string prefix) + public virtual Task ContainsPrefixAsync(string prefix) { - return PrefixContainer.ContainsPrefix(prefix); + return Task.FromResult(PrefixContainer.ContainsPrefix(prefix)); } public virtual IDictionary GetKeysFromPrefix([NotNull] string prefix) @@ -56,21 +57,25 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return PrefixContainer.GetKeysFromPrefix(prefix); } - - public virtual ValueProviderResult GetValue([NotNull] string key) + public virtual Task GetValueAsync([NotNull] string key) { + ValueProviderResult result; var values = _values.GetValues(key); if (values == null) { - return null; + result = null; } else if (values.Count == 1) { var value = (string)values[0]; - return new ValueProviderResult(value, value, _culture); + result = new ValueProviderResult(value, value, _culture); + } + else + { + result = new ValueProviderResult(values, _values.Get(key), _culture); } - return new ValueProviderResult(values, _values.Get(key), _culture); + return Task.FromResult(result); } } } diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/ArrayModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/ArrayModelBinderTest.cs index ac02bf66e4..572590d2a8 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/ArrayModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/ArrayModelBinderTest.cs @@ -1,4 +1,5 @@ #if NET45 +using System.Threading.Tasks; using Moq; using Xunit; @@ -7,7 +8,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test public class ArrayModelBinderTest { [Fact] - public void BindModel() + public async Task BindModel() { // Arrange var valueProvider = new SimpleHttpValueProvider @@ -19,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new ArrayModelBinder(); // Act - bool retVal = binder.BindModel(bindingContext); + var retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.True(retVal); @@ -29,21 +30,21 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void GetBinder_ValueProviderDoesNotContainPrefix_ReturnsNull() + public async Task GetBinder_ValueProviderDoesNotContainPrefix_ReturnsNull() { // Arrange ModelBindingContext bindingContext = GetBindingContext(new SimpleHttpValueProvider()); var binder = new ArrayModelBinder(); // Act - bool bound = binder.BindModel(bindingContext); + var bound = await binder.BindModelAsync(bindingContext); // Assert Assert.False(bound); } [Fact] - public void GetBinder_ModelMetadataReturnsReadOnly_ReturnsNull() + public async Task GetBinder_ModelMetadataReturnsReadOnly_ReturnsNull() { // Arrange var valueProvider = new SimpleHttpValueProvider @@ -55,7 +56,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new ArrayModelBinder(); // Act - bool bound = binder.BindModel(bindingContext); + var bound = await binder.BindModelAsync(bindingContext); // Assert Assert.False(bound); @@ -65,10 +66,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { var mockIntBinder = new Mock(); mockIntBinder - .Setup(o => o.BindModel(It.IsAny())) - .Returns((ModelBindingContext mbc) => + .Setup(o => o.BindModelAsync(It.IsAny())) + .Returns(async (ModelBindingContext mbc) => { - var value = mbc.ValueProvider.GetValue(mbc.ModelName); + var value = await mbc.ValueProvider.GetValueAsync(mbc.ModelName); if (value != null) { mbc.Model = value.ConvertTo(mbc.ModelType); diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/CollectionModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/CollectionModelBinderTest.cs index 1751ea0d51..bc3e05f070 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/CollectionModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/CollectionModelBinderTest.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Threading.Tasks; #if NET45 using Moq; #endif @@ -12,7 +13,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { #if NET45 [Fact] - public void BindComplexCollectionFromIndexes_FiniteIndexes() + public async Task BindComplexCollectionFromIndexes_FiniteIndexes() { // Arrange var valueProvider = new SimpleHttpValueProvider @@ -24,7 +25,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new CollectionModelBinder(); // Act - var boundCollection = binder.BindComplexCollectionFromIndexes(bindingContext, new[] { "foo", "bar", "baz" }); + var boundCollection = await binder.BindComplexCollectionFromIndexes(bindingContext, new[] { "foo", "bar", "baz" }); // Assert Assert.Equal(new[] { 42, 0, 200 }, boundCollection.ToArray()); @@ -32,7 +33,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindComplexCollectionFromIndexes_InfiniteIndexes() + public async Task BindComplexCollectionFromIndexes_InfiniteIndexes() { // Arrange var valueProvider = new SimpleHttpValueProvider @@ -45,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new CollectionModelBinder(); // Act - var boundCollection = binder.BindComplexCollectionFromIndexes(bindingContext, indexNames: null); + var boundCollection = await binder.BindComplexCollectionFromIndexes(bindingContext, indexNames: null); // Assert Assert.Equal(new[] { 42, 100 }, boundCollection.ToArray()); @@ -53,7 +54,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindModel_ComplexCollection() + public async Task BindModel_ComplexCollection() { // Arrange var valueProvider = new SimpleHttpValueProvider @@ -67,14 +68,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new CollectionModelBinder(); // Act - bool retVal = binder.BindModel(bindingContext); + bool retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.Equal(new[] { 42, 100, 200 }, ((List)bindingContext.Model).ToArray()); } [Fact] - public void BindModel_SimpleCollection() + public async Task BindModel_SimpleCollection() { // Arrange var valueProvider = new SimpleHttpValueProvider @@ -85,7 +86,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new CollectionModelBinder(); // Act - bool retVal = binder.BindModel(bindingContext); + bool retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.True(retVal); @@ -94,13 +95,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test #endif [Fact] - public void BindSimpleCollection_RawValueIsEmptyCollection_ReturnsEmptyList() + public async Task BindSimpleCollection_RawValueIsEmptyCollection_ReturnsEmptyList() { // Arrange var binder = new CollectionModelBinder(); // Act - var boundCollection = binder.BindSimpleCollection(bindingContext: null, rawValue: new object[0], culture: null); + var boundCollection = await binder.BindSimpleCollection(bindingContext: null, rawValue: new object[0], culture: null); // Assert Assert.NotNull(boundCollection); @@ -108,13 +109,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindSimpleCollection_RawValueIsNull_ReturnsNull() + public async Task BindSimpleCollection_RawValueIsNull_ReturnsNull() { // Arrange var binder = new CollectionModelBinder(); // Act - var boundCollection = binder.BindSimpleCollection(bindingContext: null, rawValue: null, culture: null); + var boundCollection = await binder.BindSimpleCollection(bindingContext: null, rawValue: null, culture: null); // Assert Assert.Null(boundCollection); @@ -122,7 +123,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test #if NET45 [Fact] - public void BindSimpleCollection_SubBindingSucceeds() + public async Task BindSimpleCollection_SubBindingSucceeds() { // Arrange var culture = new CultureInfo("fr-FR"); @@ -130,18 +131,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test ModelValidationNode childValidationNode = null; Mock.Get(bindingContext.ModelBinder) - .Setup(o => o.BindModel(It.IsAny())) + .Setup(o => o.BindModelAsync(It.IsAny())) .Returns((ModelBindingContext mbc) => { Assert.Equal("someName", mbc.ModelName); childValidationNode = mbc.ValidationNode; mbc.Model = 42; - return true; + return Task.FromResult(true); }); var modelBinder = new CollectionModelBinder(); // Act - var boundCollection = modelBinder.BindSimpleCollection(bindingContext, new int[1], culture); + var boundCollection = await modelBinder.BindSimpleCollection(bindingContext, new int[1], culture); // Assert Assert.Equal(new[] { 42 }, boundCollection.ToArray()); @@ -166,10 +167,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { Mock mockIntBinder = new Mock(); mockIntBinder - .Setup(o => o.BindModel(It.IsAny())) - .Returns((ModelBindingContext mbc) => + .Setup(o => o.BindModelAsync(It.IsAny())) + .Returns(async (ModelBindingContext mbc) => { - var value = mbc.ValueProvider.GetValue(mbc.ModelName); + var value = await mbc.ValueProvider.GetValueAsync(mbc.ModelName); if (value != null) { mbc.Model = value.ConvertTo(mbc.ModelType); diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/CompositeModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/CompositeModelBinderTest.cs index 34145da86f..67e23ddf8d 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/CompositeModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/CompositeModelBinderTest.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNet.DependencyInjection; using Moq; using Xunit; @@ -12,7 +13,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test public class CompositeModelBinderTest { [Fact] - public void BindModel_SuccessfulBind_RunsValidationAndReturnsModel() + public async Task BindModel_SuccessfulBind_RunsValidationAndReturnsModel() { // Arrange var validationCalled = false; @@ -23,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(int)), ModelName = "someName", ModelState = new ModelStateDictionary(), - ValueProvider = new SimpleValueProvider + ValueProvider = new SimpleHttpValueProvider { { "someName", "dummyValue" } }, @@ -32,7 +33,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var mockIntBinder = new Mock(); mockIntBinder - .Setup(o => o.BindModel(It.IsAny())) + .Setup(o => o.BindModelAsync(It.IsAny())) .Returns( delegate(ModelBindingContext context) { @@ -42,13 +43,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test context.Model = 42; bindingContext.ValidationNode.Validating += delegate { validationCalled = true; }; - return true; + return Task.FromResult(true); }); var shimBinder = new CompositeModelBinder(mockIntBinder.Object); // Act - var isBound = shimBinder.BindModel(bindingContext); + var isBound = await shimBinder.BindModelAsync(bindingContext); // Assert Assert.True(isBound); @@ -59,7 +60,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindModel_SuccessfulBind_ComplexTypeFallback_RunsValidationAndReturnsModel() + public async Task BindModel_SuccessfulBind_ComplexTypeFallback_RunsValidationAndReturnsModel() { // Arrange var validationCalled = false; @@ -71,7 +72,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(List)), ModelName = "someName", ModelState = new ModelStateDictionary(), - ValueProvider = new SimpleValueProvider + ValueProvider = new SimpleHttpValueProvider { { "someOtherName", "dummyValue" } }, @@ -80,13 +81,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var mockIntBinder = new Mock(); mockIntBinder - .Setup(o => o.BindModel(It.IsAny())) + .Setup(o => o.BindModelAsync(It.IsAny())) .Returns( delegate(ModelBindingContext mbc) { - if (!String.IsNullOrEmpty(mbc.ModelName)) + if (!string.IsNullOrEmpty(mbc.ModelName)) { - return false; + return Task.FromResult(false); } Assert.Same(bindingContext.ModelMetadata, mbc.ModelMetadata); @@ -95,13 +96,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test mbc.Model = expectedModel; mbc.ValidationNode.Validating += delegate { validationCalled = true; }; - return true; + return Task.FromResult(true); }); IModelBinder shimBinder = new CompositeModelBinder(mockIntBinder.Object); // Act - bool isBound = shimBinder.BindModel(bindingContext); + var isBound = await shimBinder.BindModelAsync(bindingContext); // Assert Assert.True(isBound); @@ -111,12 +112,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindModel_UnsuccessfulBind_BinderFails_ReturnsNull() + public async Task BindModel_UnsuccessfulBind_BinderFails_ReturnsNull() { // Arrange var mockListBinder = new Mock(); - mockListBinder.Setup(o => o.BindModel(It.IsAny())) - .Returns(false) + mockListBinder.Setup(o => o.BindModelAsync(It.IsAny())) + .Returns(Task.FromResult(false)) .Verifiable(); var shimBinder = (IModelBinder)mockListBinder.Object; @@ -128,7 +129,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test }; // Act - var isBound = shimBinder.BindModel(bindingContext); + var isBound = await shimBinder.BindModelAsync(bindingContext); // Assert Assert.False(isBound); @@ -138,7 +139,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindModel_UnsuccessfulBind_SimpleTypeNoFallback_ReturnsNull() + public async Task BindModel_UnsuccessfulBind_SimpleTypeNoFallback_ReturnsNull() { // Arrange var innerBinder = Mock.Of(); @@ -152,7 +153,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test }; // Act - var isBound = shimBinder.BindModel(bindingContext); + var isBound = await shimBinder.BindModelAsync(bindingContext); // Assert Assert.False(isBound); @@ -160,12 +161,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindModel_WithDefaultBinders_BindsSimpleType() + public async Task BindModel_WithDefaultBinders_BindsSimpleType() { // Arrange var binder = CreateBinderWithDefaults(); - var valueProvider = new SimpleValueProvider + var valueProvider = new SimpleHttpValueProvider { { "firstName", "firstName-value"}, { "lastName", "lastName-value"} @@ -173,7 +174,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var bindingContext = CreateBindingContext(binder, valueProvider, typeof(SimplePropertiesModel)); // Act - var isBound = binder.BindModel(bindingContext); + var isBound = await binder.BindModelAsync(bindingContext); // Assert Assert.True(isBound); @@ -183,12 +184,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindModel_WithDefaultBinders_BindsComplexType() + public async Task BindModel_WithDefaultBinders_BindsComplexType() { // Arrange var binder = CreateBinderWithDefaults(); - var valueProvider = new SimpleValueProvider + var valueProvider = new SimpleHttpValueProvider { { "firstName", "firstName-value"}, { "lastName", "lastName-value"}, @@ -201,7 +202,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var bindingContext = CreateBindingContext(binder, valueProvider, typeof(Person)); // Act - var isBound = binder.BindModel(bindingContext); + var isBound = await binder.BindModelAsync(bindingContext); // Assert Assert.True(isBound); @@ -270,70 +271,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test public List Friends { get; set; } } - - private class SimpleValueProvider : Dictionary, IValueProvider - { - private readonly CultureInfo _culture; - - public SimpleValueProvider() - : this(null) - { - } - - public SimpleValueProvider(CultureInfo culture) - : base(StringComparer.OrdinalIgnoreCase) - { - _culture = culture ?? CultureInfo.InvariantCulture; - } - - // copied from ValueProviderUtil - public bool ContainsPrefix(string prefix) - { - foreach (string key in Keys) - { - if (key != null) - { - if (prefix.Length == 0) - { - return true; // shortcut - non-null key matches empty prefix - } - - if (key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) - { - if (key.Length == prefix.Length) - { - return true; // exact match - } - else - { - switch (key[prefix.Length]) - { - case '.': // known separator characters - case '[': - return true; - } - } - } - } - } - - return false; // nothing found - } - - public ValueProviderResult GetValue(string key) - { - object rawValue; - if (TryGetValue(key, out rawValue)) - { - return new ValueProviderResult(rawValue, Convert.ToString(rawValue, _culture), _culture); - } - else - { - // value not found - return null; - } - } - } } } #endif diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/DictionaryModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/DictionaryModelBinderTest.cs index c40bfc42a1..31b70902a2 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/DictionaryModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/DictionaryModelBinderTest.cs @@ -1,5 +1,6 @@ #if NET45 using System.Collections.Generic; +using System.Threading.Tasks; using Moq; using Xunit; @@ -8,7 +9,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test public class DictionaryModelBinderTest { [Fact] - public void BindModel() + public async Task BindModel() { // Arrange var metadataProvider = new EmptyModelMetadataProvider(); @@ -27,7 +28,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new DictionaryModelBinder(); // Act - bool retVal = binder.BindModel(bindingContext); + bool retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.True(retVal); @@ -43,10 +44,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { Mock mockKvpBinder = new Mock(); mockKvpBinder - .Setup(o => o.BindModel(It.IsAny())) - .Returns((ModelBindingContext mbc) => + .Setup(o => o.BindModelAsync(It.IsAny())) + .Returns(async (ModelBindingContext mbc) => { - var value = mbc.ValueProvider.GetValue(mbc.ModelName); + var value = await mbc.ValueProvider.GetValueAsync(mbc.ModelName); if (value != null) { mbc.Model = value.ConvertTo(mbc.ModelType); diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/KeyValuePairModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/KeyValuePairModelBinderTest.cs index 976bbd64dd..d007da8678 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/KeyValuePairModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/KeyValuePairModelBinderTest.cs @@ -1,6 +1,7 @@ #if NET45 using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Moq; using Xunit; @@ -9,7 +10,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test public class KeyValuePairModelBinderTest { [Fact] - public void BindModel_MissingKey_ReturnsFalse() + public async Task BindModel_MissingKey_ReturnsFalse() { // Arrange var valueProvider = new SimpleHttpValueProvider(); @@ -17,7 +18,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new KeyValuePairModelBinder(); // Act - bool retVal = binder.BindModel(bindingContext); + bool retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.False(retVal); @@ -26,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindModel_MissingValue_ReturnsTrue() + public async Task BindModel_MissingValue_ReturnsTrue() { // Arrange var valueProvider = new SimpleHttpValueProvider(); @@ -34,7 +35,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new KeyValuePairModelBinder(); // Act - bool retVal = binder.BindModel(bindingContext); + bool retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.True(retVal); @@ -43,7 +44,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindModel_SubBindingSucceeds() + public async Task BindModel_SubBindingSucceeds() { // Arrange var innerBinder = new CompositeModelBinder(CreateStringBinder(), CreateIntBinder()); @@ -53,7 +54,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new KeyValuePairModelBinder(); // Act - var retVal = binder.BindModel(bindingContext); + var retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.True(retVal); @@ -62,34 +63,33 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void TryBindStrongModel_BinderExists_BinderReturnsCorrectlyTypedObject_ReturnsTrue() + public async Task TryBindStrongModel_BinderExists_BinderReturnsCorrectlyTypedObject_ReturnsTrue() { // Arrange ModelBindingContext bindingContext = GetBindingContext(new SimpleHttpValueProvider()); var binder = new KeyValuePairModelBinder(); // Act - int model; - var retVal = binder.TryBindStrongModel(bindingContext, "key", out model); + var retVal = await binder.TryBindStrongModel(bindingContext, "key"); // Assert - Assert.True(retVal); - Assert.Equal(42, model); + Assert.True(retVal.Success); + Assert.Equal(42, retVal.Model); Assert.Single(bindingContext.ValidationNode.ChildNodes); Assert.Empty(bindingContext.ModelState); } [Fact] - public void TryBindStrongModel_BinderExists_BinderReturnsIncorrectlyTypedObject_ReturnsTrue() + public async Task TryBindStrongModel_BinderExists_BinderReturnsIncorrectlyTypedObject_ReturnsTrue() { // Arrange var innerBinder = new Mock(); innerBinder - .Setup(o => o.BindModel(It.IsAny())) + .Setup(o => o.BindModelAsync(It.IsAny())) .Returns((ModelBindingContext mbc) => { Assert.Equal("someName.key", mbc.ModelName); - return true; + return Task.FromResult(true); }); var bindingContext = GetBindingContext(new SimpleHttpValueProvider(), innerBinder.Object); @@ -97,12 +97,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new KeyValuePairModelBinder(); // Act - int model; - var retVal = binder.TryBindStrongModel(bindingContext, "key", out model); + var retVal = await binder.TryBindStrongModel(bindingContext, "key"); // Assert - Assert.True(retVal); - Assert.Equal(default(int), model); + Assert.True(retVal.Success); + Assert.Equal(default(int), retVal.Model); Assert.Single(bindingContext.ValidationNode.ChildNodes); Assert.Empty(bindingContext.ModelState); } @@ -126,15 +125,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { var mockIntBinder = new Mock(); mockIntBinder - .Setup(o => o.BindModel(It.IsAny())) + .Setup(o => o.BindModelAsync(It.IsAny())) .Returns((ModelBindingContext mbc) => { if (mbc.ModelType == typeof(int)) { mbc.Model = 42; - return true; + return Task.FromResult(true); } - return false; + return Task.FromResult(false); }); return mockIntBinder.Object; } @@ -143,15 +142,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { var mockStringBinder = new Mock(); mockStringBinder - .Setup(o => o.BindModel(It.IsAny())) + .Setup(o => o.BindModelAsync(It.IsAny())) .Returns((ModelBindingContext mbc) => { if (mbc.ModelType == typeof(string)) { mbc.Model = "some-value"; - return true; + return Task.FromResult(true); } - return false; + return Task.FromResult(false); }); return mockStringBinder.Object; } diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/MutableObjectModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/MutableObjectModelBinderTest.cs index b8082e2e47..dfa0b7eea7 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/MutableObjectModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/MutableObjectModelBinderTest.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNet.Testing; using Moq; using Xunit; @@ -13,12 +14,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public class MutableObjectModelBinderTest { [Fact] - public void BindModel_InitsInstance() + public async Task BindModel_InitsInstance() { // Arrange var mockValueProvider = new Mock(); - mockValueProvider.Setup(o => o.ContainsPrefix(It.IsAny())) - .Returns(true); + mockValueProvider.Setup(o => o.ContainsPrefixAsync(It.IsAny())) + .Returns(Task.FromResult(true)); var mockDtoBinder = new Mock(); var bindingContext = new ModelBindingContext @@ -32,11 +33,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding }; mockDtoBinder - .Setup(o => o.BindModel(It.IsAny())) + .Setup(o => o.BindModelAsync(It.IsAny())) .Returns((ModelBindingContext mbc) => { // just return the DTO unchanged - return true; + return Task.FromResult(true); }); var testableBinder = new Mock { CallBase = true }; @@ -45,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding .Returns(new ModelMetadata[0]).Verifiable(); // Act - var retValue = testableBinder.Object.BindModel(bindingContext); + var retValue = await testableBinder.Object.BindModelAsync(bindingContext); // Assert Assert.True(retValue); diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/TypeConverterModelBinderTest.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/TypeConverterModelBinderTest.cs index f44d0bccd5..50040db328 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/TypeConverterModelBinderTest.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Binders/TypeConverterModelBinderTest.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel; using System.Globalization; +using System.Threading.Tasks; using Xunit; namespace Microsoft.AspNet.Mvc.ModelBinding.Test @@ -11,7 +12,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test [InlineData(typeof(object))] [InlineData(typeof(Calendar))] [InlineData(typeof(TestClass))] - public void BindModel_ReturnsFalse_IfTypeCannotBeConverted(Type destinationType) + public async Task BindModel_ReturnsFalse_IfTypeCannotBeConverted(Type destinationType) { // Arrange var bindingContext = GetBindingContext(destinationType); @@ -23,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new TypeConverterModelBinder(); // Act - var retVal = binder.BindModel(bindingContext); + var retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.False(retVal); @@ -36,7 +37,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test [InlineData(typeof(DateTimeOffset))] [InlineData(typeof(double))] [InlineData(typeof(DayOfWeek))] - public void BindModel_ReturnsTrue_IfTypeCanBeConverted(Type destinationType) + public async Task BindModel_ReturnsTrue_IfTypeCanBeConverted(Type destinationType) { // Arrange var bindingContext = GetBindingContext(destinationType); @@ -48,14 +49,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var binder = new TypeConverterModelBinder(); // Act - var retVal = binder.BindModel(bindingContext); + var retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.True(retVal); } [Fact] - public void BindModel_Error_FormatExceptionsTurnedIntoStringsInModelState() + public async Task BindModel_Error_FormatExceptionsTurnedIntoStringsInModelState() { // Arrange ModelBindingContext bindingContext = GetBindingContext(typeof(int)); @@ -67,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test TypeConverterModelBinder binder = new TypeConverterModelBinder(); // Act - bool retVal = binder.BindModel(bindingContext); + bool retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.True(retVal); @@ -77,7 +78,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindModel_NullValueProviderResult_ReturnsFalse() + public async Task BindModel_NullValueProviderResult_ReturnsFalse() { // Arrange ModelBindingContext bindingContext = GetBindingContext(typeof(int)); @@ -85,7 +86,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test TypeConverterModelBinder binder = new TypeConverterModelBinder(); // Act - bool retVal = binder.BindModel(bindingContext); + bool retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.False(retVal, "BindModel should have returned null."); @@ -93,7 +94,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindModel_ValidValueProviderResult_ConvertEmptyStringsToNull() + public async Task BindModel_ValidValueProviderResult_ConvertEmptyStringsToNull() { // Arrange ModelBindingContext bindingContext = GetBindingContext(typeof(string)); @@ -105,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test TypeConverterModelBinder binder = new TypeConverterModelBinder(); // Act - bool retVal = binder.BindModel(bindingContext); + bool retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.True(retVal); @@ -114,7 +115,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void BindModel_ValidValueProviderResult_ReturnsModel() + public async Task BindModel_ValidValueProviderResult_ReturnsModel() { // Arrange ModelBindingContext bindingContext = GetBindingContext(typeof(int)); @@ -126,7 +127,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test TypeConverterModelBinder binder = new TypeConverterModelBinder(); // Act - bool retVal = binder.BindModel(bindingContext); + bool retVal = await binder.BindModelAsync(bindingContext); // Assert Assert.True(retVal); diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Utils/SimpleHttpValueProvider.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Utils/SimpleHttpValueProvider.cs index 756d05df10..98f64f24cd 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Utils/SimpleHttpValueProvider.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/Utils/SimpleHttpValueProvider.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Threading.Tasks; namespace Microsoft.AspNet.Mvc.ModelBinding.Test { @@ -20,7 +21,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } // copied from ValueProviderUtil - public bool ContainsPrefix(string prefix) + public Task ContainsPrefixAsync(string prefix) { foreach (string key in Keys) { @@ -28,14 +29,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { if (prefix.Length == 0) { - return true; // shortcut - non-null key matches empty prefix + return Task.FromResult(true); // shortcut - non-null key matches empty prefix } if (key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { if (key.Length == prefix.Length) { - return true; // exact match + return Task.FromResult(true); // exact match } else { @@ -43,28 +44,26 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test { case '.': // known separator characters case '[': - return true; + return Task.FromResult(true); } } } } } - return false; // nothing found + return Task.FromResult(false); // nothing found } - public ValueProviderResult GetValue(string key) + public Task GetValueAsync(string key) { + ValueProviderResult result = null; object rawValue; if (TryGetValue(key, out rawValue)) { - return new ValueProviderResult(rawValue, Convert.ToString(rawValue, _culture), _culture); - } - else - { - // value not found - return null; + result = new ValueProviderResult(rawValue, Convert.ToString(rawValue, _culture), _culture); } + + return Task.FromResult(result); } } } diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/ValueProviders/ReadableStringCollectionValueProviderTests.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/ValueProviders/ReadableStringCollectionValueProviderTests.cs index 6a3cc102e9..a3e632a7d7 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/ValueProviders/ReadableStringCollectionValueProviderTests.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/ValueProviders/ReadableStringCollectionValueProviderTests.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.PipelineCore.Collections; using Xunit; @@ -20,52 +21,52 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test [Fact] - public void ContainsPrefix_WithEmptyCollection_ReturnsFalseForEmptyPrefix() + public async Task ContainsPrefix_WithEmptyCollection_ReturnsFalseForEmptyPrefix() { // Arrange var backingStore = new ReadableStringCollection(new Dictionary()); var valueProvider = new ReadableStringCollectionValueProvider(backingStore, null); // Act - bool result = valueProvider.ContainsPrefix(""); + var result = await valueProvider.ContainsPrefixAsync(""); // Assert Assert.False(result); } [Fact] - public void ContainsPrefix_WithNonEmptyCollection_ReturnsTrueForEmptyPrefix() + public async Task ContainsPrefix_WithNonEmptyCollection_ReturnsTrueForEmptyPrefix() { // Arrange var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null); // Act - bool result = valueProvider.ContainsPrefix(""); + var result = await valueProvider.ContainsPrefixAsync(""); // Assert Assert.True(result); } [Fact] - public void ContainsPrefix_WithNonEmptyCollection_ReturnsTrueForKnownPrefixes() + public async Task ContainsPrefix_WithNonEmptyCollection_ReturnsTrueForKnownPrefixes() { // Arrange var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null); // Act & Assert - Assert.True(valueProvider.ContainsPrefix("foo")); - Assert.True(valueProvider.ContainsPrefix("bar")); - Assert.True(valueProvider.ContainsPrefix("bar.baz")); + Assert.True(await valueProvider.ContainsPrefixAsync("foo")); + Assert.True(await valueProvider.ContainsPrefixAsync("bar")); + Assert.True(await valueProvider.ContainsPrefixAsync("bar.baz")); } [Fact] - public void ContainsPrefix_WithNonEmptyCollection_ReturnsFalseForUnknownPrefix() + public async Task ContainsPrefix_WithNonEmptyCollection_ReturnsFalseForUnknownPrefix() { // Arrange var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null); // Act - bool result = valueProvider.ContainsPrefix("biff"); + var result = await valueProvider.ContainsPrefixAsync("biff"); // Assert Assert.False(result); @@ -115,14 +116,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void GetValue_SingleValue() + public async Task GetValue_SingleValue() { // Arrange var culture = new CultureInfo("fr-FR"); var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, culture); // Act - ValueProviderResult vpResult = valueProvider.GetValue("bar.baz"); + var vpResult = await valueProvider.GetValueAsync("bar.baz"); // Assert Assert.NotNull(vpResult); @@ -132,14 +133,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void GetValue_MultiValue() + public async Task GetValue_MultiValue() { // Arrange var culture = new CultureInfo("fr-FR"); var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, culture); // Act - ValueProviderResult vpResult = valueProvider.GetValue("foo"); + var vpResult = await valueProvider.GetValueAsync("foo"); // Assert Assert.NotNull(vpResult); @@ -153,7 +154,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test //[Theory] //[InlineData("null_value")] //[InlineData("prefix.null_value")] - //public void GetValue_NullValue(string key) + //public async Task GetValue_NullValue(string key) //{ // // Arrange // var culture = new CultureInfo("fr-FR"); @@ -170,7 +171,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test //} [Fact] - public void GetValue_NullMultipleValue() + public async Task GetValue_NullMultipleValue() { // Arrange var backingStore = new ReadableStringCollection( @@ -182,7 +183,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test var valueProvider = new ReadableStringCollectionValueProvider(backingStore, culture); // Act - ValueProviderResult vpResult = valueProvider.GetValue("key"); + var vpResult = await valueProvider.GetValueAsync("key"); // Assert Assert.Equal(new[] { null, null, "value" }, vpResult.RawValue as IEnumerable); @@ -190,13 +191,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } [Fact] - public void GetValue_ReturnsNullIfKeyNotFound() + public async Task GetValue_ReturnsNullIfKeyNotFound() { // Arrange var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null); // Act - ValueProviderResult vpResult = valueProvider.GetValue("bar"); + var vpResult = await valueProvider.GetValueAsync("bar"); // Assert Assert.Null(vpResult);