CompositeValueProvider.GetKeysFromPrefixAsync throws null if provider is not an

IEnumerableValueProvider

Fixes #1419
This commit is contained in:
Pranav K 2014-10-20 18:25:45 -07:00
parent 26cd8df577
commit 756f8be49c
2 changed files with 66 additions and 11 deletions

View File

@ -9,18 +9,30 @@ using System.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
/// <summary>
/// Represents a <see cref="IValueProvider"/> whose values come from a collection of <see cref="IValueProvider"/>s.
/// </summary>
public class CompositeValueProvider : Collection<IValueProvider>, IEnumerableValueProvider, IMetadataAwareValueProvider
{
/// <summary>
/// Initializes a new instance of <see cref="CompositeValueProvider"/>.
/// </summary>
public CompositeValueProvider()
: base()
{
}
/// <summary>
/// Initializes a new instance of <see cref="CompositeValueProvider"/>.
/// </summary>
/// <param name="valueProviders">The sequence of <see cref="IValueProvider"/> to add to this instance of
/// <see cref="CompositeValueProvider"/>.</param>
public CompositeValueProvider(IEnumerable<IValueProvider> valueProviders)
: base(valueProviders.ToList())
{
}
/// <inheritdoc />
public virtual async Task<bool> ContainsPrefixAsync(string prefix)
{
for (var i = 0; i < Count; i++)
@ -33,6 +45,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return false;
}
/// <inheritdoc />
public virtual async Task<ValueProviderResult> GetValueAsync(string key)
{
// Performance-sensitive
@ -50,36 +63,37 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return null;
}
/// <inheritdoc />
public virtual async Task<IDictionary<string, string>> 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<string, string>(StringComparer.OrdinalIgnoreCase);
}
private static Task<IDictionary<string, string>> GetKeysFromPrefixFromProvider(IValueProvider provider,
string prefix)
{
var enumeratedProvider = provider as IEnumerableValueProvider;
return (enumeratedProvider != null) ? enumeratedProvider.GetKeysFromPrefixAsync(prefix) : null;
}
/// <inheritdoc />
protected override void InsertItem(int index, [NotNull] IValueProvider item)
{
base.InsertItem(index, item);
}
/// <inheritdoc />
protected override void SetItem(int index, [NotNull] IValueProvider item)
{
base.SetItem(index, item);
}
/// <inheritdoc />
public IValueProvider Filter(IValueProviderMetadata valueBinderMetadata)
{
var filteredValueProviders = new List<IValueProvider>();

View File

@ -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<IValueProvider>();
var dictionary = new Dictionary<string, string>(StringComparer.Ordinal)
{
{ "prefix-test", "some-value" },
};
var provider2 = new Mock<IEnumerableValueProvider>();
provider2.Setup(p => p.GetKeysFromPrefixAsync("prefix"))
.Returns(Task.FromResult<IDictionary<string, string>>(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<IValueProvider>();
var provider2 = Mock.Of<IValueProvider>();
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)