Example #1
0
        public void EnterNestedScope_FiltersValueProviders_BasedOnTopLevelValueProviders()
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider
            .ForProperty(typeof(string), nameof(string.Length))
            .BindingDetails(b => b.BindingSource = BindingSource.Form);

            var original = CreateDefaultValueProvider();
            var operationBindingContext = new OperationBindingContext()
            {
                ActionContext = new ActionContext(),
                ValueProvider = original,
            };

            var context = DefaultModelBindingContext.CreateBindingContext(
                operationBindingContext,
                metadataProvider.GetMetadataForType(typeof(string)),
                new BindingInfo()
            {
                BindingSource = BindingSource.Query
            },
                "model");

            var propertyMetadata = metadataProvider.GetMetadataForProperty(typeof(string), nameof(string.Length));

            // Act
            context.EnterNestedScope(propertyMetadata, "Length", "Length", model: null);

            // Assert
            Assert.Collection(
                Assert.IsType <CompositeValueProvider>(context.ValueProvider),
                vp => Assert.Same(original[2], vp));
        }
Example #2
0
        private static DefaultModelBindingContext GetModelBindingContext(
            IValueProvider valueProvider,
            bool isReadOnly = false)
        {
            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider
            .ForProperty <ModelWithIListProperty>(nameof(ModelWithIListProperty.ListProperty))
            .BindingDetails(bd => bd.IsReadOnly = isReadOnly);
            var metadata = metadataProvider.GetMetadataForProperty(
                typeof(ModelWithIListProperty),
                nameof(ModelWithIListProperty.ListProperty));

            var bindingContext = new DefaultModelBindingContext
            {
                ModelMetadata           = metadata,
                ModelName               = "someName",
                ModelState              = new ModelStateDictionary(),
                ValueProvider           = valueProvider,
                OperationBindingContext = new OperationBindingContext
                {
                    ModelBinder      = CreateIntBinder(),
                    MetadataProvider = metadataProvider
                },
                ValidationState = new ValidationStateDictionary(),
                FieldName       = "testfieldname",
            };

            return(bindingContext);
        }
Example #3
0
        private static (DefaultModelBindingContext, IModelBinder) GetBinderAndContext(
            Type modelType,
            bool suppressBindingUndefinedValueToEnumType,
            object valueProviderValue)
        {
            var binderProviderContext = new TestModelBinderProviderContext(modelType);
            var modelName             = "theModelName";
            var bindingContext        = new DefaultModelBindingContext
            {
                ModelMetadata = binderProviderContext.Metadata,
                ModelName     = modelName,
                ModelState    = new ModelStateDictionary(),
                ValueProvider = new SimpleValueProvider()
                {
                    { modelName, valueProviderValue }
                }
            };
            var binderProvider = new EnumTypeModelBinderProvider(new MvcOptions
            {
                SuppressBindingUndefinedValueToEnumType = suppressBindingUndefinedValueToEnumType
            });
            var binder = binderProvider.GetBinder(binderProviderContext);

            return(bindingContext, binder);
        }
Example #4
0
        public void CreateBindingContext_FiltersValueProviders_ForValueProviderSource()
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();

            var original = CreateDefaultValueProvider();
            var operationBindingContext = new OperationBindingContext()
            {
                ActionContext = new ActionContext(),
                ValueProvider = original,
            };

            // Act
            var context = DefaultModelBindingContext.CreateBindingContext(
                operationBindingContext,
                metadataProvider.GetMetadataForType(typeof(object)),
                new BindingInfo()
            {
                BindingSource = BindingSource.Query
            },
                "model");

            // Assert
            Assert.Collection(
                Assert.IsType <CompositeValueProvider>(context.ValueProvider),
                vp => Assert.Same(original[1], vp));
        }
