public virtual async Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);
            if (!CanBindType(bindingContext.ModelType))
            {
                return null;
            }

            var mutableObjectBinderContext = new MutableObjectBinderContext()
            {
                ModelBindingContext = bindingContext,
                PropertyMetadata = GetMetadataForProperties(bindingContext),
            };

            if (!(await CanCreateModel(mutableObjectBinderContext)))
            {
                return null;
            }

            EnsureModel(bindingContext);
            var result = await CreateAndPopulateDto(bindingContext, mutableObjectBinderContext.PropertyMetadata);

            // post-processing, e.g. property setters and hooking up validation
            ProcessDto(bindingContext, (ComplexModelDto)result.Model);
            return new ModelBindingResult(
                bindingContext.Model,
                bindingContext.ModelName,
                isModelSet: true);
        }
Exemplo n.º 2
0
        public virtual async Task <bool> BindModelAsync(ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);
            if (!CanBindType(bindingContext.ModelType))
            {
                return(false);
            }

            var mutableObjectBinderContext = new MutableObjectBinderContext()
            {
                ModelBindingContext = bindingContext,
                PropertyMetadata    = GetMetadataForProperties(bindingContext),
            };

            if (!(await CanCreateModel(mutableObjectBinderContext)))
            {
                return(false);
            }

            EnsureModel(bindingContext);
            var dto = await CreateAndPopulateDto(bindingContext, mutableObjectBinderContext.PropertyMetadata);

            // post-processing, e.g. property setters and hooking up validation
            ProcessDto(bindingContext, dto);
            // complex models require full validation
            bindingContext.ValidationNode.ValidateAllProperties = true;
            return(true);
        }
Exemplo n.º 3
0
        /// <inheritdoc />
        public virtual async Task <ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);
            if (!CanBindType(bindingContext.ModelMetadata))
            {
                return(null);
            }

            var mutableObjectBinderContext = new MutableObjectBinderContext()
            {
                ModelBindingContext = bindingContext,
                PropertyMetadata    = GetMetadataForProperties(bindingContext),
            };

            if (!(await CanCreateModel(mutableObjectBinderContext)))
            {
                return(null);
            }

            EnsureModel(bindingContext);
            var result = await CreateAndPopulateDto(bindingContext, mutableObjectBinderContext.PropertyMetadata);

            var validationNode = new ModelValidationNode(
                bindingContext.ModelName,
                bindingContext.ModelMetadata,
                bindingContext.Model);

            // post-processing, e.g. property setters and hooking up validation
            ProcessDto(bindingContext, (ComplexModelDto)result.Model, validationNode);
            return(new ModelBindingResult(
                       bindingContext.Model,
                       bindingContext.ModelName,
                       isModelSet: true,
                       validationNode: validationNode));
        }
        public void CanCreateModel_ReturnsFalse_IfNotIsTopLevelObjectAndModelIsMarkedWithBinderMetadata()
        {
            // Get the property metadata so that it is not a top level object.
            var modelMetadata = GetMetadataForType(typeof(Document))
                .Properties
                .First(metadata => metadata.PropertyName == nameof(Document.SubDocument));
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    ModelMetadata = modelMetadata,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                    },
                    BindingSource = modelMetadata.BindingSource,
                    BinderModelName = modelMetadata.BinderModelName,
                    ModelState = new ModelStateDictionary(),
                },
            };

            var mutableBinder = new MutableObjectModelBinder();

            // Act
            var canCreate = mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.False(canCreate);
        }
Exemplo n.º 5
0
        /// <inheritdoc />
        public Task <ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }

            ModelBindingHelper.ValidateBindingContext(bindingContext);
            if (!CanBindType(bindingContext.ModelMetadata))
            {
                return(ModelBindingResult.NoResultAsync);
            }

            var mutableObjectBinderContext = new MutableObjectBinderContext()
            {
                ModelBindingContext = bindingContext,
                PropertyMetadata    = GetMetadataForProperties(bindingContext).ToArray(),
            };

            if (!(CanCreateModel(mutableObjectBinderContext)))
            {
                return(ModelBindingResult.NoResultAsync);
            }

            return(BindModelCoreAsync(bindingContext, mutableObjectBinderContext));
        }
