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); }
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; }
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! }
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); }
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); }
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); }
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); }
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); }
public virtual void SetPropertyPublic(ModelBindingContext bindingContext, ModelMetadata propertyMetadata, ComplexModelDtoResult dtoResult, IModelValidator requiredValidator) { base.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator); }
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); }
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); }
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); }
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! }
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); } } }
protected override void SetProperty(ModelBindingContext bindingContext, ModelMetadata propertyMetadata, ComplexModelDtoResult dtoResult, IModelValidator requiredValidator) { SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator); }
public virtual void SetPropertyPublic(ModelBindingContext bindingContext, ModelMetadata propertyMetadata, ComplexModelDtoResult dtoResult, IModelValidator requiredValidator) { base.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator); }
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); }
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); }
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); } } }
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); }