Example #5
0
        public void BindAttribute_ProviderType_Cached()
        {
            // Arrange
            var bind = new BindAttribute(typeof(TestProvider));

            var context = new DefaultModelBindingContext();

            context.OperationBindingContext = new OperationBindingContext()
            {
                ActionContext = new ActionContext()
                {
                    HttpContext = new DefaultHttpContext(),
                },
            };

            var services = new Mock <IServiceProvider>(MockBehavior.Strict);

            context.OperationBindingContext.HttpContext.RequestServices = services.Object;

            // Act
            var predicate = bind.PropertyFilter;

            // Assert
            Assert.True(predicate(context, "UserName"));
            Assert.True(predicate(context, "UserName"));
        }
Example #6
0
        public void ModelTypeAreFedFromModelMetadata()
        {
            // Act
            var bindingContext = new DefaultModelBindingContext
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int))
            };

            // Assert
            Assert.Equal(typeof(int), bindingContext.ModelType);
        }
Example #7
0
        public void EnterNestedScope_CopiesProperties()
        {
            // Arrange
            var bindingContext = new DefaultModelBindingContext
            {
                Model                   = new object(),
                ModelMetadata           = new TestModelMetadataProvider().GetMetadataForType(typeof(object)),
                ModelName               = "theName",
                OperationBindingContext = new OperationBindingContext(),
                ValueProvider           = new SimpleValueProvider(),
                ModelState              = new ModelStateDictionary(),
            };

            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider.ForType <object>().BindingDetails(d =>
            {
                d.BindingSource   = BindingSource.Custom;
                d.BinderType      = typeof(TestModelBinder);
                d.BinderModelName = "custom";
            });

            var newModelMetadata = metadataProvider.GetMetadataForType(typeof(object));

            // Act
            var originalBinderModelName         = bindingContext.BinderModelName;
            var originalBinderType              = bindingContext.BinderType;
            var originalBindingSource           = bindingContext.BindingSource;
            var originalModelState              = bindingContext.ModelState;
            var originalOperationBindingContext = bindingContext.OperationBindingContext;
            var originalValueProvider           = bindingContext.ValueProvider;

            var disposable = bindingContext.EnterNestedScope(
                modelMetadata: newModelMetadata,
                fieldName: "fieldName",
                modelName: "modelprefix.fieldName",
                model: null);

            // Assert
            Assert.Same(newModelMetadata.BinderModelName, bindingContext.BinderModelName);
            Assert.Same(newModelMetadata.BinderType, bindingContext.BinderType);
            Assert.Same(newModelMetadata.BindingSource, bindingContext.BindingSource);
            Assert.False(bindingContext.FallbackToEmptyPrefix);
            Assert.Equal("fieldName", bindingContext.FieldName);
            Assert.False(bindingContext.IsTopLevelObject);
            Assert.Null(bindingContext.Model);
            Assert.Same(newModelMetadata, bindingContext.ModelMetadata);
            Assert.Equal("modelprefix.fieldName", bindingContext.ModelName);
            Assert.Same(originalModelState, bindingContext.ModelState);
            Assert.Same(originalOperationBindingContext, bindingContext.OperationBindingContext);
            Assert.Same(originalValueProvider, bindingContext.ValueProvider);

            disposable.Dispose();
        }
