/// <summary>
		/// Binds the model.
		/// </summary>
		public async Task BindModelAsync(ModelBindingContext bindingContext)
		{
			var typeFieldNamePrefix = !string.IsNullOrEmpty(bindingContext.ModelName)
				? $"{bindingContext.ModelName}."
				: "";

			var typeName = (string)bindingContext.ValueProvider
				.GetValue($"{typeFieldNamePrefix}{_baseType.Name}Type")
				.ConvertTo(typeof(string));

			if (typeName == null)
				return;
			
			var derivedModelBinderKvp = _derivedModelBinders.First(kvp => kvp.Key.Name == typeName);
			var derivedModelType = derivedModelBinderKvp.Key;
			var derivedModelBinder = derivedModelBinderKvp.Value;

			ModelBindingResult result;
			using (bindingContext.EnterNestedScope(
				_modelMetadataProvider.GetMetadataForType(derivedModelType),
				bindingContext.FieldName,
				bindingContext.ModelName,
				model: null
				))
			{
				await derivedModelBinder.BindModelAsync(bindingContext);
				result = bindingContext.Result;
			}

			bindingContext.Result = result;
		}
        internal async Task <ModelBindingResult> TryBindStrongModel <TModel>(
            ModelBindingContext bindingContext,
            string propertyName)
        {
            var propertyModelMetadata =
                bindingContext.OperationBindingContext.MetadataProvider.GetMetadataForType(typeof(TModel));
            var propertyModelName =
                ModelNames.CreatePropertyModelName(bindingContext.ModelName, propertyName);

            using (bindingContext.EnterNestedScope(
                       modelMetadata: propertyModelMetadata,
                       fieldName: propertyName,
                       modelName: propertyModelName,
                       model: null))
            {
                await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(
                    bindingContext);

                var result = bindingContext.Result;
                if (result != null && result.Value.IsModelSet)
                {
                    return(result.Value);
                }
                else
                {
                    return(ModelBindingResult.Failed(propertyModelName));
                }
            }
        }
        private async Task BindModelCoreAsync(ModelBindingContext bindingContext)
        {
            // Create model first (if necessary) to avoid reporting errors about properties when activation fails.
            if (bindingContext.Model == null)
            {
                bindingContext.Model = CreateModel(bindingContext);
            }

            foreach (var property in bindingContext.ModelMetadata.Properties)
            {
                if (!CanBindProperty(bindingContext, property))
                {
                    continue;
                }

                // Pass complex (including collection) values down so that binding system does not unnecessarily
                // recreate instances or overwrite inner properties that are not bound. No need for this with simple
                // values because they will be overwritten if binding succeeds. Arrays are never reused because they
                // cannot be resized.
                object propertyModel = null;
                if (property.PropertyGetter != null &&
                    property.IsComplexType &&
                    !property.ModelType.IsArray)
                {
                    propertyModel = property.PropertyGetter(bindingContext.Model);
                }

                var fieldName = property.BinderModelName ?? property.PropertyName;
                var modelName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, fieldName);

                ModelBindingResult result;
                using (bindingContext.EnterNestedScope(
                           modelMetadata: property,
                           fieldName: fieldName,
                           modelName: modelName,
                           model: propertyModel))
                {
                    await BindProperty(bindingContext);

                    result = bindingContext.Result ?? ModelBindingResult.Failed(modelName);
                }

                if (result.IsModelSet)
                {
                    SetProperty(bindingContext, property, result);
                }
                else if (property.IsBindingRequired)
                {
                    var message = property.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(fieldName);
                    bindingContext.ModelState.TryAddModelError(modelName, message);
                }
            }

            bindingContext.Result = ModelBindingResult.Success(bindingContext.ModelName, bindingContext.Model);
        }
        // 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 metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
            var elementMetadata  = metadataProvider.GetMetadataForType(typeof(TElement));


            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
                };

                object boundValue = null;

                using (bindingContext.EnterNestedScope(
                           elementMetadata,
                           fieldName: bindingContext.FieldName,
                           modelName: bindingContext.ModelName,
                           model: null))
                {
                    await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(bindingContext);

                    if (bindingContext.Result != null && bindingContext.Result.Value.IsModelSet)
                    {
                        boundValue = bindingContext.Result.Value.Model;
                        boundCollection.Add(ModelBindingHelper.CastOrDefault <TElement>(boundValue));
                    }
                }
            }

            return(new CollectionResult
            {
                Model = boundCollection
            });
        }
        private bool CanValueBindAnyModelProperties(ModelBindingContext bindingContext)
        {
            // If there are no properties on the model, there is nothing to bind. We are here means this is not a top
            // level object. So we return false.
            if (bindingContext.ModelMetadata.Properties.Count == 0)
            {
                return(false);
            }

            // We want to check to see if any of the properties of the model can be bound using the value providers,
            // because that's all that MutableObjectModelBinder can handle.
            //
            // However, because a property might specify a custom binding source ([FromForm]), it's not correct
            // for us to just try bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName),
            // because that may include other value providers - that would lead us to mistakenly create the model
            // when the data is coming from a source we should use (ex: value found in query string, but the
            // model has [FromForm]).
            //
            // To do this we need to enumerate the properties, and see which of them provide a binding source
            // through metadata, then we decide what to do.
            //
            //      If a property has a binding source, and it's a greedy source, then it's not
            //      allowed to come from a value provider, so we skip it.
            //
            //      If a property has a binding source, and it's a non-greedy source, then we'll filter the
            //      the value providers to just that source, and see if we can find a matching prefix
            //      (see CanBindValue).
            //
            //      If a property does not have a binding source, then it's fair game for any value provider.
            //
            // If any property meets the above conditions and has a value from valueproviders, then we'll
            // create the model and try to bind it. OR if ALL properties of the model have a greedy source,
            // then we go ahead and create it.
            //
            var hasBindableProperty = false;
            var isAnyPropertyEnabledForValueProviderBasedBinding = false;

            foreach (var propertyMetadata in bindingContext.ModelMetadata.Properties)
            {
                if (!CanBindProperty(bindingContext, propertyMetadata))
                {
                    continue;
                }

                hasBindableProperty = true;

                // This check will skip properties which are marked explicitly using a non value binder.
                var bindingSource = propertyMetadata.BindingSource;
                if (bindingSource == null || !bindingSource.IsGreedy)
                {
                    isAnyPropertyEnabledForValueProviderBasedBinding = true;

                    var fieldName = propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName;
                    var modelName = ModelNames.CreatePropertyModelName(
                        bindingContext.ModelName,
                        fieldName);

                    using (bindingContext.EnterNestedScope(
                               modelMetadata: propertyMetadata,
                               fieldName: fieldName,
                               modelName: modelName,
                               model: null))
                    {
                        // If any property can return a true value.
                        if (CanBindValue(bindingContext))
                        {
                            return(true);
                        }
                    }
                }
            }

            if (hasBindableProperty && !isAnyPropertyEnabledForValueProviderBasedBinding)
            {
                // All the properties are marked with a non value provider based marker like [FromHeader] or
                // [FromBody].
                return(true);
            }

            return(false);
        }
        /// <inheritdoc />
        public override async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }

            await base.BindModelAsync(bindingContext);

            if (bindingContext.Result == null || !bindingContext.Result.Value.IsModelSet)
            {
                // No match for the prefix at all.
                return;
            }

            var result = bindingContext.Result.Value;

            Debug.Assert(result.Model != null);
            var model = (IDictionary <TKey, TValue>)result.Model;

            if (model.Count != 0)
            {
                // ICollection<KeyValuePair<TKey, TValue>> approach was successful.
                return;
            }

            var enumerableValueProvider = bindingContext.ValueProvider as IEnumerableValueProvider;

            if (enumerableValueProvider == null)
            {
                // No IEnumerableValueProvider available for the fallback approach. For example the user may have
                // replaced the ValueProvider with something other than a CompositeValueProvider.
                return;
            }

            // Attempt to bind dictionary from a set of prefix[key]=value entries. Get the short and long keys first.
            var keys = enumerableValueProvider.GetKeysFromPrefix(bindingContext.ModelName);

            if (!keys.Any())
            {
                // No entries with the expected keys.
                return;
            }

            // Update the existing successful but empty ModelBindingResult.
            var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
            var valueMetadata    = metadataProvider.GetMetadataForType(typeof(TValue));

            var modelBinder = bindingContext.OperationBindingContext.ModelBinder;

            var keyMappings = new Dictionary <string, TKey>(StringComparer.Ordinal);

            foreach (var kvp in keys)
            {
                // Use InvariantCulture to convert the key since ExpressionHelper.GetExpressionText() would use
                // that culture when rendering a form.
                var convertedKey = ModelBindingHelper.ConvertTo <TKey>(kvp.Key, culture: null);

                using (bindingContext.EnterNestedScope(
                           modelMetadata: valueMetadata,
                           fieldName: bindingContext.FieldName,
                           modelName: kvp.Value,
                           model: null))
                {
                    await modelBinder.BindModelAsync(bindingContext);

                    var valueResult = bindingContext.Result;

                    // Always add an entry to the dictionary but validate only if binding was successful.
                    model[convertedKey] = ModelBindingHelper.CastOrDefault <TValue>(valueResult.Value.Model);
                    keyMappings.Add(kvp.Key, convertedKey);
                }
            }

            bindingContext.ValidationState.Add(model, new ValidationStateEntry()
            {
                Strategy = new ShortFormDictionaryValidationStrategy <TKey, TValue>(keyMappings, valueMetadata),
            });
        }
        private async Task RunModelBinders(ModelBindingContext bindingContext)
        {
            RuntimeHelpers.EnsureSufficientExecutionStack();

            ModelBindingResult?overallResult = null;

            try
            {
                using (bindingContext.EnterNestedScope())
                {
                    if (PrepareBindingContext(bindingContext))
                    {
                        // Perf: Avoid allocations
                        for (var i = 0; i < ModelBinders.Count; i++)
                        {
                            var binder = ModelBinders[i];
                            await binder.BindModelAsync(bindingContext);

                            if (bindingContext.Result != null)
                            {
                                var result = bindingContext.Result.Value;
                                // This condition is necessary because the ModelState entry would never be validated if
                                // caller fell back to the empty prefix, leading to an possibly-incorrect !IsValid. In most
                                // (hopefully all) cases, the ModelState entry exists because some binders add errors before
                                // returning a result with !IsModelSet. Those binders often cannot run twice anyhow.
                                if (result.IsModelSet ||
                                    bindingContext.ModelState.ContainsKey(bindingContext.ModelName))
                                {
                                    if (bindingContext.IsTopLevelObject && result.Model != null)
                                    {
                                        ValidationStateEntry entry;
                                        if (!bindingContext.ValidationState.TryGetValue(result.Model, out entry))
                                        {
                                            entry = new ValidationStateEntry()
                                            {
                                                Key      = result.Key,
                                                Metadata = bindingContext.ModelMetadata,
                                            };
                                            bindingContext.ValidationState.Add(result.Model, entry);
                                        }
                                    }

                                    overallResult = bindingContext.Result;
                                    return;
                                }

                                // Current binder should have been able to bind value but found nothing. Exit loop in a way that
                                // tells caller to fall back to the empty prefix, if appropriate. Do not return result because it
                                // means only "other binders are not applicable".

                                // overallResult MUST still be null at this return statement.
                                return;
                            }
                        }
                    }
                }
            }
            finally
            {
                bindingContext.Result = overallResult;
            }
        }
        // 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 metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
            var elementMetadata  = metadataProvider.GetMetadataForType(typeof(TElement));

            var boundCollection = new List <TElement>();

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

                var                didBind    = false;
                object             boundValue = null;
                ModelBindingResult?result;
                using (bindingContext.EnterNestedScope(
                           elementMetadata,
                           fieldName: indexName,
                           modelName: fullChildName,
                           model: null))
                {
                    await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(bindingContext);

                    result = bindingContext.Result;
                }

                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));
            }

            return(new CollectionResult
            {
                Model = boundCollection,

                // If we're working with a fixed set of indexes then this is the format like:
                //
                //  ?parameter.index=zero,one,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,
            });
        }