public void CombineWith() { // Arrange List<string> log = new List<string>(); ModelValidationNode[] allChildNodes = new[] { new ModelValidationNode(GetModelMetadata(), "key1"), new ModelValidationNode(GetModelMetadata(), "key2"), new ModelValidationNode(GetModelMetadata(), "key3"), }; ModelValidationNode parentNode1 = new ModelValidationNode(GetModelMetadata(), "parent1"); parentNode1.ChildNodes.Add(allChildNodes[0]); parentNode1.Validating += (sender, e) => log.Add("Validating parent1."); parentNode1.Validated += (sender, e) => log.Add("Validated parent1."); ModelValidationNode parentNode2 = new ModelValidationNode(GetModelMetadata(), "parent2"); parentNode2.ChildNodes.Add(allChildNodes[1]); parentNode2.ChildNodes.Add(allChildNodes[2]); parentNode2.Validating += (sender, e) => log.Add("Validating parent2."); parentNode2.Validated += (sender, e) => log.Add("Validated parent2."); // Act parentNode1.CombineWith(parentNode2); parentNode1.Validate(ContextUtil.CreateActionContext()); // Assert Assert.Equal(new[] { "Validating parent1.", "Validating parent2.", "Validated parent1.", "Validated parent2." }, log.ToArray()); Assert.Equal(allChildNodes, parentNode1.ChildNodes.ToArray()); }
public ComplexModelDtoResult(object model, ModelValidationNode validationNode) { if (validationNode == null) { throw Error.ArgumentNull("validationNode"); } Model = model; ValidationNode = validationNode; }
public ModelValidatingEventArgs(HttpActionContext actionContext, ModelValidationNode parentNode) { if (actionContext == null) { throw Error.ArgumentNull("actionContext"); } ActionContext = actionContext; ParentNode = parentNode; }
private void AddChildNodes(XElement parent, ModelValidationNode child) { XElement childElement = new XElement("ModelValidationNode"); childElement.Add(new XAttribute("ModelStateKey", child.ModelStateKey)); childElement.Add(new XAttribute("Value", child.ModelMetadata.Model)); foreach (ModelValidationNode childNode in child.ChildNodes) { AddChildNodes(childElement, childNode); } parent.Add(childElement); }
public void CombineWith(ModelValidationNode otherNode) { if (otherNode != null && !otherNode.SuppressValidation) { Validated += otherNode.Validated; Validating += otherNode.Validating; foreach (ModelValidationNode childNode in otherNode.ChildNodes) { ChildNodes.Add(childNode); } } }
public void CombineWith(ModelValidationNode otherNode) { if (otherNode != null && !otherNode.SuppressValidation) { Validated += otherNode.Validated; Validating += otherNode.Validating; List<ModelValidationNode> otherChildNodes = otherNode._childNodes; for (int i = 0; i < otherChildNodes.Count; i++) { ModelValidationNode childNode = otherChildNodes[i]; _childNodes.Add(childNode); } } }
private static ModelValidationNode CreateModelValidationNode(object o, ModelMetadataProvider metadataProvider, ModelStateDictionary modelStateDictionary, string modelStateKey) { ModelMetadata metadata = metadataProvider.GetMetadataForType(() => { return o; }, o.GetType()); ModelValidationNode validationNode = new ModelValidationNode(metadata, modelStateKey); // for this root node, recursively add all child nodes HashSet<object> visited = new HashSet<object>(); CreateModelValidationNodeRecursive(o, validationNode, metadataProvider, metadata, modelStateDictionary, modelStateKey, visited); return validationNode; }
public void PropertiesAreSet() { // Arrange ModelMetadata metadata = GetModelMetadata(); string modelStateKey = "someKey"; // Act ModelValidationNode node = new ModelValidationNode(metadata, modelStateKey); // Assert Assert.Equal(metadata, node.ModelMetadata); Assert.Equal(modelStateKey, node.ModelStateKey); Assert.NotNull(node.ChildNodes); Assert.Empty(node.ChildNodes); }
public void ConstructorSetsCollectionInstance() { // Arrange ModelMetadata metadata = GetModelMetadata(); string modelStateKey = "someKey"; ModelValidationNode[] childNodes = new[] { new ModelValidationNode(metadata, "someKey0"), new ModelValidationNode(metadata, "someKey1") }; // Act ModelValidationNode node = new ModelValidationNode(metadata, modelStateKey, childNodes); // Assert Assert.Equal(childNodes, node.ChildNodes.ToArray()); }
private object TryConvertContainerToMetadataType(ModelValidationNode parentNode) { if (parentNode != null) { object containerInstance = parentNode.ModelMetadata.Model; if (containerInstance != null) { Type expectedContainerType = ModelMetadata.ContainerType; if (expectedContainerType != null) { if (expectedContainerType.IsInstanceOfType(containerInstance)) { return containerInstance; } } } } return null; }
private static void CreateModelValidationNodeRecursive(object o, ModelValidationNode parentNode, ModelMetadataProvider metadataProvider, ModelMetadata metadata, ModelStateDictionary modelStateDictionary, string modelStateKey, HashSet<object> visited) { if (visited.Contains(o)) { return; } visited.Add(o); foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(o)) { // append the current property name to the model state path string propertyKey = modelStateKey; if (propertyKey.Length > 0) { propertyKey += "."; } propertyKey += property.Name; // create the node for this property and add to the parent node object propertyValue = property.GetValue(o); metadata = metadataProvider.GetMetadataForProperty(() => { return propertyValue; }, o.GetType(), property.Name); ModelValidationNode childNode = new ModelValidationNode(metadata, propertyKey); parentNode.ChildNodes.Add(childNode); // add the property node to model state ModelState modelState = new ModelState(); modelState.Value = new ValueProviderResult(propertyValue, null, CultureInfo.CurrentCulture); modelStateDictionary.Add(propertyKey, modelState); if (propertyValue != null) { CreateModelValidationNodeRecursive(propertyValue, childNode, metadataProvider, metadata, modelStateDictionary, propertyKey, visited); } } }
public void Validate(HttpActionContext actionContext, ModelValidationNode parentNode) { if (actionContext == null) { throw Error.ArgumentNull("actionContext"); } if (SuppressValidation) { // no-op return; } // pre-validation steps ModelValidatingEventArgs validatingEventArgs = new ModelValidatingEventArgs(actionContext, parentNode); OnValidating(validatingEventArgs); if (validatingEventArgs.Cancel) { return; } ValidateChildren(actionContext); ValidateThis(actionContext, parentNode); // post-validation steps ModelValidatedEventArgs validatedEventArgs = new ModelValidatedEventArgs(actionContext, parentNode); OnValidated(validatedEventArgs); }
public void Validate_ValidateAllProperties_AddsValidationErrors() { // Arrange ValidateAllPropertiesModel model = new ValidateAllPropertiesModel { RequiredString = null /* error */, RangedInt = 0 /* error */, ValidString = "dog" }; ModelMetadata modelMetadata = GetModelMetadata(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey") { ValidateAllProperties = true }; context.ModelState.AddModelError("theKey.RequiredString.Dummy", "existing Error Text"); // Act node.Validate(context); // Assert Assert.Null(context.ModelState["theKey.RequiredString"]); Assert.Equal("existing Error Text", context.ModelState["theKey.RequiredString.Dummy"].Errors[0].ErrorMessage); Assert.Equal("The field RangedInt must be between 10 and 30.", context.ModelState["theKey.RangedInt"].Errors[0].ErrorMessage); Assert.Null(context.ModelState["theKey.ValidString"]); Assert.Null(context.ModelState["theKey"]); }
public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorPresent_AddsModelError() { // Arrange HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = GetMetadataForObject(new Person()), ModelName = "foo" }; ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "ValueTypeRequired"); ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo.ValueTypeRequired"); ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(null /* model */, validationNode); ModelValidator requiredValidator = context.GetValidators(propertyMetadata).Where(v => v.IsRequired).FirstOrDefault(); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.SetPropertyPublic(context, bindingContext, propertyMetadata, dtoResult, requiredValidator); // Assert Assert.False(bindingContext.ModelState.IsValid); Assert.Equal("Sample message", bindingContext.ModelState["foo.ValueTypeRequired"].Errors[0].ErrorMessage); }
public void SetProperty_PropertyIsSettable_SetterThrows_RecordsError() { // Arrange Person model = new Person { DateOfBirth = new DateTime(1900, 1, 1) }; ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = GetMetadataForObject(model) }; ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfDeath"); ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo"); ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(new DateTime(1800, 1, 1), validationNode); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.SetPropertyPublic(null, 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_PropertyIsReadOnly_DoesNothing() { // Arrange ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = GetMetadataForType(typeof(Person)) }; ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "NonUpdateableProperty"); ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo"); ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(null /* model */, validationNode); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.SetPropertyPublic(null, bindingContext, propertyMetadata, dtoResult, requiredValidator: null); // Assert // If didn't throw, success! }
public void NullCheckFailedHandler_ModelStateValid_CallbackReturnsNull_DoesNothing() { // Arrange HttpActionContext context = ContextUtil.CreateActionContext(); ModelMetadata modelMetadata = GetMetadataForType(typeof(Person)); ModelValidationNode validationNode = new ModelValidationNode(modelMetadata, "foo"); ModelValidatedEventArgs e = new ModelValidatedEventArgs(context, null /* parentNode */); // Act ModelBinderErrorMessageProvider originalProvider = ModelBinderConfig.ValueRequiredErrorMessageProvider; try { ModelBinderConfig.ValueRequiredErrorMessageProvider = (ec, mm, value) => null; EventHandler<ModelValidatedEventArgs> handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(modelMetadata, null /* incomingValue */); handler(validationNode, e); } finally { ModelBinderConfig.ValueRequiredErrorMessageProvider = originalProvider; } // Assert Assert.True(context.ModelState.IsValid); }
public void NullCheckFailedHandler_ModelStateAlreadyInvalid_DoesNothing() { // Arrange HttpActionContext context = ContextUtil.CreateActionContext(); context.ModelState.AddModelError("foo.bar", "Some existing error."); ModelMetadata modelMetadata = GetMetadataForType(typeof(Person)); ModelValidationNode validationNode = new ModelValidationNode(modelMetadata, "foo"); ModelValidatedEventArgs e = new ModelValidatedEventArgs(context, null /* parentNode */); // Act EventHandler<ModelValidatedEventArgs> handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(modelMetadata, null /* incomingValue */); handler(validationNode, e); // Assert Assert.False(context.ModelState.ContainsKey("foo")); }
private void ValidateThis(HttpActionContext actionContext, ModelValidationNode parentNode) { ModelStateDictionary modelState = actionContext.ModelState; if (!modelState.IsValidField(ModelStateKey)) { return; // short-circuit } // If 'this' is null and there is no parent, we cannot validate, and // the DataAnnotationsModelValidator will throw. So we intercept here // to provide a catch-all value-required validation error if (parentNode == null && ModelMetadata.Model == null) { string trueModelStateKey = ModelBindingHelper.CreatePropertyModelName(ModelStateKey, ModelMetadata.GetDisplayName()); modelState.AddModelError(trueModelStateKey, SRResources.Validation_ValueNotFound); return; } _validators = actionContext.GetValidators(ModelMetadata); object container = TryConvertContainerToMetadataType(parentNode); foreach (ModelValidator validator in _validators) { foreach (ModelValidationResult validationResult in validator.Validate(ModelMetadata, container)) { string trueModelStateKey = ModelBindingHelper.CreatePropertyModelName(ModelStateKey, validationResult.MemberName); modelState.AddModelError(trueModelStateKey, validationResult.Message); } } }
public void NullCheckFailedHandler_ModelStateValid_AddsErrorString() { // Arrange HttpActionContext context = ContextUtil.CreateActionContext(); ModelMetadata modelMetadata = GetMetadataForType(typeof(Person)); ModelValidationNode validationNode = new ModelValidationNode(modelMetadata, "foo"); ModelValidatedEventArgs e = new ModelValidatedEventArgs(context, null /* parentNode */); // Act EventHandler<ModelValidatedEventArgs> handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(modelMetadata, null /* incomingValue */); handler(validationNode, e); // Assert Assert.True(context.ModelState.ContainsKey("foo")); Assert.Equal("A value is required.", context.ModelState["foo"].Errors[0].ErrorMessage); }
public void Validate_Ordering() { // Proper order of invocation: // 1. OnValidating() // 2. Child validators // 3. This validator // 4. OnValidated() // Arrange List<string> log = new List<string>(); LoggingValidatableObject model = new LoggingValidatableObject(log); ModelMetadata modelMetadata = GetModelMetadata(model); ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "ValidStringProperty"); ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey"); node.Validating += (sender, e) => log.Add("In OnValidating()"); node.Validated += (sender, e) => log.Add("In OnValidated()"); node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.ValidStringProperty")); // Act node.Validate(ContextUtil.CreateActionContext()); // Assert Assert.Equal(new[] { "In OnValidating()", "In LoggingValidatonAttribute.IsValid()", "In IValidatableObject.Validate()", "In OnValidated()" }, log.ToArray()); }
public void SetProperty_PropertyHasDefaultValue_SetsDefaultValue() { // Arrange HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = GetMetadataForObject(new Person()) }; ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "PropertyWithDefaultValue"); ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo"); ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(null /* model */, validationNode); ModelValidator requiredValidator = context.GetValidators(propertyMetadata).Where(v => v.IsRequired).FirstOrDefault(); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.SetPropertyPublic(context, bindingContext, propertyMetadata, dtoResult, requiredValidator); // Assert var person = Assert.IsType<Person>(bindingContext.Model); Assert.Equal(123.456m, person.PropertyWithDefaultValue); Assert.True(context.ModelState.IsValid); }
public void Validate_SkipsRemainingValidationIfModelStateIsInvalid() { // Because a property validator fails, the model validator shouldn't run // Arrange List<string> log = new List<string>(); LoggingValidatableObject model = new LoggingValidatableObject(log); ModelMetadata modelMetadata = GetModelMetadata(model); ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "InvalidStringProperty"); ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey"); node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.InvalidStringProperty")); node.Validating += (sender, e) => log.Add("In OnValidating()"); node.Validated += (sender, e) => log.Add("In OnValidated()"); HttpActionContext context = ContextUtil.CreateActionContext(); // Act node.Validate(context); // Assert Assert.Equal(new[] { "In OnValidating()", "In IValidatableObject.Validate()", "In OnValidated()" }, log.ToArray()); Assert.Equal("Sample error message", context.ModelState["theKey.InvalidStringProperty"].Errors[0].ErrorMessage); }
public void SetProperty_PropertyIsSettable_CallsSetter() { // Arrange Person model = new Person(); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = GetMetadataForObject(model) }; ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth"); ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo"); ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(new DateTime(2001, 1, 1), validationNode); ModelValidator requiredValidator = context.GetValidators(propertyMetadata).Where(v => v.IsRequired).FirstOrDefault(); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.SetPropertyPublic(context, bindingContext, propertyMetadata, dtoResult, requiredValidator); // Assert validationNode.Validate(context); Assert.True(context.ModelState.IsValid); Assert.Equal(new DateTime(2001, 1, 1), model.DateOfBirth); }
public void Validate_SkipsValidationIfHandlerCancels() { // Arrange List<string> log = new List<string>(); LoggingValidatableObject model = new LoggingValidatableObject(log); ModelMetadata modelMetadata = GetModelMetadata(model); ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey"); node.Validating += (sender, e) => { log.Add("In OnValidating()"); e.Cancel = true; }; node.Validated += (sender, e) => log.Add("In OnValidated()"); // Act node.Validate(ContextUtil.CreateActionContext()); // Assert Assert.Equal(new[] { "In OnValidating()" }, log.ToArray()); }
public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorNotPresent_RegistersValidationCallback() { // Arrange HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = GetMetadataForObject(new Person()), }; ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth"); ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo"); ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(null /* model */, validationNode); ModelValidator requiredValidator = context.GetValidators(propertyMetadata).Where(v => v.IsRequired).FirstOrDefault(); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.SetPropertyPublic(context, bindingContext, propertyMetadata, dtoResult, requiredValidator); // Assert Assert.True(context.ModelState.IsValid); validationNode.Validate(context, bindingContext.ValidationNode); Assert.False(context.ModelState.IsValid); }
public void Validate_SkipsValidationIfSuppressed() { // Arrange List<string> log = new List<string>(); LoggingValidatableObject model = new LoggingValidatableObject(log); ModelMetadata modelMetadata = GetModelMetadata(model); ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey") { SuppressValidation = true }; node.Validating += (sender, e) => log.Add("In OnValidating()"); node.Validated += (sender, e) => log.Add("In OnValidated()"); // Act node.Validate(ContextUtil.CreateActionContext()); // Assert Assert.Empty(log); }
public void SetProperty_SettingNullableTypeToNull_RequiredValidatorPresent_PropertySetterThrows_AddsRequiredMessageString() { // Arrange HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = GetMetadataForObject(new ModelWhosePropertySetterThrows()), ModelName = "foo" }; ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "Name"); ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo.Name"); ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(null /* model */, validationNode); ModelValidator requiredValidator = context.GetValidators(propertyMetadata).Where(v => v.IsRequired).FirstOrDefault(); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.SetPropertyPublic(context, bindingContext, propertyMetadata, dtoResult, requiredValidator); // Assert Assert.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 Validate_ThrowsIfControllerContextIsNull() { // Arrange ModelValidationNode node = new ModelValidationNode(GetModelMetadata(), "someKey"); // Act & assert Assert.ThrowsArgumentNull( () => node.Validate(null), "actionContext"); }