Exemplo n.º 6
0
        internal async Task <bool> CanCreateModel(MutableObjectBinderContext context)
        {
            var bindingContext   = context.ModelBindingContext;
            var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;
            var hasExplicitAlias = bindingContext.ModelMetadata.BinderModelName != null;

            // The fact that this has reached here,
            // it is a complex object which was not directly bound by any previous model binders.
            // Check if this was supposed to be handled by a non value provider based binder.
            // if it was then it should be not be bound using mutable object binder.
            // This check would prevent it from recursing in if a model contains a property of its own type.
            // We skip this check if it is a top level object because we want to always evaluate
            // the creation of top level object (this is also required for ModelBinderAttribute to work.)
            if (!isTopLevelObject &&
                bindingContext.ModelMetadata.BinderMetadata != null &&
                !(bindingContext.ModelMetadata.BinderMetadata is IValueProviderMetadata))
            {
                return(false);
            }

            // Create the object if :
            // 1. It is a top level model with an explicit user supplied prefix.
            //    In this case since it will never fallback to empty prefix, we need to create the model here.
            if (isTopLevelObject && hasExplicitAlias)
            {
                return(true);
            }

            // 2. It is a top level object and there is no model name ( Fallback to empty prefix case ).
            //    This is necessary as we do not want to depend on a value provider to contain an empty prefix.
            if (isTopLevelObject && bindingContext.ModelName == string.Empty)
            {
                return(true);
            }

            // 3. The model name is not prefixed and a value provider can directly provide a value for the model name.
            //    The fact that it is not prefixed means that the containsPrefixAsync call checks for the exact
            //    model name instead of doing a prefix match.
            if (!bindingContext.ModelName.Contains(".") &&
                await bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName))
            {
                return(true);
            }

            // 4. Any of the model properties can be bound using a value provider.
            if (await CanValueBindAnyModelProperties(context))
            {
                return(true);
            }

            return(false);
        }
Exemplo n.º 7
0
        internal async Task <bool> CanCreateModel(MutableObjectBinderContext context)
        {
            var bindingContext = context.ModelBindingContext;

            var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;
            var hasExplicitAlias = bindingContext.BinderModelName != null;

            // If we get here the model is a complex object which was not directly bound by any previous model binder,
            // so we want to decide if we want to continue binding. This is important to get right to avoid infinite
            // recursion.
            //
            // First, we want to make sure this object is allowed to come from a value provider source as this binder
            // will always include value provider data. For instance if the model is marked with [FromBody], then we
            // can just skip it. A greedy source cannot be a value provider.
            //
            // If the model isn't marked with ANY binding source, then we assume it's ok also.
            //
            // We skip this check if it is a top level object because we want to always evaluate
            // the creation of top level object (this is also required for ModelBinderAttribute to work.)
            var bindingSource = bindingContext.BindingSource;

            if (!isTopLevelObject &&
                bindingSource != null &&
                bindingSource.IsGreedy)
            {
                return(false);
            }

            // Create the object if :
            // 1. It is a top level model with an explicit user supplied prefix.
            //    In this case since it will never fallback to empty prefix, we need to create the model here.
            if (isTopLevelObject && hasExplicitAlias)
            {
                return(true);
            }

            // 2. It is a top level object and there is no model name ( Fallback to empty prefix case ).
            //    This is necessary as we do not want to depend on a value provider to contain an empty prefix.
            if (isTopLevelObject && bindingContext.ModelName == string.Empty)
            {
                return(true);
            }

            // 3. Any of the model properties can be bound using a value provider.
            if (await CanValueBindAnyModelProperties(context))
            {
                return(true);
            }

            return(false);
        }
        internal async Task<bool> CanCreateModel(MutableObjectBinderContext context)
        {
            var bindingContext = context.ModelBindingContext;

            var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;
            var hasExplicitAlias = bindingContext.BinderModelName != null;

            // If we get here the model is a complex object which was not directly bound by any previous model binder,
            // so we want to decide if we want to continue binding. This is important to get right to avoid infinite
            // recursion.
            //
            // First, we want to make sure this object is allowed to come from a value provider source as this binder
            // will always include value provider data. For instance if the model is marked with [FromBody], then we
            // can just skip it. A greedy source cannot be a value provider.
            //
            // If the model isn't marked with ANY binding source, then we assume it's ok also.
            //
            // We skip this check if it is a top level object because we want to always evaluate
            // the creation of top level object (this is also required for ModelBinderAttribute to work.)
            var bindingSource = bindingContext.BindingSource;
            if (!isTopLevelObject &&
                bindingSource != null &&
                bindingSource.IsGreedy)
            {
                return false;
            }

            // Create the object if :
            // 1. It is a top level model with an explicit user supplied prefix.
            //    In this case since it will never fallback to empty prefix, we need to create the model here.
            if (isTopLevelObject && hasExplicitAlias)
            {
                return true;
            }

            // 2. It is a top level object and there is no model name ( Fallback to empty prefix case ).
            //    This is necessary as we do not want to depend on a value provider to contain an empty prefix.
            if (isTopLevelObject && bindingContext.ModelName == string.Empty)
            {
                return true;
            }

            // 3. Any of the model properties can be bound using a value provider.
            if (await CanValueBindAnyModelProperties(context))
            {
                return true;
            }

            return false;
        }
