// Copyright (c) .NET Foundation. 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.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; namespace Microsoft.AspNetCore.Mvc.ModelBinding { /// /// Represents a whose values come from a collection of s. /// public class CompositeValueProvider : Collection, IEnumerableValueProvider, IBindingSourceValueProvider { /// /// Initializes a new instance of . /// public CompositeValueProvider() : base() { } /// /// Initializes a new instance of . /// /// The sequence of to add to this instance of /// . public CompositeValueProvider(IList valueProviders) : base(valueProviders) { } /// /// Asynchronously creates a using the provided /// . /// /// The associated with the current request. /// /// A which, when completed, asynchronously returns a /// . /// public static async Task CreateAsync(ControllerContext controllerContext) { if (controllerContext == null) { throw new ArgumentNullException(nameof(controllerContext)); } var factories = controllerContext.ValueProviderFactories; return await CreateAsync(controllerContext, factories); } /// /// Asynchronously creates a using the provided /// . /// /// The associated with the current request. /// The to be applied to the context. /// /// A which, when completed, asynchronously returns a /// . /// public static async Task CreateAsync( ActionContext actionContext, IList factories) { var valueProviderFactoryContext = new ValueProviderFactoryContext(actionContext); for (var i = 0; i < factories.Count; i++) { var factory = factories[i]; await factory.CreateValueProviderAsync(valueProviderFactoryContext); } return new CompositeValueProvider(valueProviderFactoryContext.ValueProviders); } /// public virtual bool ContainsPrefix(string prefix) { for (var i = 0; i < Count; i++) { if (this[i].ContainsPrefix(prefix)) { return true; } } return false; } /// public virtual ValueProviderResult GetValue(string key) { // Performance-sensitive // Caching the count is faster for IList var itemCount = Items.Count; for (var i = 0; i < itemCount; i++) { var valueProvider = Items[i]; var result = valueProvider.GetValue(key); if (result != ValueProviderResult.None) { return result; } } return ValueProviderResult.None; } /// public virtual IDictionary GetKeysFromPrefix(string prefix) { foreach (var valueProvider in this) { var enumeratedProvider = valueProvider as IEnumerableValueProvider; if (enumeratedProvider != null) { var result = enumeratedProvider.GetKeysFromPrefix(prefix); if (result != null && result.Count > 0) { return result; } } } return new Dictionary(StringComparer.OrdinalIgnoreCase); } /// protected override void InsertItem(int index, IValueProvider item) { if (item == null) { throw new ArgumentNullException(nameof(item)); } base.InsertItem(index, item); } /// protected override void SetItem(int index, IValueProvider item) { if (item == null) { throw new ArgumentNullException(nameof(item)); } base.SetItem(index, item); } /// public IValueProvider Filter(BindingSource bindingSource) { if (bindingSource == null) { throw new ArgumentNullException(nameof(bindingSource)); } var filteredValueProviders = new List(); foreach (var valueProvider in this.OfType()) { var result = valueProvider.Filter(bindingSource); if (result != null) { filteredValueProviders.Add(result); } } if (filteredValueProviders.Count == 0) { // Do not create an empty CompositeValueProvider. return null; } if (filteredValueProviders.Count == Count) { // No need for a new CompositeValueProvider. return this; } return new CompositeValueProvider(filteredValueProviders); } } }