Example #8
0
        public void BindAttribute_Include(string property, bool isIncluded)
        {
            // Arrange
            var bind = new BindAttribute(new string[] { "UserName", "FirstName", "LastName, MiddleName,  ,foo,bar " });

            var context = new DefaultModelBindingContext();

            // Act
            var predicate = bind.PropertyFilter;

            // Assert
            Assert.Equal(isIncluded, predicate(context, property));
        }
        public void EnterNestedScope_CopiesProperties()
        {
            // Arrange
            var bindingContext = new DefaultModelBindingContext
            {
                Model = new object(),
                ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)),
                ModelName = "theName",
                OperationBindingContext = new OperationBindingContext(),
                ValueProvider = new SimpleValueProvider(),
                ModelState = new ModelStateDictionary(),
            };

            var metadataProvider = new TestModelMetadataProvider();
            metadataProvider.ForType<object>().BindingDetails(d =>
                {
                    d.BindingSource = BindingSource.Custom;
                    d.BinderType = typeof(TestModelBinder);
                    d.BinderModelName = "custom";
                });

            var newModelMetadata = metadataProvider.GetMetadataForType(typeof(object));

            // Act
            var originalBinderModelName = bindingContext.BinderModelName;
            var originalBindingSource = bindingContext.BindingSource;
            var originalModelState = bindingContext.ModelState;
            var originalOperationBindingContext = bindingContext.OperationBindingContext;
            var originalValueProvider = bindingContext.ValueProvider;

            var disposable = bindingContext.EnterNestedScope(
                modelMetadata: newModelMetadata,
                fieldName: "fieldName",
                modelName: "modelprefix.fieldName",
                model: null);

            // Assert
            Assert.Same(newModelMetadata.BinderModelName, bindingContext.BinderModelName);
            Assert.Same(newModelMetadata.BindingSource, bindingContext.BindingSource);
            Assert.Equal("fieldName", bindingContext.FieldName);
            Assert.False(bindingContext.IsTopLevelObject);
            Assert.Null(bindingContext.Model);
            Assert.Same(newModelMetadata, bindingContext.ModelMetadata);
            Assert.Equal("modelprefix.fieldName", bindingContext.ModelName);
            Assert.Same(originalModelState, bindingContext.ModelState);
            Assert.Same(originalOperationBindingContext, bindingContext.OperationBindingContext);
            Assert.Same(originalValueProvider, bindingContext.ValueProvider);

            disposable.Dispose();
        }
Example #10
0
        private static DefaultModelBindingContext CreateContext()
        {
            var modelBindingContext = new DefaultModelBindingContext()
            {
                OperationBindingContext = new OperationBindingContext()
                {
                    ActionContext = new ActionContext()
                    {
                        HttpContext = new DefaultHttpContext(),
                    },
                    MetadataProvider = new TestModelMetadataProvider(),
                }
            };

            return(modelBindingContext);
        }
        private static DefaultModelBindingContext GetBindingContext(
            Type modelType,
            IEnumerable <IInputFormatter> inputFormatters = null,
            HttpContext httpContext = null,
            IModelMetadataProvider metadataProvider = null)
        {
            if (httpContext == null)
            {
                httpContext = new DefaultHttpContext();
            }

            if (inputFormatters == null)
            {
                inputFormatters = Enumerable.Empty <IInputFormatter>();
            }

            if (metadataProvider == null)
            {
                metadataProvider = new EmptyModelMetadataProvider();
            }

            var operationBindingContext = new OperationBindingContext
            {
                ActionContext = new ActionContext()
                {
                    HttpContext = httpContext,
                },
                InputFormatters  = inputFormatters.ToList(),
                ModelBinder      = new BodyModelBinder(new TestHttpRequestStreamReaderFactory()),
                MetadataProvider = metadataProvider,
            };

            var bindingContext = new DefaultModelBindingContext
            {
                FieldName               = "someField",
                IsTopLevelObject        = true,
                ModelMetadata           = metadataProvider.GetMetadataForType(modelType),
                ModelName               = "someName",
                ValueProvider           = Mock.Of <IValueProvider>(),
                ModelState              = new ModelStateDictionary(),
                OperationBindingContext = operationBindingContext,
                BindingSource           = BindingSource.Body,
            };

            return(bindingContext);
        }
        public void BindAttribute_Include(string property, bool isIncluded)
        {
            // Arrange
            var bind = new BindAttribute(new string[] { "UserName", "FirstName", "LastName, MiddleName,  ,foo,bar " });

            var context = new DefaultModelBindingContext();

            var identity = ModelMetadataIdentity.ForProperty(typeof(int), property, typeof(string));

            context.ModelMetadata = new Mock <ModelMetadata>(identity).Object;

            // Act
            var propertyFilter = bind.PropertyFilter;

            // Assert
            Assert.Equal(isIncluded, propertyFilter(context.ModelMetadata));
        }
        private static DefaultModelBindingContext GetBindingContext(Type modelType)
        {
            var metadataProvider = new EmptyModelMetadataProvider();
            DefaultModelBindingContext bindingContext = new DefaultModelBindingContext
            {
                ActionContext = new ActionContext()
                {
                    HttpContext = new DefaultHttpContext(),
                },
                ModelMetadata = metadataProvider.GetMetadataForType(modelType),
                ModelName = "someName",
                ValidationState = new ValidationStateDictionary(),
            };

            bindingContext.HttpContext.Request.Method = "GET";

            return bindingContext;
        }
