Example #1
0
        public async Task <bool> BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(ComplexModelDto))
            {
                ModelBindingHelper.ValidateBindingContext(bindingContext,
                                                          typeof(ComplexModelDto),
                                                          allowNullModel: false);

                var dto = (ComplexModelDto)bindingContext.Model;
                foreach (var propertyMetadata in dto.PropertyMetadata)
                {
                    var propertyModelName = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName,
                                                                                       propertyMetadata.PropertyName);

                    var propertyBindingContext = new ModelBindingContext(bindingContext,
                                                                         propertyModelName,
                                                                         propertyMetadata);

                    // bind and propagate the values
                    // If we can't bind then leave the result missing (don't add a null).
                    if (await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(propertyBindingContext))
                    {
                        var result = ComplexModelDtoResult.FromBindingContext(propertyBindingContext);
                        dto.Results[propertyMetadata] = result;
                    }
                }

                return(true);
            }

            return(false);
        }
        public void SetProperty_PropertyIsSettable_CallsSetter()
        {
            // Arrange
            var model          = new Person();
            var bindingContext = CreateContext(GetMetadataForObject(model));

            var propertyMetadata  = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth");
            var validationNode    = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult         = new ComplexModelDtoResult(new DateTime(2001, 1, 1), validationNode);
            var requiredValidator = bindingContext.ValidatorProviders
                                    .SelectMany(v => v.GetValidators(propertyMetadata))
                                    .Where(v => v.IsRequired)
                                    .FirstOrDefault();
            var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            validationNode.Validate(validationContext);
            Assert.Equal(true, bindingContext.ModelState.IsValid);
            Assert.Equal(new DateTime(2001, 1, 1), model.DateOfBirth);
        }
Example #3
0
        public async Task<bool> BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(ComplexModelDto))
            {
                ModelBindingHelper.ValidateBindingContext(bindingContext,
                                                          typeof(ComplexModelDto),
                                                          allowNullModel: false);

                var dto = (ComplexModelDto)bindingContext.Model;
                foreach (var propertyMetadata in dto.PropertyMetadata)
                {
                    var propertyBindingContext = new ModelBindingContext(bindingContext)
                    {
                        ModelMetadata = propertyMetadata,
                        ModelName = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName,
                                                                               propertyMetadata.PropertyName)
                    };

                    // bind and propagate the values
                    // If we can't bind, then leave the result missing (don't add a null).
                    if (await bindingContext.ModelBinder.BindModelAsync(propertyBindingContext))
                    {
                        var result = new ComplexModelDtoResult(propertyBindingContext.Model,
                                                               propertyBindingContext.ValidationNode);
                        dto.Results[propertyMetadata] = result;
                    }
                }

                return true;
            }

            return false;
        }
Example #4
0
        public void SetProperty_PropertyIsReadOnly_DoesNothing()
        {
            // Arrange
            var bindingContext   = CreateContext(GetMetadataForObject(new Person()));
            var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "NonUpdateableProperty");
            var validationNode   = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult        = new ComplexModelDtoResult(model: null, validationNode: validationNode);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator: null);

            // Assert
            // If didn't throw, success!
        }
Example #5
0
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorNotPresent_RegistersValidationCallback()
        {
            // Arrange
            var bindingContext    = CreateContext(GetMetadataForObject(new Person()));
            var propertyMetadata  = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth");
            var validationNode    = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult         = new ComplexModelDtoResult(model: null, validationNode: validationNode);
            var requiredValidator = GetRequiredValidator(bindingContext, propertyMetadata);
            var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            Assert.Equal(true, bindingContext.ModelState.IsValid);
            validationNode.Validate(validationContext, bindingContext.ValidationNode);
            Assert.Equal(false, bindingContext.ModelState.IsValid);
        }
Example #6
0
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorPresent_AddsModelError()
        {
            // Arrange
            var bindingContext = CreateContext(GetMetadataForObject(new Person()));

            bindingContext.ModelName = " foo";
            var propertyMetadata  = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "ValueTypeRequired");
            var validationNode    = new ModelValidationNode(propertyMetadata, "foo.ValueTypeRequired");
            var dtoResult         = new ComplexModelDtoResult(model: null, validationNode: validationNode);
            var requiredValidator = GetRequiredValidator(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            Assert.Equal(false, bindingContext.ModelState.IsValid);
            Assert.Equal("Sample message", bindingContext.ModelState["foo.ValueTypeRequired"].Errors[0].ErrorMessage);
        }
