public bool BindModel(ControllerContext controllerContext, ExtensibleModelBindingContext bindingContext)
        {
            ModelBinderUtil.ValidateBindingContext(bindingContext, typeof(ComplexModelDto), false /* allowNullModel */);

            ComplexModelDto dto = (ComplexModelDto)bindingContext.Model;

            foreach (ModelMetadata propertyMetadata in dto.PropertyMetadata)
            {
                ExtensibleModelBindingContext propertyBindingContext = new ExtensibleModelBindingContext(bindingContext)
                {
                    ModelMetadata = propertyMetadata,
                    ModelName     = ModelBinderUtil.CreatePropertyModelName(bindingContext.ModelName, propertyMetadata.PropertyName)
                };

                // bind and propagate the values
                IExtensibleModelBinder propertyBinder = bindingContext.ModelBinderProviders.GetBinder(controllerContext, propertyBindingContext);
                if (propertyBinder != null)
                {
                    if (propertyBinder.BindModel(controllerContext, propertyBindingContext))
                    {
                        dto.Results[propertyMetadata] = new ComplexModelDtoResult(propertyBindingContext.Model, propertyBindingContext.ValidationNode);
                    }
                    else
                    {
                        dto.Results[propertyMetadata] = null;
                    }
                }
            }

            return(true);
        }
        private ComplexModelDto CreateAndPopulateDto(
            ControllerContext controllerContext,
            ExtensibleModelBindingContext bindingContext,
            IEnumerable <ModelMetadata> propertyMetadatas
            )
        {
            // create a DTO and call into the DTO binder
            ComplexModelDto originalDto = new ComplexModelDto(
                bindingContext.ModelMetadata,
                propertyMetadatas
                );
            ExtensibleModelBindingContext dtoBindingContext = new ExtensibleModelBindingContext(
                bindingContext
                )
            {
                ModelMetadata = MetadataProvider.GetMetadataForType(
                    () => originalDto,
                    typeof(ComplexModelDto)
                    ),
                ModelName = bindingContext.ModelName
            };

            IExtensibleModelBinder dtoBinder =
                bindingContext.ModelBinderProviders.GetRequiredBinder(
                    controllerContext,
                    dtoBindingContext
                    );

            dtoBinder.BindModel(controllerContext, dtoBindingContext);
            return((ComplexModelDto)dtoBindingContext.Model);
        }
        private ComplexModelDto CreateAndPopulateDto(ControllerContext controllerContext, ExtensibleModelBindingContext bindingContext, IEnumerable<ModelMetadata> propertyMetadatas) {
            // create a DTO and call into the DTO binder
            ComplexModelDto originalDto = new ComplexModelDto(bindingContext.ModelMetadata, propertyMetadatas);
            ExtensibleModelBindingContext dtoBindingContext = new ExtensibleModelBindingContext(bindingContext) {
                ModelMetadata = MetadataProvider.GetMetadataForType(() => originalDto, typeof(ComplexModelDto)),
                ModelName = bindingContext.ModelName
            };

            IExtensibleModelBinder dtoBinder = bindingContext.ModelBinderProviders.GetRequiredBinder(controllerContext, dtoBindingContext);
            dtoBinder.BindModel(controllerContext, dtoBindingContext);
            return (ComplexModelDto)dtoBindingContext.Model;
        }
        public virtual bool BindModel(ControllerContext controllerContext, ExtensibleModelBindingContext bindingContext)
        {
            ModelBinderUtil.ValidateBindingContext(bindingContext);

            EnsureModel(controllerContext, bindingContext);
            IEnumerable <ModelMetadata> propertyMetadatas = GetMetadataForProperties(controllerContext, bindingContext);
            ComplexModelDto             dto = CreateAndPopulateDto(controllerContext, bindingContext, propertyMetadatas);

            // post-processing, e.g. property setters and hooking up validation
            ProcessDto(controllerContext, bindingContext, dto);
            bindingContext.ValidationNode.ValidateAllProperties = true; // complex models require full validation
            return(true);
        }
        internal void ProcessDto(
            ControllerContext controllerContext,
            ExtensibleModelBindingContext bindingContext,
            ComplexModelDto dto
            )
        {
            HashSet <string> requiredProperties;
            HashSet <string> skipProperties;

            GetRequiredPropertiesCollection(
                bindingContext.ModelType,
                out requiredProperties,
                out skipProperties
                );

            // Are all of the required fields accounted for?
            HashSet <string> missingRequiredProperties = new HashSet <string>(requiredProperties);

            missingRequiredProperties.ExceptWith(dto.Results.Select(r => r.Key.PropertyName));
            string missingPropertyName = missingRequiredProperties.FirstOrDefault();

            if (missingPropertyName != null)
            {
                string fullPropertyKey = ModelBinderUtil.CreatePropertyModelName(
                    bindingContext.ModelName,
                    missingPropertyName
                    );
                throw Error.BindingBehavior_ValueNotFound(fullPropertyKey);
            }

            // for each property that was bound, call the setter, recording exceptions as necessary
            foreach (var entry in dto.Results)
            {
                ModelMetadata propertyMetadata = entry.Key;

                ComplexModelDtoResult dtoResult = entry.Value;
                if (dtoResult != null)
                {
                    SetProperty(controllerContext, bindingContext, propertyMetadata, dtoResult);
                    bindingContext.ValidationNode.ChildNodes.Add(dtoResult.ValidationNode);
                }
            }
        }
        internal void ProcessDto(ControllerContext controllerContext, ExtensibleModelBindingContext bindingContext, ComplexModelDto dto)
        {
            HashSet<string> requiredProperties;
            HashSet<string> skipProperties;
            GetRequiredPropertiesCollection(bindingContext.ModelType, out requiredProperties, out skipProperties);

            // Are all of the required fields accounted for?
            HashSet<string> missingRequiredProperties = new HashSet<string>(requiredProperties);
            missingRequiredProperties.ExceptWith(dto.Results.Select(r => r.Key.PropertyName));
            string missingPropertyName = missingRequiredProperties.FirstOrDefault();
            if (missingPropertyName != null)
            {
                string fullPropertyKey = ModelBinderUtil.CreatePropertyModelName(bindingContext.ModelName, missingPropertyName);
                throw Error.BindingBehavior_ValueNotFound(fullPropertyKey);
            }

            // for each property that was bound, call the setter, recording exceptions as necessary
            foreach (var entry in dto.Results)
            {
                ModelMetadata propertyMetadata = entry.Key;

                ComplexModelDtoResult dtoResult = entry.Value;
                if (dtoResult != null)
                {
                    SetProperty(controllerContext, bindingContext, propertyMetadata, dtoResult);
                    bindingContext.ValidationNode.ChildNodes.Add(dtoResult.ValidationNode);
                }
            }
        }