Example #14
0
        private static DefaultModelBindingContext GetBindingContext(Type modelType, HttpContext httpContext)
        {
            var metadataProvider = new EmptyModelMetadataProvider();
            var bindingContext   = new DefaultModelBindingContext
            {
                ModelMetadata           = metadataProvider.GetMetadataForType(modelType),
                ModelName               = "file",
                OperationBindingContext = new OperationBindingContext
                {
                    ActionContext = new ActionContext()
                    {
                        HttpContext = httpContext,
                    },
                    ModelBinder      = new FormCollectionModelBinder(),
                    MetadataProvider = metadataProvider,
                },
                ValidationState = new ValidationStateDictionary(),
            };

            return(bindingContext);
        }
Example #15
0
        private static DefaultModelBindingContext GetBindingContext(Type modelType)
        {
            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Services);
            var modelMetadata = metadataProvider.GetMetadataForType(modelType);


            var services = new ServiceCollection();

            services.AddSingleton <IService>(new Service());

            var bindingContext = new DefaultModelBindingContext
            {
                ModelMetadata           = modelMetadata,
                ModelName               = "modelName",
                FieldName               = "modelName",
                ModelState              = new ModelStateDictionary(),
                OperationBindingContext = new OperationBindingContext
                {
                    ActionContext = new ActionContext()
                    {
                        HttpContext = new DefaultHttpContext()
                        {
                            RequestServices = services.BuildServiceProvider(),
                        }
                    },
                    ModelBinder      = new HeaderModelBinder(),
                    MetadataProvider = metadataProvider,
                },
                BinderModelName = modelMetadata.BinderModelName,
                BindingSource   = modelMetadata.BindingSource,
                ValidationState = new ValidationStateDictionary(),
            };

            return(bindingContext);
        }
        private static DefaultModelBindingContext GetBindingContext(
            IModelMetadataProvider metadataProvider,
            ModelMetadata metadata,
            HttpContext httpContext)
        {
            var bindingContext = new DefaultModelBindingContext
            {
                ModelMetadata           = metadata,
                ModelName               = "file",
                ModelState              = new ModelStateDictionary(),
                OperationBindingContext = new OperationBindingContext
                {
                    ActionContext = new ActionContext()
                    {
                        HttpContext = httpContext,
                    },
                    ModelBinder      = new FormFileModelBinder(),
                    MetadataProvider = metadataProvider,
                },
                ValidationState = new ValidationStateDictionary(),
            };

            return(bindingContext);
        }
Example #17
0
        public void BindAttribute_ProviderType(string property, bool isIncluded)
        {
            // Arrange
            var bind = new BindAttribute(typeof(TestProvider));

            var context = new DefaultModelBindingContext();

            context.OperationBindingContext = new OperationBindingContext()
            {
                ActionContext = new ActionContext()
                {
                    HttpContext = new DefaultHttpContext(),
                },
            };
            var services = new Mock <IServiceProvider>();

            context.OperationBindingContext.HttpContext.RequestServices = services.Object;

            // Act
            var predicate = bind.PropertyFilter;

            // Assert
            Assert.Equal(isIncluded, predicate(context, property));
        }
