public void CreateSimpleTypeBinderTest(string methodName)
        {
            var methodInfo = typeof(Sample).GetRuntimeMethods().Single(x => x.Name == methodName);
            var binder     = _factory.CreateBinder(methodInfo.GetParameters()[0]);

            Assert.NotNull(binder);
            Assert.True(binder is SimpleTypeModelBinder);
            Assert.False(binder is ComplexTypeModelBinder);
        }
Beispiel #2
0
 public async Task BindModelAsync(ModelBindingContext bindingContext)
 {
     if (bindingContext == null)
     {
         throw new ArgumentNullException(nameof(bindingContext));
     }
     var typeValue = bindingContext.ValueProvider.GetValue(nameof(ComplexModel.Type)).Values;
     var nameValue = bindingContext.ValueProvider.GetValue(nameof(ComplexModel.Name)).Values;
     var finalModel = new ComplexModel
     {
         Name = nameValue,
         Type = typeValue
     };
     var innerType = LookupType(typeValue);
     if (innerType != null)
     {
         finalModel.Parameters = Activator.CreateInstance(innerType);
         var modelMetadata = _modelMetadataProvider.GetMetadataForType(innerType);
         var modelBinder = _modelBinderFactory.CreateBinder(new ModelBinderFactoryContext
         {
             Metadata = modelMetadata,
             CacheToken = modelMetadata
         });
         var modelName = bindingContext.BinderModelName == null ? "Parameters" : $"{bindingContext.BinderModelName}.Parameters";
         using (var scope = bindingContext.EnterNestedScope(modelMetadata, modelName, modelName, finalModel.Parameters))
         {
             await modelBinder.BindModelAsync(bindingContext);
         }
     }
     bindingContext.Result = ModelBindingResult.Success(finalModel);
     return;
 }
        public Task <IBinding?> TryCreateAsync(BindingProviderContext context)
        {
            _ = context ?? throw new ArgumentNullException(nameof(context));

            var attribute = context.Parameter.GetCustomAttributes(inherit: false).OfType <IBindingSourceMetadata>().FirstOrDefault();

            if (!(attribute is null))
            {
                var modelMetadata = _modelMetadataProvider switch
                {
                    ModelMetadataProvider provider => provider.GetMetadataForParameter(context.Parameter),
                    _ => _modelMetadataProvider.GetMetadataForType(context.Parameter.ParameterType)
                };

                var modelBinderFactoryContext = new ModelBinderFactoryContext
                {
                    Metadata    = modelMetadata,
                    BindingInfo = BindingInfo.GetBindingInfo(context.Parameter.GetCustomAttributes())
                };

                var modelBinder = _modelBinderFactory.CreateBinder(modelBinderFactoryContext);

                return(Task.FromResult <IBinding?>(new MvcModelBinding(context.Parameter, modelMetadata, modelBinder, _mvcOptions.ValueProviderFactories)));
            }

            return(Task.FromResult <IBinding?>(null));
        }
    }
Beispiel #4
0
        private static BindingInfo[] GetPropertyBindingInfo(
            IModelBinderFactory modelBinderFactory,
            IModelMetadataProvider modelMetadataProvider,
            ControllerActionDescriptor actionDescriptor)
        {
            var properties = actionDescriptor.BoundProperties;

            if (properties.Count == 0)
            {
                return(null);
            }

            var propertyBindingInfo = new BindingInfo[properties.Count];
            var controllerType      = actionDescriptor.ControllerTypeInfo.AsType();

            for (var i = 0; i < properties.Count; i++)
            {
                var property = properties[i];
                var metadata = modelMetadataProvider.GetMetadataForProperty(controllerType, property.Name);
                var binder   = modelBinderFactory.CreateBinder(new ModelBinderFactoryContext
                {
                    BindingInfo = property.BindingInfo,
                    Metadata    = metadata,
                    CacheToken  = property,
                });

                propertyBindingInfo[i] = new BindingInfo(binder, metadata);
            }

            return(propertyBindingInfo);
        }