Exemplo n.º 9
0
        private async Task <ModelBindingResult> BindModelCoreAsync(
            ModelBindingContext bindingContext,
            MutableObjectBinderContext mutableObjectBinderContext)
        {
            // Create model first (if necessary) to avoid reporting errors about properties when activation fails.
            var model = GetModel(bindingContext);

            var results = await BindPropertiesAsync(bindingContext, mutableObjectBinderContext.PropertyMetadata);

            // Post-processing e.g. property setters and hooking up validation.
            bindingContext.Model = model;
            ProcessResults(bindingContext, results);

            return(ModelBindingResult.Success(bindingContext.ModelName, model));
        }
        public async Task CanCreateModel_ReturnsTrue_IfIsTopLevelObjectAndNotIsFirstChanceBinding(
            bool isTopLevelObject,
            bool isFirstChanceBinding,
            string binderModelName,
            string modelName,
            bool expectedCanCreate)
        {
            var mockValueProvider = new Mock<IValueProvider>();
            mockValueProvider
                .Setup(o => o.ContainsPrefixAsync(It.IsAny<string>()))
                .Returns(Task.FromResult(false));

            var metadataProvider = new TestModelMetadataProvider();
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    IsTopLevelObject = isTopLevelObject,
                    IsFirstChanceBinding = isFirstChanceBinding,

                    // Random type.
                    ModelMetadata = metadataProvider.GetMetadataForType(typeof(Person)),
                    ValueProvider = mockValueProvider.Object,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValueProvider = mockValueProvider.Object,
                        MetadataProvider = metadataProvider,
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                    },

                    // CanCreateModel() ignores the BinderModelName and ModelName properties.
                    BinderModelName = binderModelName,
                    ModelName = modelName,
                },
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata =
                mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray();

            // Act
            var canCreate = await mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.Equal(expectedCanCreate, canCreate);
        }