Example #18
0
        /// <summary>
        /// Updates the specified <paramref name="model"/> instance using the specified <paramref name="modelBinder"/>
        /// and the specified <paramref name="valueProvider"/> and executes validation using the specified
        /// <paramref name="validatorProvider"/>.
        /// </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="modelBinder">The <see cref="IModelBinder"/> used for binding.</param>
        /// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
        /// <param name="inputFormatters">
        /// The set of <see cref="IInputFormatter"/> instances for deserializing the body.
        /// </param>
        /// <param name="objectModelValidator">The <see cref="IObjectModelValidator"/> used for validating the
        /// bound values.</param>
        /// <param name="validatorProvider">The <see cref="IModelValidatorProvider"/> used for executing validation
        /// on the model instance.</param>
        /// <param name="predicate">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,
            IModelBinder modelBinder,
            IValueProvider valueProvider,
            IList <IInputFormatter> inputFormatters,
            IObjectModelValidator objectModelValidator,
            IModelValidatorProvider validatorProvider,
            Func <ModelBindingContext, string, bool> predicate)
        {
            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 (modelBinder == null)
            {
                throw new ArgumentNullException(nameof(modelBinder));
            }

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

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

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

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

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

            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 operationBindingContext = new OperationBindingContext
            {
                InputFormatters   = inputFormatters,
                ModelBinder       = modelBinder,
                ValidatorProvider = validatorProvider,
                MetadataProvider  = metadataProvider,
                ActionContext     = actionContext,
                ValueProvider     = valueProvider,
            };

            var modelBindingContext = DefaultModelBindingContext.CreateBindingContext(
                operationBindingContext,
                modelMetadata,
                bindingInfo: null,
                modelName: prefix ?? string.Empty);

            modelBindingContext.Model          = model;
            modelBindingContext.PropertyFilter = predicate;

            await modelBinder.BindModelAsync(modelBindingContext);

            var modelBindingResult = modelBindingContext.Result;

            if (modelBindingResult != null && modelBindingResult.Value.IsModelSet)
            {
                objectModelValidator.Validate(
                    operationBindingContext.ActionContext,
                    operationBindingContext.ValidatorProvider,
                    modelBindingContext.ValidationState,
                    modelBindingResult.Value.Key,
                    modelBindingResult.Value.Model);

                return(modelState.IsValid);
            }

            return(false);
        }
        /// <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="modelBinder">The <see cref="IModelBinder"/>.</param>
        /// <param name="valueProvider">The <see cref="IValueProvider"/>.</param>
        /// <param name="parameter">The <see cref="ParameterDescriptor"/></param>
        /// <param name="metadata">The <see cref="ModelMetadata"/>.</param>
        /// <param name="value">The initial model value.</param>
        /// <returns>The result of model binding.</returns>
        public virtual async Task <ModelBindingResult> BindModelAsync(
            ActionContext actionContext,
            IModelBinder modelBinder,
            IValueProvider valueProvider,
            ParameterDescriptor parameter,
            ModelMetadata metadata,
            object value)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException(nameof(actionContext));
            }

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

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

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

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

            if (parameter.BindingInfo?.RequestPredicate?.Invoke(actionContext) == false)
            {
                return(ModelBindingResult.Failed());
            }

            var modelBindingContext = DefaultModelBindingContext.CreateBindingContext(
                actionContext,
                valueProvider,
                metadata,
                parameter.BindingInfo,
                parameter.Name);

            modelBindingContext.Model = value;

            var parameterModelName = parameter.BindingInfo?.BinderModelName ?? metadata.BinderModelName;

            if (parameterModelName != null)
            {
                // The name was set explicitly, always use that as the prefix.
                modelBindingContext.ModelName = parameterModelName;
            }
            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;
            }

            await modelBinder.BindModelAsync(modelBindingContext);

            var modelBindingResult = modelBindingContext.Result;

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

            return(modelBindingResult);
        }