Beispiel #5
0
        private static BindingInfo[] GetParameterBindingInfo(
            IModelBinderFactory modelBinderFactory,
            IModelMetadataProvider modelMetadataProvider,
            ControllerActionDescriptor actionDescriptor)
        {
            var parameters = actionDescriptor.Parameters;

            if (parameters.Count == 0)
            {
                return(null);
            }

            var parameterBindingInfo = new BindingInfo[parameters.Count];

            for (var i = 0; i < parameters.Count; i++)
            {
                var parameter = parameters[i];
                var metadata  = modelMetadataProvider.GetMetadataForType(parameter.ParameterType);
                var binder    = modelBinderFactory.CreateBinder(new ModelBinderFactoryContext
                {
                    BindingInfo = parameter.BindingInfo,
                    Metadata    = metadata,
                    CacheToken  = parameter,
                });

                parameterBindingInfo[i] = new BindingInfo(binder, metadata);
            }

            return(parameterBindingInfo);
        }
Beispiel #6
0
        public async Task <ModelBindingResult?> BindModelAsync(
            ParameterDescriptor parameter,
            ControllerContext controllerContext)
        {
            if (parameter == null)
            {
                throw new ArgumentNullException(nameof(parameter));
            }

            if (controllerContext == null)
            {
                throw new ArgumentNullException(nameof(controllerContext));
            }

            var metadata            = _modelMetadataProvider.GetMetadataForType(parameter.ParameterType);
            var modelBindingContext = DefaultModelBindingContext.CreateBindingContext(
                controllerContext,
                new CompositeValueProvider(controllerContext.ValueProviders),
                metadata,
                parameter.BindingInfo,
                parameter.Name);

            if (parameter.BindingInfo?.BinderModelName != null)
            {
                // The name was set explicitly, always use that as the prefix.
                modelBindingContext.ModelName = parameter.BindingInfo.BinderModelName;
            }
            else if (modelBindingContext.ValueProvider.ContainsPrefix(parameter.Name))
            {
                // We have a match for the parameter name, use that as that prefix.
                modelBindingContext.ModelName = parameter.Name;
            }
            else
            {
                // No match, fallback to empty string as the prefix.
                modelBindingContext.ModelName = string.Empty;
            }

            var binder = _modelBinderFactory.CreateBinder(new ModelBinderFactoryContext()
            {
                BindingInfo = parameter.BindingInfo,
                Metadata    = metadata,
                CacheToken  = parameter,
            });

            await binder.BindModelAsync(modelBindingContext);

            var modelBindingResult = modelBindingContext.Result;

            if (modelBindingResult != null && modelBindingResult.Value.IsModelSet)
            {
                _validator.Validate(
                    controllerContext,
                    modelBindingContext.ValidationState,
                    modelBindingResult.Value.Key,
                    modelBindingResult.Value.Model);
            }

            return(modelBindingResult);
        }
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (!int.TryParse(bindingContext.ValueProvider.GetValue("id").FirstValue, out int productId))
            {
                throw new Exception("The product id was not provided");
            }

            var editModel = new ProductConfigurationEditModel
            {
                Fields = productRepository.GetProductFields(productId)
            };

            for (int i = 0; i < editModel.Fields.Count; i++)
            {
                BaseField     field         = editModel.Fields[i];
                ModelMetadata modelMetadata = modelMetadataProvider.GetMetadataForType(field.GetType());
                IModelBinder  modelBinder   = modelBinderFactory.CreateBinder(new ModelBinderFactoryContext
                {
                    Metadata   = modelMetadata,
                    CacheToken = modelMetadata
                });

                string modelName = $"{bindingContext.BinderModelName}.Fields[{i}]".TrimStart('.');
                using (var scope = bindingContext.EnterNestedScope(modelMetadata, modelName, modelName, field))
                {
                    await modelBinder.BindModelAsync(bindingContext);
                }
            }

            bindingContext.Result = ModelBindingResult.Success(editModel);
        }
        private async Task <object> ExecuteWithParameterAsync(ObjectMethodExecutor executor,
                                                              object @class, string parameterString)
        {
            var firstParameter = executor.MethodParameters[0];

            try
            {
                var binder     = _modelBinderFactory.CreateBinder(firstParameter);
                var bindResult = await binder.BindModelAsync(parameterString);

                if (bindResult.IsSuccess)
                {
                    if (executor.IsMethodAsync)
                    {
                        return(await executor.ExecuteAsync(@class, bindResult.Model));
                    }

                    return(executor.Execute(@class, bindResult.Model));
                }

                throw new MethodBindException(
                          $"Parameters:{firstParameter.Name} bind failed! ParameterString is: {parameterString} ");
            }
            catch (FormatException ex)
            {
                _logger.ModelBinderFormattingException(executor.MethodInfo?.Name, firstParameter.Name, parameterString,
                                                       ex);
                return(null);
            }
        }