Example #7
0
        public void SetProperty_SettingNullableTypeToNull_RequiredValidatorPresent_PropertySetterThrows_AddsRequiredMessageString()
        {
            // Arrange
            var bindingContext = CreateContext(GetMetadataForObject(new ModelWhosePropertySetterThrows()));

            bindingContext.ModelName = "foo";
            var propertyMetadata  = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "Name");
            var validationNode    = new ModelValidationNode(propertyMetadata, "foo.Name");
            var dtoResult         = new ComplexModelDtoResult(model: null, validationNode: validationNode);
            var requiredValidator = GetRequiredValidator(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            Assert.Equal(false, bindingContext.ModelState.IsValid);
            Assert.Equal(1, bindingContext.ModelState["foo.Name"].Errors.Count);
            Assert.Equal("This message comes from the [Required] attribute.", bindingContext.ModelState["foo.Name"].Errors[0].ErrorMessage);
        }
Example #8
0
        public void SetProperty_PropertyIsSettable_SetterThrows_RecordsError()
        {
            // Arrange
            var model = new Person
            {
                DateOfBirth = new DateTime(1900, 1, 1)
            };
            var bindingContext = CreateContext(GetMetadataForObject(model));

            var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfDeath");
            var validationNode   = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult        = new ComplexModelDtoResult(new DateTime(1800, 1, 1), validationNode);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator: null);

            // Assert
            Assert.Equal("Date of death can't be before date of birth." + Environment.NewLine
                         + "Parameter name: value",
                         bindingContext.ModelState["foo"].Errors[0].Exception.Message);
        }
Example #9
0
        public void SetProperty_PropertyHasDefaultValue_SetsDefaultValue()
        {
            // Arrange
            var bindingContext = CreateContext(GetMetadataForObject(new Person()));

            var propertyMetadata  = bindingContext.ModelMetadata.Properties.First(o => o.PropertyName == "PropertyWithDefaultValue");
            var validationNode    = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult         = new ComplexModelDtoResult(model: null, validationNode: validationNode);
            var requiredValidator = bindingContext.ValidatorProvider
                                    .GetValidators(propertyMetadata)
                                    .FirstOrDefault(v => v.IsRequired);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            var person = Assert.IsType <Person>(bindingContext.Model);

            Assert.Equal(123.456m, person.PropertyWithDefaultValue);
            Assert.Equal(true, bindingContext.ModelState.IsValid);
        }
Example #10
0
 public virtual void SetPropertyPublic(ModelBindingContext bindingContext, ModelMetadata propertyMetadata, ComplexModelDtoResult dtoResult, IModelValidator requiredValidator)
 {
     base.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator);
 }
Example #11
0
        public void SetProperty_PropertyIsSettable_CallsSetter()
        {
            // Arrange
            var model = new Person();
            var bindingContext = CreateContext(GetMetadataForObject(model));

            var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth");
            var validationNode = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult = new ComplexModelDtoResult(new DateTime(2001, 1, 1), validationNode);
            var requiredValidator = bindingContext.ValidatorProviders
                                                  .SelectMany(v => v.GetValidators(propertyMetadata))
                                                  .Where(v => v.IsRequired)
                                                  .FirstOrDefault();
            var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            validationNode.Validate(validationContext);
            Assert.Equal(true, bindingContext.ModelState.IsValid);
            Assert.Equal(new DateTime(2001, 1, 1), model.DateOfBirth);
        }
Example #12
0
        public void SetProperty_PropertyIsSettable_SetterThrows_RecordsError()
        {
            // Arrange
            var model = new Person
            {
                DateOfBirth = new DateTime(1900, 1, 1)
            };
            var bindingContext = CreateContext(GetMetadataForObject(model));

            var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfDeath");
            var validationNode = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult = new ComplexModelDtoResult(new DateTime(1800, 1, 1), validationNode);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator: null);

            // Assert
            Assert.Equal("Date of death can't be before date of birth." + Environment.NewLine
                       + "Parameter name: value",
                         bindingContext.ModelState["foo"].Errors[0].Exception.Message);
        }
