// 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.Diagnostics;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
///
/// An adapter for data stored in an .
///
public class ReadableStringCollectionValueProvider : BindingSourceValueProvider, IEnumerableValueProvider
{
private readonly CultureInfo _culture;
private readonly Func> _valuesFactory;
private PrefixContainer _prefixContainer;
private IReadableStringCollection _values;
///
/// Creates a provider for wrapping an existing set of key value pairs.
///
/// The for the data.
/// The key value pairs to wrap.
/// The culture to return with ValueProviderResult instances.
public ReadableStringCollectionValueProvider(
[NotNull] BindingSource bindingSource,
[NotNull] IReadableStringCollection values,
CultureInfo culture)
: base(bindingSource)
{
_values = values;
_culture = culture;
}
///
/// Creates a provider for wrapping an
/// existing set of key value pairs provided by the delegate.
///
/// The for the data.
/// The delegate that provides the key value pairs to wrap.
/// The culture to return with ValueProviderResult instances.
public ReadableStringCollectionValueProvider(
[NotNull] BindingSource bindingSource,
[NotNull] Func> valuesFactory,
CultureInfo culture)
: base(bindingSource)
{
_valuesFactory = valuesFactory;
_culture = culture;
}
public CultureInfo Culture
{
get
{
return _culture;
}
}
///
public override async Task ContainsPrefixAsync(string prefix)
{
var prefixContainer = await GetPrefixContainerAsync();
return prefixContainer.ContainsPrefix(prefix);
}
///
public virtual async Task> GetKeysFromPrefixAsync([NotNull] string prefix)
{
var prefixContainer = await GetPrefixContainerAsync();
return prefixContainer.GetKeysFromPrefix(prefix);
}
///
public override async Task GetValueAsync([NotNull] string key)
{
var collection = await GetValueCollectionAsync();
var values = collection.GetValues(key);
ValueProviderResult result;
if (values == null)
{
result = null;
}
else if (values.Count == 1)
{
var value = (string)values[0];
result = new ValueProviderResult(value, value, _culture);
}
else
{
result = new ValueProviderResult(values, _values.Get(key), _culture);
}
return result;
}
private async Task GetValueCollectionAsync()
{
if (_values == null)
{
Debug.Assert(_valuesFactory != null);
_values = await _valuesFactory();
}
return _values;
}
private async Task GetPrefixContainerAsync()
{
if (_prefixContainer == null)
{
// Initialization race is OK providing data remains read-only and object identity is not significant
var collection = await GetValueCollectionAsync();
_prefixContainer = new PrefixContainer(collection.Keys);
}
return _prefixContainer;
}
}
}