Exemplo n.º 11
0
        internal bool CanCreateModel(MutableObjectBinderContext context)
        {
            var bindingContext   = context.ModelBindingContext;
            var isTopLevelObject = bindingContext.IsTopLevelObject;

            // If we get here the model is a complex object which was not directly bound by any previous model binder,
            // so we want to decide if we want to continue binding. This is important to get right to avoid infinite
            // recursion.
            //
            // First, we want to make sure this object is allowed to come from a value provider source as this binder
            // will always include value provider data. For instance if the model is marked with [FromBody], then we
            // can just skip it. A greedy source cannot be a value provider.
            //
            // If the model isn't marked with ANY binding source, then we assume it's OK also.
            //
            // We skip this check if it is a top level object because we want to always evaluate
            // the creation of top level object (this is also required for ModelBinderAttribute to work.)
            var bindingSource = bindingContext.BindingSource;

            if (!isTopLevelObject && bindingSource != null && bindingSource.IsGreedy)
            {
                return(false);
            }

            // Create the object if:
            // 1. It is a top level model.
            if (isTopLevelObject)
            {
                return(true);
            }

            // 2. If it is top level object and there are no properties to bind
            if (isTopLevelObject && context.PropertyMetadata != null && context.PropertyMetadata.Count == 0)
            {
                return(true);
            }

            // 3. Any of the model properties can be bound using a value provider.
            if (CanValueBindAnyModelProperties(context))
            {
                return(true);
            }

            return(false);
        }
Exemplo n.º 12
0
        /// <inheritdoc />
        public virtual async Task <ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);
            if (!CanBindType(bindingContext.ModelMetadata))
            {
                return(null);
            }

            var mutableObjectBinderContext = new MutableObjectBinderContext()
            {
                ModelBindingContext = bindingContext,
                PropertyMetadata    = GetMetadataForProperties(bindingContext).ToArray(),
            };

            if (!(await CanCreateModel(mutableObjectBinderContext)))
            {
                return(null);
            }

            // Create model first (if necessary) to avoid reporting errors about properties when activation fails.
            var model = GetModel(bindingContext);

            var results = await BindPropertiesAsync(bindingContext, mutableObjectBinderContext.PropertyMetadata);

            var validationNode = new ModelValidationNode(
                bindingContext.ModelName,
                bindingContext.ModelMetadata,
                model);

            // Post-processing e.g. property setters and hooking up validation.
            bindingContext.Model = model;
            ProcessResults(bindingContext, results, validationNode);

            return(new ModelBindingResult(
                       model,
                       bindingContext.ModelName,
                       isModelSet: true,
                       validationNode: validationNode));
        }
        public async Task CanCreateModel_CreatesModel_ForTopLevelObjectIfThereIsExplicitPrefix(
            Type modelType,
            bool isPrefixProvided)
        {
            var mockValueProvider = new Mock<IValueProvider>();
            mockValueProvider.Setup(o => o.ContainsPrefixAsync(It.IsAny<string>()))
                             .Returns(Task.FromResult(false));

            var metadataProvider = new TestModelMetadataProvider();
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    // Random type.
                    ModelMetadata = metadataProvider.GetMetadataForType(typeof(Person)),
                    ValueProvider = mockValueProvider.Object,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValueProvider = mockValueProvider.Object,
                        MetadataProvider = metadataProvider,
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                    },

                    // Setting it to empty ensures that model does not get created becasue of no model name.
                    ModelName = "dummyModelName",
                    BinderModelName = isPrefixProvided ? "prefix" : null,
                }
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata = mutableBinder.GetMetadataForProperties(
                                                                bindingContext.ModelBindingContext);

            // Act
            var retModel = await mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.Equal(isPrefixProvided, retModel);
        }
        public void CanCreateModel_ReturnsTrue_IfIsTopLevelObject(
            bool isTopLevelObject,
            bool expectedCanCreate)
        {
            var mockValueProvider = new Mock<IValueProvider>();
            mockValueProvider
                .Setup(o => o.ContainsPrefix(It.IsAny<string>()))
                .Returns(false);

            var metadataProvider = new TestModelMetadataProvider();
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    IsTopLevelObject = isTopLevelObject,

                    // Random type.
                    ModelMetadata = metadataProvider.GetMetadataForType(typeof(Person)),
                    ValueProvider = mockValueProvider.Object,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValueProvider = mockValueProvider.Object,
                        MetadataProvider = metadataProvider,
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                    },
                    ModelState = new ModelStateDictionary(),
                },
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata =
                mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray();

            // Act
            var canCreate = mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.Equal(expectedCanCreate, canCreate);
        }