Beispiel #9
0
        private IModelBinder GetBinder(ModelMetadata modelMetadata)
        {
            dynamic identity         = typeof(ModelMetadata).GetProperty("Identity", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic).GetValue(modelMetadata);
            var     key              = ModelMetadataIdentity.ForParameter(identity.ParameterInfo, modelMetadata.ModelType);
            var     newModelMetadata = new DefaultModelMetadata(_modelMetadataProvider, _detailsProvider, new DefaultMetadataDetails(key, ModelAttributes.GetAttributesForParameter(identity.ParameterInfo, modelMetadata.ModelType)), _modelBindingMessageProvider);

            newModelMetadata.BindingMetadata.BinderType = null;

            var factoryContext = new ModelBinderFactoryContext()
            {
                Metadata    = newModelMetadata,
                BindingInfo = new BindingInfo()
                {
                    BinderModelName        = newModelMetadata.BinderModelName,
                    BinderType             = newModelMetadata.BinderType,
                    BindingSource          = newModelMetadata.BindingSource,
                    PropertyFilterProvider = newModelMetadata.PropertyFilterProvider,
                },

                CacheToken = null,
            };

            var binder = _modelBinderFactory.CreateBinder(factoryContext);

            return(binder);
        }
Beispiel #10
0
        private BinderItem[] GetParameterBindingInfo(IModelBinderFactory modelBinderFactory)
        {
            if (Parameters.Count == 0)
            {
                return(null);
            }

            var parameterBindingInfo = new BinderItem[Parameters.Count];

            for (var i = 0; i < Parameters.Count; i++)
            {
                var parameter = Parameters[i];
                var metadata  = new ModelMetadata(parameter);

                var binder = modelBinderFactory.CreateBinder(new ModelBinderFactoryContext
                {
                    BindingInfo = parameter.BindingInfo,
                    Metadata    = metadata,
                    CacheToken  = parameter
                });

                parameterBindingInfo[i] = new BinderItem(binder, metadata);
            }

            return(parameterBindingInfo);
        }
