Example #1
0
        // 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[].
        // Internal for testing.
        internal async Task <CollectionResult> BindSimpleCollection(
            ModelBindingContext bindingContext,
            ValueProviderResult values)
        {
            var boundCollection = new List <TElement>();

            var elementMetadata = bindingContext.ModelMetadata.ElementMetadata;

            foreach (var value in values)
            {
                bindingContext.ValueProvider = new CompositeValueProvider
                {
                    // our temporary provider goes at the front of the list
                    new ElementalValueProvider(bindingContext.ModelName, value, values.Culture),
                    bindingContext.ValueProvider
                };

                // Enter new scope to change ModelMetadata and isolate element binding operations.
                using (bindingContext.EnterNestedScope(
                           elementMetadata,
                           fieldName: bindingContext.FieldName,
                           modelName: bindingContext.ModelName,
                           model: null))
                {
                    await ElementBinder.BindModelAsync(bindingContext);

                    if (bindingContext.Result.IsModelSet)
                    {
                        var boundValue = bindingContext.Result.Model;
                        boundCollection.Add(CastOrDefault <TElement>(boundValue));
                    }
                }
            }

            return(new CollectionResult
            {
                Model = boundCollection
            });
        }
Example #2
0
        // Internal for testing.
        internal async Task <CollectionResult> BindComplexCollectionFromIndexes(
            ModelBindingContext bindingContext,
            IEnumerable <string> indexNames)
        {
            bool indexNamesIsFinite;

            if (indexNames != null)
            {
                indexNamesIsFinite = true;
            }
            else
            {
                indexNamesIsFinite = false;
                indexNames         = Enumerable.Range(0, int.MaxValue)
                                     .Select(i => i.ToString(CultureInfo.InvariantCulture));
            }

            var elementMetadata = bindingContext.ModelMetadata.ElementMetadata;

            var boundCollection = new List <TElement>();

            foreach (var indexName in indexNames)
            {
                var fullChildName = ModelNames.CreateIndexModelName(bindingContext.ModelName, indexName);

                ModelBindingResult?result;
                using (bindingContext.EnterNestedScope(
                           elementMetadata,
                           fieldName: indexName,
                           modelName: fullChildName,
                           model: null))
                {
                    await ElementBinder.BindModelAsync(bindingContext);

                    result = bindingContext.Result;
                }

                var    didBind    = false;
                object boundValue = null;
                if (result != null && result.Value.IsModelSet)
                {
                    didBind    = true;
                    boundValue = result.Value.Model;
                }

                // infinite size collection stops on first bind failure
                if (!didBind && !indexNamesIsFinite)
                {
                    break;
                }

                boundCollection.Add(CastOrDefault <TElement>(boundValue));
            }

            return(new CollectionResult
            {
                Model = boundCollection,

                // If we're working with a fixed set of indexes then this is the format like:
                //
                //  ?parameter.index=zero&parameter.index=one&parameter.index=two&parameter[zero]=0&parameter[one]=1&parameter[two]=2...
                //
                // We need to provide this data to the validation system so it can 'replay' the keys.
                // But we can't just set ValidationState here, because it needs the 'real' model.
                ValidationStrategy = indexNamesIsFinite ?
                                     new ExplicitIndexCollectionValidationStrategy(indexNames) :
                                     null,
            });
        }
    internal async Task <CollectionResult> BindComplexCollectionFromIndexes(
        ModelBindingContext bindingContext,
        IEnumerable <string>?indexNames)
    {
        bool indexNamesIsFinite;

        if (indexNames != null)
        {
            indexNamesIsFinite = true;
        }
        else
        {
            indexNamesIsFinite = false;
            var limit = _maxModelBindingCollectionSize == int.MaxValue ?
                        int.MaxValue :
                        _maxModelBindingCollectionSize + 1;
            indexNames = Enumerable
                         .Range(0, limit)
                         .Select(i => i.ToString(CultureInfo.InvariantCulture));
        }

        var elementMetadata = bindingContext.ModelMetadata.ElementMetadata !;

        var boundCollection = new List <TElement?>();

        foreach (var indexName in indexNames)
        {
            var fullChildName = ModelNames.CreateIndexModelName(bindingContext.ModelName, indexName);

            ModelBindingResult?result;
            using (bindingContext.EnterNestedScope(
                       elementMetadata,
                       fieldName: indexName,
                       modelName: fullChildName,
                       model: null))
            {
                await ElementBinder.BindModelAsync(bindingContext);

                result = bindingContext.Result;
            }

            var    didBind    = false;
            object?boundValue = null;
            if (result != null && result.Value.IsModelSet)
            {
                didBind    = true;
                boundValue = result.Value.Model;
            }

            // infinite size collection stops on first bind failure
            if (!didBind && !indexNamesIsFinite)
            {
                break;
            }

            boundCollection.Add(ModelBindingHelper.CastOrDefault <TElement>(boundValue));
        }

        // Did the collection grow larger than the limit?
        if (boundCollection.Count > _maxModelBindingCollectionSize)
        {
            // Look for a non-empty name. Both ModelName and OriginalModelName may be empty at the top level.
            var name = string.IsNullOrEmpty(bindingContext.ModelName) ?
                       (string.IsNullOrEmpty(bindingContext.OriginalModelName) &&
                        bindingContext.ModelMetadata.MetadataKind != ModelMetadataKind.Type ?
                        bindingContext.ModelMetadata.Name :
                        bindingContext.OriginalModelName) : // This name may unfortunately be empty.
                       bindingContext.ModelName;

            throw new InvalidOperationException(Resources.FormatModelBinding_ExceededMaxModelBindingCollectionSize(
                                                    name,
                                                    nameof(MvcOptions),
                                                    nameof(MvcOptions.MaxModelBindingCollectionSize),
                                                    _maxModelBindingCollectionSize,
                                                    bindingContext.ModelMetadata.ElementType));
        }

        return(new CollectionResult(boundCollection)
        {
            // If we're working with a fixed set of indexes then this is the format like:
            //
            //  ?parameter.index=zero&parameter.index=one&parameter.index=two&parameter[zero]=0&parameter[one]=1&parameter[two]=2...
            //
            // We need to provide this data to the validation system so it can 'replay' the keys.
            // But we can't just set ValidationState here, because it needs the 'real' model.
            ValidationStrategy = indexNamesIsFinite ?
                                 new ExplicitIndexCollectionValidationStrategy(indexNames) :
                                 null,
        });
    }