Exemplo n.º 15
0
        private async Task <bool> CanValueBindAnyModelProperties(MutableObjectBinderContext context)
        {
            // We need to enumerate the non marked properties and properties marked with IValueProviderMetadata
            // instead of checking bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName)
            // because there can be a case where a value provider might be willing to provide a marked property,
            // which might never be bound.
            // For example if person.Name is marked with FromQuery, and FormValueProvider has a key person.Name,
            // and the QueryValueProvider does not, we do not want to create Person.
            var isAnyPropertyEnabledForValueProviderBasedBinding = false;

            foreach (var propertyMetadata in context.PropertyMetadata)
            {
                // This check will skip properties which are marked explicitly using a non value binder.
                if (propertyMetadata.BinderMetadata == null ||
                    propertyMetadata.BinderMetadata is IValueProviderMetadata)
                {
                    isAnyPropertyEnabledForValueProviderBasedBinding = true;

                    // If any property can return a true value.
                    if (await CanBindValue(context.ModelBindingContext, propertyMetadata))
                    {
                        return(true);
                    }
                }
            }

            if (!isAnyPropertyEnabledForValueProviderBasedBinding)
            {
                // Either there are no properties or all the properties are marked as
                // a non value provider based marker.
                // This would be the case when the model has all its properties annotated with
                // a IBinderMetadata. We want to be able to create such a model.
                return(true);
            }

            return(false);
        }
        public async Task CanCreateModel_UnmarkedProperties_UsesCurrentValueProvider(
            Type modelType,
            bool valueProviderProvidesValue)
        {
            var mockValueProvider = new Mock<IValueProvider>();
            mockValueProvider.Setup(o => o.ContainsPrefixAsync(It.IsAny<string>()))
                             .Returns(Task.FromResult(valueProviderProvidesValue));

            var mockOriginalValueProvider = new Mock<IValueProvider>();
            mockOriginalValueProvider.Setup(o => o.ContainsPrefixAsync(It.IsAny<string>()))
                                     .Returns(Task.FromResult(false));

            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    ModelMetadata = GetMetadataForType(modelType),
                    ValueProvider = mockValueProvider.Object,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                        ValueProvider = mockOriginalValueProvider.Object,
                        MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
                    },
                    // Setting it to empty ensures that model does not get created becasue of no model name.
                    ModelName = "dummyName"
                }
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata =
                mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray();

            // Act
            var retModel = await mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.Equal(valueProviderProvidesValue, retModel);
        }
        public async Task CanCreateModel_ForExplicitValueProviderMetadata_UsesOriginalValueProvider(
            Type modelType,
            bool originalValueProviderProvidesValue)
        {
            var mockValueProvider = new Mock<IValueProvider>();
            mockValueProvider.Setup(o => o.ContainsPrefixAsync(It.IsAny<string>()))
                             .Returns(Task.FromResult(false));

            var mockOriginalValueProvider = new Mock<IBindingSourceValueProvider>();
            mockOriginalValueProvider
                .Setup(o => o.ContainsPrefixAsync(It.IsAny<string>()))
                .Returns(Task.FromResult(originalValueProviderProvidesValue));

            mockOriginalValueProvider
                .Setup(o => o.Filter(It.IsAny<BindingSource>()))
                .Returns<BindingSource>(source =>
                {
                    if (source == BindingSource.Query)
                    {
                        return mockOriginalValueProvider.Object;
                    }

                    return null;
                });

            var modelMetadata = GetMetadataForType(modelType);
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    ModelMetadata = modelMetadata,
                    ValueProvider = mockValueProvider.Object,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValueProvider = mockOriginalValueProvider.Object,
                        MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                    },

                    // Setting it to empty ensures that model does not get created becasue of no model name.
                    ModelName = "dummyName",
                    BindingSource = modelMetadata.BindingSource,
                    BinderModelName = modelMetadata.BinderModelName
                }
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata =
                mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray();

            // Act
            var retModel = await mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.Equal(originalValueProviderProvidesValue, retModel);
        }
        public async Task CanCreateModel_ReturnsTrue_IfIsTopLevelObjectAndModelHasNoProperties()
        {
            // Arrange
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    IsTopLevelObject = true,
                    ModelMetadata = GetMetadataForType(typeof(PersonWithNoProperties))
                },
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata =
                mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray();

            // Act
            var retModel = await mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.True(retModel);
        }
        public async Task CanCreateModel_ReturnsTrue_IfNotIsTopLevelObject_BasedOnValueAvailability(
            bool valueAvailable)
        {
            // Arrange
            var mockValueProvider = new Mock<IValueProvider>(MockBehavior.Strict);
            mockValueProvider
                .Setup(provider => provider.ContainsPrefixAsync("SimpleContainer.Simple.Name"))
                .Returns(Task.FromResult(valueAvailable));

            var typeMetadata = GetMetadataForType(typeof(SimpleContainer));
            var modelMetadata = typeMetadata.Properties[nameof(SimpleContainer.Simple)];
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    ModelMetadata = modelMetadata,
                    ModelName = "SimpleContainer.Simple",
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                        ValueProvider = mockValueProvider.Object,
                        MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
                    },
                    ValueProvider = mockValueProvider.Object,
                },
                PropertyMetadata = modelMetadata.Properties,
            };

            var mutableBinder = new MutableObjectModelBinder();

            // Act
            var result = await mutableBinder.CanCreateModel(bindingContext);

            // Assert
            // Result matches whether first Simple property can bind.
            Assert.Equal(valueAvailable, result);
        }
        public async Task CanCreateModel_CreatesModel_IfTheModelIsBinderPoco()
        {
            var mockValueProvider = new Mock<IValueProvider>();
            mockValueProvider.Setup(o => o.ContainsPrefixAsync(It.IsAny<string>()))
                             .Returns(Task.FromResult(false));

            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    ModelMetadata = GetMetadataForType(typeof(BinderMetadataPocoType)),
                    ValueProvider = mockValueProvider.Object,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                        ValueProvider = mockValueProvider.Object,
                        MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
                    },

                    // Setting it to empty ensures that model does not get created because of no model name.
                    ModelName = "dummyModelName",
                },
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata =
                mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray();

            // Act
            var retModel = await mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.True(retModel);
        }
        public async Task CanCreateModel_ReturnsTrue_IfIsTopLevelObjectAndModelIsMarkedWithBinderMetadata()
        {
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    // Here the metadata represents a top level object.
                    IsTopLevelObject = true,

                    ModelMetadata = GetMetadataForType(typeof(Document)),
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                    }
                }
            };

            var mutableBinder = new MutableObjectModelBinder();

            // Act
            var canCreate = await mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.True(canCreate);
        }
            CanCreateModel_CreatesModel_ForTopLevelObjectIfThereIsEmptyModelName(Type modelType, bool emptyModelName)
        {
            var mockValueProvider = new Mock<IValueProvider>();
            mockValueProvider.Setup(o => o.ContainsPrefixAsync(It.IsAny<string>()))
                             .Returns(Task.FromResult(false));

            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    // Random type.
                    ModelMetadata = GetMetadataForType(typeof(Person)),
                    ValueProvider = mockValueProvider.Object,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                        ValueProvider = mockValueProvider.Object,
                        MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider()
                    }
                }
            };

            bindingContext.ModelBindingContext.ModelName = emptyModelName ? string.Empty : "dummyModelName";
            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata = mutableBinder.GetMetadataForProperties(
                                                                bindingContext.ModelBindingContext);

            // Act
            var retModel = await mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.Equal(emptyModelName, retModel);
        }
        private async Task<bool> CanValueBindAnyModelProperties(MutableObjectBinderContext context)
        {
            // We want to check to see if any of the properties of the model can be bound using the value providers,
            // because that's all that MutableObjectModelBinder can handle.
            //
            // However, because a property might specify a custom binding source ([FromForm]), it's not correct
            // for us to just try bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName),
            // because that may include ALL value providers - that would lead us to mistakenly create the model
            // when the data is coming from a source we should use (ex: value found in query string, but the
            // model has [FromForm]).
            //
            // To do this we need to enumerate the properties, and see which of them provide a binding source
            // through metadata, then we decide what to do.
            //
            //      If a property has a binding source, and it's a greedy source, then it's not
            //      allowed to come from a value provider, so we skip it.
            //
            //      If a property has a binding source, and it's a non-greedy source, then we'll filter the
            //      the value providers to just that source, and see if we can find a matching prefix
            //      (see CanBindValue).
            //
            //      If a property does not have a binding source, then it's fair game for any value provider.
            //
            // If any property meets the above conditions and has a value from valueproviders, then we'll
            // create the model and try to bind it. OR if ALL properties of the model have a greedy source,
            // then we go ahead and create it.
            //
            var isAnyPropertyEnabledForValueProviderBasedBinding = false;
            foreach (var propertyMetadata in context.PropertyMetadata)
            {
                // This check will skip properties which are marked explicitly using a non value binder.
                var bindingSource = propertyMetadata.BindingSource;
                if (bindingSource == null || !bindingSource.IsGreedy)
                {
                    isAnyPropertyEnabledForValueProviderBasedBinding = true;

                    var propertyModelName = ModelBindingHelper.CreatePropertyModelName(
                        context.ModelBindingContext.ModelName,
                        propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName);

                    var propertyModelBindingContext = ModelBindingContext.GetChildModelBindingContext(
                        context.ModelBindingContext,
                        propertyModelName,
                        propertyMetadata);

                    // If any property can return a true value.
                    if (await CanBindValue(propertyModelBindingContext))
                    {
                        return true;
                    }
                }
            }

            if (!isAnyPropertyEnabledForValueProviderBasedBinding)
            {
                // Either there are no properties or all the properties are marked as
                // a non value provider based marker.
                // This would be the case when the model has all its properties annotated with
                // a IBinderMetadata. We want to be able to create such a model.
                return true;
            }

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

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

                    var propertyModelName = ModelNames.CreatePropertyModelName(
                        context.ModelBindingContext.ModelName,
                        propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName);

                    var propertyModelBindingContext = ModelBindingContext.GetChildModelBindingContext(
                        context.ModelBindingContext,
                        propertyModelName,
                        propertyMetadata);

                    // If any property can return a true value.
                    if (await CanBindValue(propertyModelBindingContext))
                    {
                        return(true);
                    }
                }
            }

            if (!isAnyPropertyEnabledForValueProviderBasedBinding)
            {
                // Either there are no properties or all the properties are marked as
                // a non value provider based marker.
                // This would be the case when the model has all its properties annotated with
                // a IBinderMetadata. We want to be able to create such a model.
                return(true);
            }

            return(false);
        }
        public void CanCreateModel_ReturnsFalse_IfNotIsTopLevelObjectAndModelHasNoProperties()
        {
            // Arrange
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    IsTopLevelObject = false,

                    ModelMetadata = GetMetadataForType(typeof(PersonWithNoProperties))
                }
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata =
                mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray();

            // Act
            var canCreate = mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.False(canCreate);
        }
        public void CanCreateModel_CreatesModelForValueProviderBasedBinderMetadatas_IfAValueProviderProvidesValue(
            Type modelType,
            bool valueProviderProvidesValue)
        {
            var mockValueProvider = new Mock<IValueProvider>();
            mockValueProvider.Setup(o => o.ContainsPrefix(It.IsAny<string>()))
                             .Returns(valueProviderProvidesValue);

            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    ModelMetadata = GetMetadataForType(modelType),
                    ValueProvider = mockValueProvider.Object,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                        ValueProvider = mockValueProvider.Object,
                        MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
                    },
                    // Setting it to empty ensures that model does not get created becasue of no model name.
                    ModelName = "dummyName",
                    ModelState = new ModelStateDictionary(),
                }
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata =
                mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray();

            // Act
            var canCreate = mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.Equal(valueProviderProvidesValue, canCreate);
        }