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