Example #20
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="modelBinder">The <see cref="IModelBinder"/>.</param>
        /// <param name="valueProvider">The <see cref="IValueProvider"/>.</param>
        /// <param name="parameter">The <see cref="ParameterDescriptor"/></param>
        /// <param name="metadata">The <see cref="ModelMetadata"/>.</param>
        /// <param name="value">The initial model value.</param>
        /// <returns>The result of model binding.</returns>
        public virtual async Task <ModelBindingResult> BindModelAsync(
            ActionContext actionContext,
            IModelBinder modelBinder,
            IValueProvider valueProvider,
            ParameterDescriptor parameter,
            ModelMetadata metadata,
            object value)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException(nameof(actionContext));
            }

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

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

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

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

            if (parameter.BindingInfo?.RequestPredicate?.Invoke(actionContext) == false)
            {
                return(ModelBindingResult.Failed());
            }

            var modelBindingContext = DefaultModelBindingContext.CreateBindingContext(
                actionContext,
                valueProvider,
                metadata,
                parameter.BindingInfo,
                parameter.Name);

            modelBindingContext.Model = value;

            var parameterModelName = parameter.BindingInfo?.BinderModelName ?? metadata.BinderModelName;

            if (parameterModelName != null)
            {
                // The name was set explicitly, always use that as the prefix.
                modelBindingContext.ModelName = parameterModelName;
            }
            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;
            }

            await modelBinder.BindModelAsync(modelBindingContext);

            var modelBindingResult = modelBindingContext.Result;

            if (_validatorForBackCompatOnly != null)
            {
                // Since we don't have access to an IModelValidatorProvider, fall back
                // on back-compatibility logic. In this scenario, top-level validation
                // attributes will be ignored like they were historically.
                if (modelBindingResult.IsModelSet)
                {
                    _validatorForBackCompatOnly.Validate(
                        actionContext,
                        modelBindingContext.ValidationState,
                        modelBindingContext.ModelName,
                        modelBindingResult.Model);
                }
            }
            else
            {
                EnforceBindRequiredAndValidate(
                    actionContext,
                    metadata,
                    modelBindingContext,
                    modelBindingResult);
            }

            return(modelBindingResult);
        }
        public void ModelTypeAreFedFromModelMetadata()
        {
            // Act
            var bindingContext = new DefaultModelBindingContext
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int))
            };

            // Assert
            Assert.Equal(typeof(int), bindingContext.ModelType);
        }
Example #22
0
        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);

            if (modelMetadata.BoundConstructor != null)
            {
                throw new NotSupportedException(Resources.FormatTryUpdateModel_RecordTypeNotSupported(nameof(TryUpdateModelAsync), 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);
        }
Example #23
0
        /// <summary>
        /// Creates a new <see cref="DefaultModelBindingContext"/> for top-level model binding operation.
        /// </summary>
        /// <param name="actionContext">
        /// The <see cref="ActionContext"/> associated with the binding operation.
        /// </param>
        /// <param name="valueProvider">The <see cref="IValueProvider"/> to use for binding.</param>
        /// <param name="metadata"><see cref="ModelMetadata"/> associated with the model.</param>
        /// <param name="bindingInfo"><see cref="BindingInfo"/> associated with the model.</param>
        /// <param name="modelName">The name of the property or parameter being bound.</param>
        /// <returns>A new instance of <see cref="DefaultModelBindingContext"/>.</returns>
        public static ModelBindingContext CreateBindingContext(
            ActionContext actionContext,
            IValueProvider valueProvider,
            ModelMetadata metadata,
            BindingInfo bindingInfo,
            string modelName)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException(nameof(actionContext));
            }

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

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

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

            var binderModelName        = bindingInfo?.BinderModelName ?? metadata.BinderModelName;
            var bindingSource          = bindingInfo?.BindingSource ?? metadata.BindingSource;
            var propertyFilterProvider = bindingInfo?.PropertyFilterProvider ?? metadata.PropertyFilterProvider;

            var bindingContext = new DefaultModelBindingContext()
            {
                ActionContext   = actionContext,
                BinderModelName = binderModelName,
                BindingSource   = bindingSource,
                PropertyFilter  = propertyFilterProvider?.PropertyFilter,
                ValidationState = new ValidationStateDictionary(),

                // Because this is the top-level context, FieldName and ModelName should be the same.
                FieldName         = binderModelName ?? modelName,
                ModelName         = binderModelName ?? modelName,
                OriginalModelName = binderModelName ?? modelName,

                IsTopLevelObject = true,
                ModelMetadata    = metadata,
                ModelState       = actionContext.ModelState,

                OriginalValueProvider = valueProvider,
                ValueProvider         = FilterValueProvider(valueProvider, bindingSource),
            };

            // mvcOptions may be null when this method is called in test scenarios.
            var mvcOptions = actionContext.HttpContext.RequestServices?.GetService <IOptions <MvcOptions> >();

            if (mvcOptions != null)
            {
                bindingContext.MaxModelBindingRecursionDepth = mvcOptions.Value.MaxModelBindingRecursionDepth;
            }

            return(bindingContext);
        }