Beispiel #11
0
        protected override async Task <ModelBindingResult> BindAsync(PageContext pageContext, object value, string name, Type type)
        {
            var factories = pageContext.ValueProviderFactories;
            var valueProviderFactoryContext = new ValueProviderFactoryContext(pageContext);

            for (var i = 0; i < factories.Count; i++)
            {
                var factory = factories[i];
                await factory.CreateValueProviderAsync(valueProviderFactoryContext);
            }

            var valueProvider = new CompositeValueProvider(valueProviderFactoryContext.ValueProviders);

            var metadata = _modelMetadataProvider.GetMetadataForType(type);
            var binder   = _modelBinderFactory.CreateBinder(new ModelBinderFactoryContext()
            {
                BindingInfo = null,
                Metadata    = metadata,
                CacheToken  = null,
            });

            var modelBindingContext = DefaultModelBindingContext.CreateBindingContext(
                pageContext,
                valueProvider,
                metadata,
                null,
                name);

            modelBindingContext.Model = value;

            if (modelBindingContext.ValueProvider.ContainsPrefix(name))
            {
                // We have a match for the parameter name, use that as that prefix.
                modelBindingContext.ModelName = name;
            }
            else
            {
                // No match, fallback to empty string as the prefix.
                modelBindingContext.ModelName = string.Empty;
            }

            await binder.BindModelAsync(modelBindingContext);

            var result = modelBindingContext.Result;

            if (result.IsModelSet)
            {
                _validator.Validate(
                    pageContext,
                    modelBindingContext.ValidationState,
                    modelBindingContext.ModelName,
                    result.Model);
            }

            return(result);
        }
        public async Task <T> Bind <T>(HttpRequest request) where T : new()
        {
            //always rewind the stream; otherwise,
            //if multiple handlers concurrently bind
            //different models only the first one succeeds
            request.Body.Position = 0;

            var modelType     = typeof(T);
            var modelMetadata = modelMetadataProvider.GetMetadataForType(modelType);
            var actionContext = new ActionContext(
                request.HttpContext,
                request.HttpContext.GetRouteData(),
                new ActionDescriptor(),
                new ModelStateDictionary());
            var valueProvider =
                await CompositeValueProvider.CreateAsync(actionContext, mvcOptions.Value.ValueProviderFactories);

#if NET5_0
            if (modelMetadata.BoundConstructor != null)
            {
                throw new NotSupportedException("Record type not supported");
            }
#endif

            var modelBindingContext = DefaultModelBindingContext.CreateBindingContext(
                actionContext,
                valueProvider,
                modelMetadata,
                bindingInfo: null,
                modelName: "");

            modelBindingContext.Model          = new T();
            modelBindingContext.PropertyFilter = _ => true; // All props

            var factoryContext = new ModelBinderFactoryContext()
            {
                Metadata    = modelMetadata,
                BindingInfo = new BindingInfo()
                {
                    BinderModelName        = modelMetadata.BinderModelName,
                    BinderType             = modelMetadata.BinderType,
                    BindingSource          = modelMetadata.BindingSource,
                    PropertyFilterProvider = modelMetadata.PropertyFilterProvider,
                },
                CacheToken = modelMetadata,
            };

            await modelBinderFactory
            .CreateBinder(factoryContext)
            .BindModelAsync(modelBindingContext);

            return((T)modelBindingContext.Result.Model);
        }
Beispiel #13
0
        protected override object GetHttpValue(string name, Type valueType)
        {
            if (valueType == typeof(Stream) && name == "$request")
            {
                return(HttpContext.Request.Body);
            }
            else if (valueType == typeof(Stream) && name == "$response")
            {
                return(HttpContext.Response.Body);
            }
            else if (valueType == typeof(ISelectedFile) || valueType == typeof(ISelectedFile[]))
            {
                return(base.GetHttpValue(name, valueType));
            }

            ModelBinderFactoryContext context = new ModelBinderFactoryContext();

            context.BindingInfo = new BindingInfo()
            {
                BinderModelName = name, BindingSource = BindingSource.ModelBinding
            };
            context.CacheToken = name + "_" + valueType.Name;
            context.Metadata   = _ModelMetadataProvider.GetMetadataForType(valueType);

            var binder         = _ModelBinderFactory.CreateBinder(context);
            var bindingContext = DefaultModelBindingContext.CreateBindingContext(ActionContext, this, context.Metadata, context.BindingInfo, name);

            try
            {
                binder.BindModelAsync(bindingContext).Wait();
                if (bindingContext.Result.IsModelSet)
                {
                    return(bindingContext.Result.Model);
                }
            }
            catch
            {
            }
            return(null);
        }
        public async Task InvokeAsync()
        {
            using (_logger.BeginScope("consumer invoker begin"))
            {
                _logger.LogDebug("Executing consumer Topic: {0}", _consumerContext.ConsumerDescriptor.MethodInfo.Name);

                var obj = ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider,
                                                                        _consumerContext.ConsumerDescriptor.ImplTypeInfo.AsType());

                var value = _consumerContext.DeliverMessage.Content;
                if (_executor.MethodParameters.Length > 0)
                {
                    var firstParameter = _executor.MethodParameters[0];
                    try
                    {
                        var binder = _modelBinderFactory.CreateBinder(firstParameter);
                        var result = await binder.BindModelAsync(value);

                        if (result.IsSuccess)
                        {
                            _executor.Execute(obj, result.Model);
                        }
                        else
                        {
                            _logger.LogWarning($"Parameters:{firstParameter.Name} bind failed! the content is:" + value);
                        }
                    }
                    catch (FormatException ex)
                    {
                        _logger.ModelBinderFormattingException(_executor.MethodInfo?.Name, firstParameter.Name, value, ex);
                    }
                }
                else
                {
                    _executor.Execute(obj);
                }
            }
        }
