From 756f8be49c9547db0520e4f32f739d3cbd839299 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 20 Oct 2014 18:25:45 -0700 Subject: [PATCH] CompositeValueProvider.GetKeysFromPrefixAsync throws null if provider is not an IEnumerableValueProvider Fixes #1419 --- .../ValueProviders/CompositeValueProvider.cs | 34 ++++++++++----- .../CompositeValueProviderTests.cs | 43 ++++++++++++++++++- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/CompositeValueProvider.cs b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/CompositeValueProvider.cs index 375d30a69f..059d682bc0 100644 --- a/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/CompositeValueProvider.cs +++ b/src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/CompositeValueProvider.cs @@ -9,18 +9,30 @@ using System.Threading.Tasks; namespace Microsoft.AspNet.Mvc.ModelBinding { + /// + /// Represents a whose values come from a collection of s. + /// public class CompositeValueProvider : Collection, IEnumerableValueProvider, IMetadataAwareValueProvider { + /// + /// Initializes a new instance of . + /// public CompositeValueProvider() : base() { } + /// + /// Initializes a new instance of . + /// + /// The sequence of to add to this instance of + /// . public CompositeValueProvider(IEnumerable valueProviders) : base(valueProviders.ToList()) { } + /// public virtual async Task ContainsPrefixAsync(string prefix) { for (var i = 0; i < Count; i++) @@ -33,6 +45,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return false; } + /// public virtual async Task GetValueAsync(string key) { // Performance-sensitive @@ -50,36 +63,37 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return null; } + /// public virtual async Task> GetKeysFromPrefixAsync(string prefix) { foreach (var valueProvider in this) { - var result = await GetKeysFromPrefixFromProvider(valueProvider, prefix); - if (result != null && result.Count > 0) + var enumeratedProvider = valueProvider as IEnumerableValueProvider; + if (enumeratedProvider != null) { - return result; + var result = await enumeratedProvider.GetKeysFromPrefixAsync(prefix); + if (result != null && result.Count > 0) + { + return result; + } } } return new Dictionary(StringComparer.OrdinalIgnoreCase); } - private static Task> GetKeysFromPrefixFromProvider(IValueProvider provider, - string prefix) - { - var enumeratedProvider = provider as IEnumerableValueProvider; - return (enumeratedProvider != null) ? enumeratedProvider.GetKeysFromPrefixAsync(prefix) : null; - } - + /// protected override void InsertItem(int index, [NotNull] IValueProvider item) { base.InsertItem(index, item); } + /// protected override void SetItem(int index, [NotNull] IValueProvider item) { base.SetItem(index, item); } + /// public IValueProvider Filter(IValueProviderMetadata valueBinderMetadata) { var filteredValueProviders = new List(); diff --git a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/ValueProviders/CompositeValueProviderTests.cs b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/ValueProviders/CompositeValueProviderTests.cs index ceddc0d88e..f59b3f2cef 100644 --- a/test/Microsoft.AspNet.Mvc.ModelBinding.Test/ValueProviders/CompositeValueProviderTests.cs +++ b/test/Microsoft.AspNet.Mvc.ModelBinding.Test/ValueProviders/CompositeValueProviderTests.cs @@ -5,10 +5,11 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Moq; using Xunit; -namespace Microsoft.AspNet.Mvc.ModelBinding.Test +namespace Microsoft.AspNet.Mvc.ModelBinding { public class CompositeValueProviderTests { @@ -21,6 +22,46 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test } } + [Fact] + public async Task GetKeysFromPrefixAsync_ReturnsResultFromFirstValueProviderThatReturnsValues() + { + // Arrange + var provider1 = Mock.Of(); + var dictionary = new Dictionary(StringComparer.Ordinal) + { + { "prefix-test", "some-value" }, + }; + var provider2 = new Mock(); + provider2.Setup(p => p.GetKeysFromPrefixAsync("prefix")) + .Returns(Task.FromResult>(dictionary)) + .Verifiable(); + var provider = new CompositeValueProvider(new[] { provider1, provider2.Object }); + + // Act + var values = await provider.GetKeysFromPrefixAsync("prefix"); + + // Assert + var result = Assert.Single(values); + Assert.Equal("prefix-test", result.Key); + Assert.Equal("some-value", result.Value); + provider2.Verify(); + } + + [Fact] + public async Task GetKeysFromPrefixAsync_ReturnsEmptyDictionaryIfNoValueProviderReturnsValues() + { + // Arrange + var provider1 = Mock.Of(); + var provider2 = Mock.Of(); + var provider = new CompositeValueProvider(new[] { provider1, provider2 }); + + // Act + var values = await provider.GetKeysFromPrefixAsync("prefix"); + + // Assert + Assert.Empty(values); + } + [Theory] [MemberData(nameof(RegisteredAsMetadataClasses))] public void FilterReturnsItself_ForAnyClassRegisteredAsGenericParam(IValueProviderMetadata metadata)