Example #13
0
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorNotPresent_RegistersValidationCallback()
        {
            // Arrange
            var bindingContext = CreateContext(GetMetadataForObject(new Person()));
            var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth");
            var validationNode = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult = new ComplexModelDtoResult(model: null, validationNode: validationNode);
            var requiredValidator = GetRequiredValidator(bindingContext, propertyMetadata);
            var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            Assert.Equal(true, bindingContext.ModelState.IsValid);
            validationNode.Validate(validationContext, bindingContext.ValidationNode);
            Assert.Equal(false, bindingContext.ModelState.IsValid);
        }
Example #14
0
        public void SetProperty_PropertyIsReadOnly_DoesNothing()
        {
            // Arrange
            var bindingContext = CreateContext(GetMetadataForObject(new Person()));
            var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "NonUpdateableProperty");
            var validationNode = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult = new ComplexModelDtoResult(model: null, validationNode: validationNode);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator: null);

            // Assert
            // If didn't throw, success!
        }
Example #15
0
 protected override void SetProperty(ModelBindingContext bindingContext, ModelMetadata propertyMetadata, ComplexModelDtoResult dtoResult, IModelValidator requiredValidator)
 {
     SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);
 }
        protected virtual void SetProperty(ModelBindingContext bindingContext,
                                           ModelMetadata propertyMetadata,
                                           ComplexModelDtoResult dtoResult,
                                           IModelValidator requiredValidator)
        {
            var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase;
            var property     = bindingContext.ModelType
                               .GetProperty(propertyMetadata.PropertyName, bindingFlags);

            if (property == null || !property.CanWrite)
            {
                // nothing to do
                return;
            }

            var value = dtoResult.Model ?? GetPropertyDefaultValue(property);

            propertyMetadata.Model = value;

            // 'Required' validators need to run first so that we can provide useful error messages if
            // the property setters throw, e.g. if we're setting entity keys to null.
            if (value == null)
            {
                var modelStateKey   = dtoResult.ValidationNode.ModelStateKey;
                var validationState = bindingContext.ModelState.GetFieldValidationState(modelStateKey);
                if (validationState == ModelValidationState.Unvalidated)
                {
                    if (requiredValidator != null)
                    {
                        var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);
                        foreach (var validationResult in requiredValidator.Validate(validationContext))
                        {
                            bindingContext.ModelState.TryAddModelError(modelStateKey, validationResult.Message);
                        }
                    }
                }
            }

            if (value != null || property.PropertyType.AllowsNullValue())
            {
                try
                {
                    property.SetValue(bindingContext.Model, value);
                }
                catch (Exception ex)
                {
                    // don't display a duplicate error message if a binding error has already occurred for this field
                    var targetInvocationException = ex as TargetInvocationException;
                    if (targetInvocationException != null &&
                        targetInvocationException.InnerException != null)
                    {
                        ex = targetInvocationException.InnerException;
                    }
                    var modelStateKey   = dtoResult.ValidationNode.ModelStateKey;
                    var validationState = bindingContext.ModelState.GetFieldValidationState(modelStateKey);
                    if (validationState == ModelValidationState.Unvalidated)
                    {
                        bindingContext.ModelState.AddModelError(modelStateKey, ex);
                    }
                }
            }
            else
            {
                // trying to set a non-nullable value type to null, need to make sure there's a message
                var modelStateKey   = dtoResult.ValidationNode.ModelStateKey;
                var validationState = bindingContext.ModelState.GetFieldValidationState(modelStateKey);
                if (validationState == ModelValidationState.Unvalidated)
                {
                    dtoResult.ValidationNode.Validated += CreateNullCheckFailedHandler(propertyMetadata, value);
                }
            }
        }
Example #17
0
 protected override void SetProperty(ModelBindingContext bindingContext, ModelMetadata propertyMetadata, ComplexModelDtoResult dtoResult, IModelValidator requiredValidator)
 {
     SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);
 }
Example #18
0
 public virtual void SetPropertyPublic(ModelBindingContext bindingContext, ModelMetadata propertyMetadata, ComplexModelDtoResult dtoResult, IModelValidator requiredValidator)
 {
     base.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator);
 }
Example #19
0
        public void SetProperty_SettingNullableTypeToNull_RequiredValidatorPresent_PropertySetterThrows_AddsRequiredMessageString()
        {
            // Arrange
            var bindingContext = CreateContext(GetMetadataForObject(new ModelWhosePropertySetterThrows()));
            bindingContext.ModelName = "foo";
            var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "Name");
            var validationNode = new ModelValidationNode(propertyMetadata, "foo.Name");
            var dtoResult = new ComplexModelDtoResult(model: null, validationNode: validationNode);
            var requiredValidator = GetRequiredValidator(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            Assert.Equal(false, bindingContext.ModelState.IsValid);
            Assert.Equal(1, bindingContext.ModelState["foo.Name"].Errors.Count);
            Assert.Equal("This message comes from the [Required] attribute.", bindingContext.ModelState["foo.Name"].Errors[0].ErrorMessage);
        }