Example #24
0
        public void ModelMetadataProvider_UsesPropertyFilterProviderOnType()
        {
            // Arrange
            var type = typeof(User);

            var provider = CreateProvider();
            var context = new DefaultModelBindingContext();

            var expected = new[] { "IsAdmin", "UserName" };

            // Act
            var metadata = provider.GetMetadataForType(type);

            // Assert
            var propertyFilter = metadata.PropertyFilterProvider.PropertyFilter;

            var matched = new HashSet<string>();
            foreach (var property in metadata.Properties)
            {
                if (propertyFilter(property))
                {
                    matched.Add(property.PropertyName);
                }
            }

            Assert.Equal<string>(expected, matched);
        }
Example #25
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="modelBinder">The <see cref="IModelBinder"/>.</param>
        /// <param name="valueProvider">The <see cref="IValueProvider"/>.</param>
        /// <param name="parameter">The <see cref="ParameterDescriptor"/></param>
        /// <param name="metadata">The <see cref="ModelMetadata"/>.</param>
        /// <param name="value">The initial model value.</param>
        /// <returns>The result of model binding.</returns>
        public virtual async Task <ModelBindingResult> BindModelAsync(
            ActionContext actionContext,
            IModelBinder modelBinder,
            IValueProvider valueProvider,
            ParameterDescriptor parameter,
            ModelMetadata metadata,
            object value)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException(nameof(actionContext));
            }

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

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

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

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

            if (parameter.BindingInfo?.RequestPredicate?.Invoke(actionContext) == false)
            {
                return(ModelBindingResult.Failed());
            }

            var modelBindingContext = DefaultModelBindingContext.CreateBindingContext(
                actionContext,
                valueProvider,
                metadata,
                parameter.BindingInfo,
                parameter.Name);

            modelBindingContext.Model = value;

            Logger.AttemptingToBindParameterOrProperty(parameter, modelBindingContext);

            var parameterModelName = parameter.BindingInfo?.BinderModelName ?? metadata.BinderModelName;

            if (parameterModelName != null)
            {
                // The name was set explicitly, always use that as the prefix.
                modelBindingContext.ModelName = parameterModelName;
            }
            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;
            }

            await modelBinder.BindModelAsync(modelBindingContext);

            Logger.DoneAttemptingToBindParameterOrProperty(parameter, modelBindingContext);

            var modelBindingResult = modelBindingContext.Result;

            if (_mvcOptions.AllowValidatingTopLevelNodes &&
                _objectModelValidator is ObjectModelValidator baseObjectValidator)
            {
                Logger.AttemptingToValidateParameterOrProperty(parameter, modelBindingContext);

                EnforceBindRequiredAndValidate(
                    baseObjectValidator,
                    actionContext,
                    parameter,
                    metadata,
                    modelBindingContext,
                    modelBindingResult);

                Logger.DoneAttemptingToValidateParameterOrProperty(parameter, modelBindingContext);
            }
            else
            {
                // For legacy implementations (which directly implemented IObjectModelValidator), fall back to the
                // back-compatibility logic. In this scenario, top-level validation attributes will be ignored like
                // they were historically.
                if (modelBindingResult.IsModelSet)
                {
                    _objectModelValidator.Validate(
                        actionContext,
                        modelBindingContext.ValidationState,
                        modelBindingContext.ModelName,
                        modelBindingResult.Model);
                }
            }

            return(modelBindingResult);
        }