Beispiel #15
0
    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        var         contentType = bindingContext.ActionContext.HttpContext.Request.ContentType;
        BindingInfo bindingInfo = new BindingInfo();

        if (contentType == "application/json")
        {
        }
        else if (contentType == "application/x-www-form-urlencoded")
        {
            bindingInfo.BindingSource = BindingSource.Form;
        }
        else
        {
            bindingContext.Result = ModelBindingResult.Failed();
        }
        var binder = factory.CreateBinder(new ModelBinderFactoryContext
        {
            Metadata    = bindingContext.ModelMetadata,
            BindingInfo = bindingInfo,
        });
        await binder.BindModelAsync(bindingContext);
    }
Beispiel #16
0
        /// <summary>
        /// Binds a model specified by <paramref name="parameter"/> using <paramref name="value"/> as the initial value.
        /// </summary>
        /// <param name="actionContext">The <see cref="ActionContext"/>.</param>
        /// <param name="valueProvider">The <see cref="IValueProvider"/>.</param>
        /// <param name="parameter">The <see cref="ParameterDescriptor"/></param>
        /// <param name="value">The initial model value.</param>
        /// <returns>The result of model binding.</returns>
        public virtual Task <ModelBindingResult> BindModelAsync(
            ActionContext actionContext,
            IValueProvider valueProvider,
            ParameterDescriptor parameter,
            object value)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException(nameof(actionContext));
            }

            if (valueProvider == null)
            {
                throw new ArgumentNullException(nameof(valueProvider));
            }

            if (parameter == null)
            {
                throw new ArgumentNullException(nameof(parameter));
            }

            var metadata = _modelMetadataProvider.GetMetadataForType(parameter.ParameterType);
            var binder   = _modelBinderFactory.CreateBinder(new ModelBinderFactoryContext
            {
                BindingInfo = parameter.BindingInfo,
                Metadata    = metadata,
                CacheToken  = parameter,
            });

            return(BindModelAsync(
                       actionContext,
                       binder,
                       valueProvider,
                       parameter,
                       metadata,
                       value));
        }
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var actualDiscriminatorValue = await _reader.ReadDiscriminatorAsync(_discriminator.Property, bindingContext.HttpContext);

            if (null == actualDiscriminatorValue)
            {
                throw new CouldNotReadDiscriminatorException();
            }

            var resolvedType = Fn.CreateResolver(_cases)(actualDiscriminatorValue);

            if (null == resolvedType)
            {
                throw new UnresolvableDiscriminatorCaseException(actualDiscriminatorValue);
            }

            var metadataForResolvedType = _metadataProvider.GetMetadataForType(resolvedType);

            var modelBinderForResolvedType = _factory.CreateBinder(new ModelBinderFactoryContext
            {
                Metadata    = metadataForResolvedType,
                BindingInfo = new BindingInfo
                {
                    BindingSource   = bindingContext.BindingSource,
                    BinderModelName = bindingContext.BinderModelName
                }
            });

            if (null == modelBinderForResolvedType)
            {
                throw new CouldNotResolveBinderForTypeException(resolvedType);
            }

            bindingContext.ModelMetadata = metadataForResolvedType;

            await modelBinderForResolvedType.BindModelAsync(bindingContext);
        }
 public IModelBinder CreateBinder(ModelBinderFactoryContext context)
 => new Wrapper(_modelBinderFactory.CreateBinder(context));