Example #20
0
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorPresent_AddsModelError()
        {
            // Arrange
            var bindingContext = CreateContext(GetMetadataForObject(new Person()));
            bindingContext.ModelName = " foo";
            var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "ValueTypeRequired");
            var validationNode = new ModelValidationNode(propertyMetadata, "foo.ValueTypeRequired");
            var dtoResult = new ComplexModelDtoResult(model: null, validationNode: validationNode);
            var requiredValidator = GetRequiredValidator(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            Assert.Equal(false, bindingContext.ModelState.IsValid);
            Assert.Equal("Sample message", bindingContext.ModelState["foo.ValueTypeRequired"].Errors[0].ErrorMessage);
        }
Example #21
0
        protected virtual void SetProperty(ModelBindingContext bindingContext,
                                           ModelMetadata propertyMetadata,
                                           ComplexModelDtoResult dtoResult,
                                           IModelValidator requiredValidator)
        {
            var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase;
            var property = bindingContext.ModelType
                                         .GetProperty(propertyMetadata.PropertyName, bindingFlags);

            if (property == null || !property.CanWrite)
            {
                // nothing to do
                return;
            }

            var value = dtoResult.Model ?? GetPropertyDefaultValue(property);
            propertyMetadata.Model = value;

            // 'Required' validators need to run first so that we can provide useful error messages if
            // the property setters throw, e.g. if we're setting entity keys to null. 
            if (value == null)
            {
                var modelStateKey = dtoResult.ValidationNode.ModelStateKey;
                var validationState = bindingContext.ModelState.GetFieldValidationState(modelStateKey);
                if (validationState == ModelValidationState.Unvalidated)
                {
                    if (requiredValidator != null)
                    {
                        var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);
                        foreach (var validationResult in requiredValidator.Validate(validationContext))
                        {
                            bindingContext.ModelState.AddModelError(modelStateKey, validationResult.Message);
                        }
                    }
                }
            }

            if (value != null || property.PropertyType.AllowsNullValue())
            {
                try
                {
                    property.SetValue(bindingContext.Model, value);
                }
                catch (Exception ex)
                {
                    // don't display a duplicate error message if a binding error has already occurred for this field
                    var targetInvocationException = ex as TargetInvocationException;
                    if (targetInvocationException != null &&
                        targetInvocationException.InnerException != null)
                    {
                        ex = targetInvocationException.InnerException;
                    }
                    var modelStateKey = dtoResult.ValidationNode.ModelStateKey;
                    var validationState = bindingContext.ModelState.GetFieldValidationState(modelStateKey);
                    if (validationState == ModelValidationState.Unvalidated)
                    {
                        bindingContext.ModelState.AddModelError(modelStateKey, ex);
                    }
                }
            }
            else
            {
                // trying to set a non-nullable value type to null, need to make sure there's a message
                var modelStateKey = dtoResult.ValidationNode.ModelStateKey;
                var validationState = bindingContext.ModelState.GetFieldValidationState(modelStateKey);
                if (validationState == ModelValidationState.Unvalidated)
                {
                    dtoResult.ValidationNode.Validated += CreateNullCheckFailedHandler(propertyMetadata, value);
                }
            }
        }
Example #22
0
        public void SetProperty_PropertyHasDefaultValue_SetsDefaultValue()
        {
            // Arrange
            var bindingContext = CreateContext(GetMetadataForObject(new Person()));

            var propertyMetadata = bindingContext.ModelMetadata.Properties.First(o => o.PropertyName == "PropertyWithDefaultValue");
            var validationNode = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult = new ComplexModelDtoResult(model: null, validationNode: validationNode);
            var requiredValidator = bindingContext.ValidatorProviders
                                                  .SelectMany(v => v.GetValidators(propertyMetadata))
                                                  .Where(v => v.IsRequired)
                                                  .FirstOrDefault();

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            var person = Assert.IsType<Person>(bindingContext.Model);
            Assert.Equal(123.456m, person.PropertyWithDefaultValue);
            Assert.Equal(true, bindingContext.ModelState.IsValid);
        }