Beispiel #19
0
        public static PageHandlerBinderDelegate CreateHandlerBinder(
            ParameterBinder parameterBinder,
            IModelMetadataProvider modelMetadataProvider,
            IModelBinderFactory modelBinderFactory,
            CompiledPageActionDescriptor actionDescriptor,
            HandlerMethodDescriptor handler,
            MvcOptions mvcOptions)
        {
            if (handler.Parameters == null || handler.Parameters.Count == 0)
            {
                return(NullHandlerBinder);
            }

            var handlerType          = actionDescriptor.HandlerTypeInfo.AsType();
            var parameterBindingInfo = new BinderItem[handler.Parameters.Count];

            for (var i = 0; i < parameterBindingInfo.Length; i++)
            {
                var           parameter = handler.Parameters[i];
                ModelMetadata metadata;
                if (mvcOptions.AllowValidatingTopLevelNodes &&
                    modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
                {
                    // The default model metadata provider derives from ModelMetadataProvider
                    // and can therefore supply information about attributes applied to parameters.
                    metadata = modelMetadataProviderBase.GetMetadataForParameter(parameter.ParameterInfo);
                }
                else
                {
                    // For backward compatibility, if there's a custom model metadata provider that
                    // only implements the older IModelMetadataProvider interface, access the more
                    // limited metadata information it supplies. In this scenario, validation attributes
                    // are not supported on parameters.
                    metadata = modelMetadataProvider.GetMetadataForType(parameter.ParameterType);
                }

                var binder = modelBinderFactory.CreateBinder(new ModelBinderFactoryContext
                {
                    BindingInfo = parameter.BindingInfo,
                    Metadata    = metadata,
                    CacheToken  = parameter,
                });

                parameterBindingInfo[i] = new BinderItem(binder, metadata);
            }

            return(Bind);

            async Task Bind(PageContext pageContext, IDictionary <string, object> arguments)
            {
                var valueProvider = await CompositeValueProvider.CreateAsync(pageContext, pageContext.ValueProviderFactories);

                for (var i = 0; i < parameterBindingInfo.Length; i++)
                {
                    var parameter     = handler.Parameters[i];
                    var bindingInfo   = parameterBindingInfo[i];
                    var modelMetadata = bindingInfo.ModelMetadata;

                    if (!modelMetadata.IsBindingAllowed)
                    {
                        continue;
                    }

                    var result = await parameterBinder.BindModelAsync(
                        pageContext,
                        bindingInfo.ModelBinder,
                        valueProvider,
                        parameter,
                        modelMetadata,
                        value : null);

                    if (result.IsModelSet)
                    {
                        arguments[parameter.Name] = result.Model;
                    }
                }
            }
        }
Beispiel #20
0
        public static Func <PageContext, object, Task> CreatePropertyBinder(
            ParameterBinder parameterBinder,
            IModelMetadataProvider modelMetadataProvider,
            IModelBinderFactory modelBinderFactory,
            CompiledPageActionDescriptor actionDescriptor)
        {
            if (parameterBinder == null)
            {
                throw new ArgumentNullException(nameof(parameterBinder));
            }

            if (actionDescriptor == null)
            {
                throw new ArgumentNullException(nameof(actionDescriptor));
            }

            var properties = actionDescriptor.BoundProperties;

            if (properties == null || properties.Count == 0)
            {
                return(NullPropertyBinder);
            }

            var handlerType         = actionDescriptor.HandlerTypeInfo.AsType();
            var propertyBindingInfo = new BinderItem[properties.Count];

            for (var i = 0; i < properties.Count; i++)
            {
                var property = properties[i];
                var metadata = modelMetadataProvider.GetMetadataForProperty(handlerType, property.Name);
                var binder   = modelBinderFactory.CreateBinder(new ModelBinderFactoryContext
                {
                    BindingInfo = property.BindingInfo,
                    Metadata    = metadata,
                    CacheToken  = property,
                });

                propertyBindingInfo[i] = new BinderItem(binder, metadata);
            }

            return(Bind);

            async Task Bind(PageContext pageContext, object instance)
            {
                var valueProvider = await CompositeValueProvider.CreateAsync(pageContext, pageContext.ValueProviderFactories);

                for (var i = 0; i < properties.Count; i++)
                {
                    var property      = properties[i];
                    var bindingInfo   = propertyBindingInfo[i];
                    var modelMetadata = bindingInfo.ModelMetadata;

                    if (!modelMetadata.IsBindingAllowed)
                    {
                        continue;
                    }

                    var result = await parameterBinder.BindModelAsync(
                        pageContext,
                        bindingInfo.ModelBinder,
                        valueProvider,
                        property,
                        modelMetadata,
                        value : null);

                    if (result.IsModelSet)
                    {
                        PropertyValueSetter.SetValue(bindingInfo.ModelMetadata, instance, result.Model);
                    }
                }
            }
        }
Beispiel #21
0
 public IModelBinder CreateBinder(ModelBinderFactoryContext context) =>
 _factory.CreateBinder(context);
Beispiel #22
0
        /// <summary>
        /// Updates the specified <paramref name="model"/> instance using the specified <paramref name="modelBinderFactory"/>
        /// and the specified <paramref name="valueProvider"/> and executes validation using the specified
        /// <paramref name="objectModelValidator"/>.
        /// </summary>
        /// <param name="model">The model instance to update and validate.</param>
        /// <param name="modelType">The type of model instance to update and validate.</param>
        /// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
        /// </param>
        /// <param name="actionContext">The <see cref="ActionContext"/> for the current executing request.</param>
        /// <param name="metadataProvider">The provider used for reading metadata for the model type.</param>
        /// <param name="modelBinderFactory">The <see cref="IModelBinderFactory"/> used for binding.</param>
        /// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
        /// <param name="objectModelValidator">The <see cref="IObjectModelValidator"/> used for validating the
        /// bound values.</param>
        /// <param name="propertyFilter">A predicate which can be used to
        /// filter properties(for inclusion/exclusion) at runtime.</param>
        /// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
        public static async Task <bool> TryUpdateModelAsync(
            object model,
            Type modelType,
            string prefix,
            ActionContext actionContext,
            IModelMetadataProvider metadataProvider,
            IModelBinderFactory modelBinderFactory,
            IValueProvider valueProvider,
            IObjectModelValidator objectModelValidator,
            Func <ModelMetadata, bool> propertyFilter)
        {
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }

            if (modelType == null)
            {
                throw new ArgumentNullException(nameof(modelType));
            }

            if (prefix == null)
            {
                throw new ArgumentNullException(nameof(prefix));
            }

            if (actionContext == null)
            {
                throw new ArgumentNullException(nameof(actionContext));
            }

            if (metadataProvider == null)
            {
                throw new ArgumentNullException(nameof(metadataProvider));
            }

            if (modelBinderFactory == null)
            {
                throw new ArgumentNullException(nameof(modelBinderFactory));
            }

            if (valueProvider == null)
            {
                throw new ArgumentNullException(nameof(valueProvider));
            }

            if (objectModelValidator == null)
            {
                throw new ArgumentNullException(nameof(objectModelValidator));
            }

            if (propertyFilter == null)
            {
                throw new ArgumentNullException(nameof(propertyFilter));
            }

            if (!modelType.IsAssignableFrom(model.GetType()))
            {
                var message = Resources.FormatModelType_WrongType(
                    model.GetType().FullName,
                    modelType.FullName);
                throw new ArgumentException(message, nameof(modelType));
            }

            var modelMetadata = metadataProvider.GetMetadataForType(modelType);
            var modelState    = actionContext.ModelState;

            var modelBindingContext = DefaultModelBindingContext.CreateBindingContext(
                actionContext,
                valueProvider,
                modelMetadata,
                bindingInfo: null,
                modelName: prefix);

            modelBindingContext.Model          = model;
            modelBindingContext.PropertyFilter = propertyFilter;

            var factoryContext = new ModelBinderFactoryContext()
            {
                Metadata    = modelMetadata,
                BindingInfo = new BindingInfo()
                {
                    BinderModelName        = modelMetadata.BinderModelName,
                    BinderType             = modelMetadata.BinderType,
                    BindingSource          = modelMetadata.BindingSource,
                    PropertyFilterProvider = modelMetadata.PropertyFilterProvider,
                },

                // We're using the model metadata as the cache token here so that TryUpdateModelAsync calls
                // for the same model type can share a binder. This won't overlap with normal model binding
                // operations because they use the ParameterDescriptor for the token.
                CacheToken = modelMetadata,
            };
            var binder = modelBinderFactory.CreateBinder(factoryContext);

            await binder.BindModelAsync(modelBindingContext);

            var modelBindingResult = modelBindingContext.Result;

            if (modelBindingResult.IsModelSet)
            {
                objectModelValidator.Validate(
                    actionContext,
                    modelBindingContext.ValidationState,
                    modelBindingContext.ModelName,
                    modelBindingResult.Model);

                return(modelState.IsValid);
            }

            return(false);
        }
        private async Task <CustomPropertiesDictionary> BindCore(ModelBindingContext bindingContext)
        {
            var model = bindingContext.Model as CustomPropertiesDictionary ?? new CustomPropertiesDictionary();

            var keys = GetValueProviderKeys(bindingContext.ActionContext, bindingContext.ModelName + "[");

            if (keys.Count == 0)
            {
                return(model);
            }

            foreach (var key in keys)
            {
                var keyName = GetKeyName(key);
                if (keyName == null || model.ContainsKey(keyName))
                {
                    continue;
                }

                var subPropertyName = GetSubPropertyName(key);
                if (subPropertyName.EqualsNoCase("__Type__"))
                {
                    continue;
                }

                ModelMetadata       valueMetadata;
                ModelBindingContext valueBindingContext;

                if (subPropertyName == null)
                {
                    valueMetadata       = _modelMetadataProvider.GetMetadataForType(GetValueType(keys, key, bindingContext.ValueProvider));
                    valueBindingContext = DefaultModelBindingContext.CreateBindingContext(
                        bindingContext.ActionContext,
                        bindingContext.ValueProvider,
                        valueMetadata,
                        bindingInfo: null,
                        modelName: key);
                }
                else
                {
                    // Is Complex type
                    var modelName = key.Substring(0, key.Length - subPropertyName.Length - 1);
                    var valueType = GetValueType(keys, modelName, bindingContext.ValueProvider);
                    if (!valueType.HasAttribute <CustomModelPartAttribute>(false))
                    {
                        throw new SecurityException("For security reasons complex types in '{0}' must be decorated with the '{1}' attribute.".FormatInvariant(
                                                        typeof(CustomPropertiesDictionary).AssemblyQualifiedNameWithoutVersion(),
                                                        typeof(CustomModelPartAttribute).AssemblyQualifiedNameWithoutVersion()));
                    }

                    valueMetadata       = _modelMetadataProvider.GetMetadataForType(valueType);
                    valueBindingContext = DefaultModelBindingContext.CreateBindingContext(
                        bindingContext.ActionContext,
                        bindingContext.ValueProvider,
                        valueMetadata,
                        bindingInfo: null,
                        modelName: key.Substring(0, key.Length - subPropertyName.Length - 1));
                }

                if (valueBindingContext != null)
                {
                    valueBindingContext.PropertyFilter = bindingContext.PropertyFilter;

                    var factoryContext = new ModelBinderFactoryContext {
                        Metadata = valueMetadata
                    };
                    var valueBinder = _modelBinderFactory.CreateBinder(factoryContext);

                    if (valueBinder != null)
                    {
                        await valueBinder.BindModelAsync(valueBindingContext);

                        if (valueBindingContext.Result.IsModelSet)
                        {
                            model[keyName] = valueBindingContext.Result.Model;
                        }
                    }
                }
            }

            return(model);
        }