Esempio n. 1
0
        private void ValidateProperties(ModelValidationContext validationContext)
        {
            var modelState = validationContext.ModelState;

            var model           = ModelMetadata.Model;
            var updatedMetadata = validationContext.MetadataProvider.GetMetadataForType(() => model,
                                                                                        ModelMetadata.ModelType);

            foreach (var propertyMetadata in updatedMetadata.Properties)
            {
                // Only want to add errors to ModelState if something doesn't already exist for the property node,
                // else we could end up with duplicate or irrelevant error messages.
                var propertyKeyRoot = ModelBindingHelper.CreatePropertyModelName(ModelStateKey,
                                                                                 propertyMetadata.PropertyName);

                if (modelState.GetFieldValidationState(propertyKeyRoot) == ModelValidationState.Unvalidated)
                {
                    var propertyValidators        = GetValidators(validationContext, propertyMetadata);
                    var propertyValidationContext = new ModelValidationContext(validationContext, propertyMetadata);
                    foreach (var propertyValidator in propertyValidators)
                    {
                        foreach (var propertyResult in propertyValidator.Validate(propertyValidationContext))
                        {
                            var thisErrorKey = ModelBindingHelper.CreatePropertyModelName(propertyKeyRoot,
                                                                                          propertyResult.MemberName);
                            modelState.TryAddModelError(thisErrorKey, propertyResult.Message);
                        }
                    }
                }
            }
        }
Esempio n. 2
0
        public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
        {
            var propertiesValid = true;
            var metadata = context.ModelMetadata;

            foreach (var propertyMetadata in metadata.Properties)
            {
                var propertyContext = new ModelValidationContext(context, propertyMetadata);

                foreach (var propertyValidator in _validators)
                {
                    foreach (var validationResult in propertyValidator.Validate(propertyContext))
                    {
                        propertiesValid = false;
                        yield return CreateSubPropertyResult(propertyMetadata, validationResult);
                    }
                }
            }

            if (propertiesValid)
            {
                foreach (var typeValidator in _validators)
                {
                    foreach (var typeResult in typeValidator.Validate(context))
                    {
                        yield return typeResult;
                    }
                }
            }
        }
Esempio n. 3
0
        public void Validate([NotNull] ModelValidationContext validationContext, ModelValidationNode parentNode)
        {
            if (SuppressValidation || !validationContext.ModelState.CanAddErrors)
            {
                // Short circuit if validation does not need to be applied or if we've reached the max number of validation errors.
                return;
            }

            // pre-validation steps
            var validatingEventArgs = new ModelValidatingEventArgs(validationContext, parentNode);

            OnValidating(validatingEventArgs);
            if (validatingEventArgs.Cancel)
            {
                return;
            }

            ValidateChildren(validationContext);
            ValidateThis(validationContext, parentNode);

            // post-validation steps
            var validatedEventArgs = new ModelValidatedEventArgs(validationContext, parentNode);

            OnValidated(validatedEventArgs);

            var modelState = validationContext.ModelState;

            if (modelState.GetFieldValidationState(ModelStateKey) != ModelValidationState.Invalid)
            {
                // If a node or its subtree were not marked invalid, we can consider it valid at this point.
                modelState.MarkFieldValid(ModelStateKey);
            }
        }
        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);
        }
Esempio n. 5
0
        public IEnumerable <ModelValidationResult> Validate(ModelValidationContext context)
        {
            var propertiesValid = true;
            var metadata        = context.ModelMetadata;

            foreach (var propertyMetadata in metadata.Properties)
            {
                var propertyContext = new ModelValidationContext(context, propertyMetadata);

                foreach (var propertyValidator in _validators)
                {
                    foreach (var validationResult in propertyValidator.Validate(propertyContext))
                    {
                        propertiesValid = false;
                        yield return(CreateSubPropertyResult(propertyMetadata, validationResult));
                    }
                }
            }

            if (propertiesValid)
            {
                foreach (var typeValidator in _validators)
                {
                    foreach (var typeResult in typeValidator.Validate(context))
                    {
                        yield return(typeResult);
                    }
                }
            }
        }
Esempio n. 6
0
        private void ValidateThis(ModelValidationContext validationContext, ModelValidationNode parentNode)
        {
            var modelState = validationContext.ModelState;

            if (modelState.GetFieldValidationState(ModelStateKey) == ModelValidationState.Invalid)
            {
                // If any item in the key's subtree has been identified as invalid, short-circuit
                return;
            }

            // If the Model at the current node 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)
            {
                modelState.TryAddModelError(ModelStateKey, Resources.Validation_ValueNotFound);
                return;
            }

            var container  = TryConvertContainerToMetadataType(parentNode);
            var validators = GetValidators(validationContext, ModelMetadata).ToArray();

            for (var i = 0; i < validators.Length; i++)
            {
                var validator = validators[i];
                foreach (var validationResult in validator.Validate(validationContext))
                {
                    var currentModelStateKey = ModelBindingHelper.CreatePropertyModelName(ModelStateKey,
                                                                                          validationResult.MemberName);
                    modelState.TryAddModelError(currentModelStateKey, validationResult.Message);
                }
            }
        }
Esempio n. 7
0
        public IEnumerable<ModelValidationResult> Validate(ModelValidationContext validationContext)
        {
            var metadata = validationContext.ModelMetadata;
            var memberName = metadata.PropertyName ?? metadata.ModelType.Name;
            var containerMetadata = validationContext.ContainerMetadata;
            var container = containerMetadata != null ? containerMetadata.Model : null;
            var context = new ValidationContext(container ?? metadata.Model)
            {
                DisplayName = metadata.GetDisplayName(),
                MemberName = memberName
            };

            var result = Attribute.GetValidationResult(metadata.Model, context);
            if (result != ValidationResult.Success)
            {
                // ModelValidationResult.MemberName is used by invoking validators (such as ModelValidator) to
                // construct the ModelKey for ModelStateDictionary. When validating at type level we want to append
                // the returned MemberNames if specified (e.g. person.Address.FirstName). For property validation, the
                // ModelKey can be constructed using the ModelMetadata and we should ignore MemberName (we don't want
                // (person.Name.Name). However the invoking validator does not have a way to distinguish between these
                // two cases. Consequently we'll only set MemberName if this validation returns a MemberName that is 
                // different from the property being validated.

                var errorMemberName = result.MemberNames.FirstOrDefault();
                if (string.Equals(errorMemberName, memberName, StringComparison.Ordinal))
                {
                    errorMemberName = null;
                }

                var validationResult = new ModelValidationResult(errorMemberName, result.ErrorMessage);
                return new ModelValidationResult[] { validationResult };
            }

            return Enumerable.Empty<ModelValidationResult>();
        }
Esempio n. 8
0
        public virtual async Task <bool> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            var newBindingContext = CreateNewBindingContext(bindingContext,
                                                            bindingContext.ModelName,
                                                            reuseValidationNode: true);

            var boundSuccessfully = await TryBind(newBindingContext);

            if (!boundSuccessfully && !string.IsNullOrEmpty(bindingContext.ModelName) &&
                bindingContext.FallbackToEmptyPrefix)
            {
                // fallback to empty prefix?
                newBindingContext = CreateNewBindingContext(bindingContext,
                                                            modelName: string.Empty,
                                                            reuseValidationNode: false);
                boundSuccessfully = await TryBind(newBindingContext);
            }

            if (!boundSuccessfully)
            {
                return(false); // something went wrong
            }

            // Only perform validation at the root of the object graph. ValidationNode will recursively walk the graph.
            // Ignore ComplexModelDto since it essentially wraps the primary object.
            if (newBindingContext.IsModelSet && IsBindingAtRootOfObjectGraph(newBindingContext))
            {
                // run validation and return the model
                // If we fell back to an empty prefix above and are dealing with simple types,
                // propagate the non-blank model name through for user clarity in validation errors.
                // Complex types will reveal their individual properties as model names and do not require this.
                if (!newBindingContext.ModelMetadata.IsComplexType &&
                    string.IsNullOrEmpty(newBindingContext.ModelName))
                {
                    newBindingContext.ValidationNode = new ModelValidationNode(newBindingContext.ModelMetadata,
                                                                               bindingContext.ModelName);
                }

                var validationContext = new ModelValidationContext(
                    bindingContext.OperationBindingContext.MetadataProvider,
                    bindingContext.OperationBindingContext.ValidatorProvider,
                    bindingContext.ModelState,
                    bindingContext.ModelMetadata,
                    containerMetadata: null);

                newBindingContext.ValidationNode.Validate(validationContext, parentNode: null);
            }

            bindingContext.OperationBindingContext.BodyBindingState =
                newBindingContext.OperationBindingContext.BodyBindingState;

            if (newBindingContext.IsModelSet)
            {
                bindingContext.Model = newBindingContext.Model;
            }

            return(true);
        }
Esempio n. 9
0
 public ModelValidationContext([NotNull] ModelValidationContext parentContext,
                               [NotNull] ModelMetadata metadata)
 {
     ModelMetadata      = metadata;
     ContainerMetadata  = parentContext.ModelMetadata;
     ModelState         = parentContext.ModelState;
     MetadataProvider   = parentContext.MetadataProvider;
     ValidatorProviders = parentContext.ValidatorProviders;
 }
Esempio n. 10
0
        private void ValidateChildren(ModelValidationContext validationContext)
        {
            for (var i = 0; i < _childNodes.Count; i++)
            {
                var child = _childNodes[i];
                var childValidationContext = new ModelValidationContext(validationContext, child.ModelMetadata);
                child.Validate(childValidationContext, this);
            }

            if (ValidateAllProperties)
            {
                ValidateProperties(validationContext);
            }
        }
Esempio n. 11
0
        public virtual async Task<bool> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            var newBindingContext = CreateNewBindingContext(bindingContext,
                                                            bindingContext.ModelName,
                                                            reuseValidationNode: true);

            var boundSuccessfully = await TryBind(newBindingContext);
            if (!boundSuccessfully && !string.IsNullOrEmpty(bindingContext.ModelName)
                && bindingContext.FallbackToEmptyPrefix)
            {
                // fallback to empty prefix?
                newBindingContext = CreateNewBindingContext(bindingContext,
                                                            modelName: string.Empty,
                                                            reuseValidationNode: false);
                boundSuccessfully = await TryBind(newBindingContext);
            }

            if (!boundSuccessfully)
            {
                return false; // something went wrong
            }

            // Only perform validation at the root of the object graph. ValidationNode will recursively walk the graph.
            // Ignore ComplexModelDto since it essentially wraps the primary object.
            if (newBindingContext.ModelMetadata.ContainerType == null &&
                newBindingContext.ModelMetadata.ModelType != typeof(ComplexModelDto))
            {
                // run validation and return the model
                // If we fell back to an empty prefix above and are dealing with simple types,
                // propagate the non-blank model name through for user clarity in validation errors.
                // Complex types will reveal their individual properties as model names and do not require this.
                if (!newBindingContext.ModelMetadata.IsComplexType &&
                    string.IsNullOrEmpty(newBindingContext.ModelName))
                {
                    newBindingContext.ValidationNode = new ModelValidationNode(newBindingContext.ModelMetadata,
                                                                               bindingContext.ModelName);
                }

                var validationContext = new ModelValidationContext(bindingContext.MetadataProvider,
                                                                   bindingContext.ValidatorProviders,
                                                                   bindingContext.ModelState,
                                                                   bindingContext.ModelMetadata,
                                                                   containerMetadata: null);

                newBindingContext.ValidationNode.Validate(validationContext, parentNode: null);
            }

            bindingContext.Model = newBindingContext.Model;
            return true;
        }
Esempio n. 12
0
        /// <inheritdoc />
        public bool Validate(
            [NotNull] ModelValidationContext modelValidationContext,
            string keyPrefix)
        {
            var metadata          = modelValidationContext.ModelMetadata;
            var validationContext = new ValidationContext()
            {
                ModelValidationContext = modelValidationContext,
                Visited     = new HashSet <object>(ReferenceEqualityComparer.Instance),
                KeyBuilders = new Stack <IKeyBuilder>(),
                RootPrefix  = keyPrefix
            };

            return(ValidateNonVisitedNodeAndChildren(metadata, validationContext, validators: null));
        }
Esempio n. 13
0
        public void DoesNotReadPropertyValue()
        {
            // Arrange
            var provider = new DataAnnotationsModelValidatorProvider();
            var model    = new ObservableModel();
            var metadata = _metadataProvider.GetMetadataForProperty(() => model.TheProperty, typeof(ObservableModel), "TheProperty");
            var context  = new ModelValidationContext(null, null, null, metadata, null);

            // Act
            var validators = provider.GetValidators(metadata).ToArray();
            var results    = validators.SelectMany(o => o.Validate(context)).ToArray();

            // Assert
            Assert.Empty(validators);
            Assert.False(model.PropertyWasRead());
        }
Esempio n. 14
0
        // Validates a single node (not including children)
        // Returns true if validation passes successfully
        private static bool ShallowValidate(
            ModelMetadata metadata,
            ValidationContext validationContext,
            [NotNull] IEnumerable <IModelValidator> validators)
        {
            var    isValid  = true;
            string modelKey = null;

            // When the are no validators we bail quickly. This saves a GetEnumerator allocation.
            // In a large array (tens of thousands or more) scenario it's very significant.
            var validatorsAsCollection = validators as ICollection;

            if (validatorsAsCollection != null && validatorsAsCollection.Count == 0)
            {
                return(isValid);
            }

            var modelValidationContext =
                new ModelValidationContext(validationContext.ModelValidationContext, metadata);

            foreach (var validator in validators)
            {
                foreach (var error in validator.Validate(modelValidationContext))
                {
                    if (modelKey == null)
                    {
                        modelKey = validationContext.RootPrefix;
                        // This constructs the object heirarchy
                        // Example: prefix.Parent.Child
                        foreach (var keyBuilder in validationContext.KeyBuilders.Reverse())
                        {
                            modelKey = keyBuilder.AppendTo(modelKey);
                        }
                    }

                    var errorKey = ModelBindingHelper.CreatePropertyModelName(modelKey, error.MemberName);
                    validationContext.ModelValidationContext.ModelState.AddModelError(errorKey, error.Message);
                    isValid = false;
                }
            }

            return(isValid);
        }
Esempio n. 15
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);
        }
Esempio n. 16
0
        public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
        {
            var model = context.ModelMetadata.Model;
            if (model == null)
            {
                return Enumerable.Empty<ModelValidationResult>();
            }

            var validatable = model as IValidatableObject;
            if (validatable == null)
            {
                var message = Resources.FormatValidatableObjectAdapter_IncompatibleType(
                                    typeof(IValidatableObject).Name,
                                    model.GetType());

                throw new InvalidOperationException(message);
            }

            var validationContext = new ValidationContext(validatable, serviceProvider: null, items: null);
            return ConvertResults(validatable.Validate(validationContext));
        }
Esempio n. 17
0
        // Returns true if validator execution adds a model error.
        private static bool RunValidator(IModelValidator validator,
                                         ModelBindingContext bindingContext,
                                         ModelMetadata propertyMetadata,
                                         string modelStateKey)
        {
            var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);

            var addedError = false;

            foreach (var validationResult in validator.Validate(validationContext))
            {
                bindingContext.ModelState.TryAddModelError(modelStateKey, validationResult.Message);
                addedError = true;
            }

            if (!addedError)
            {
                bindingContext.ModelState.MarkFieldValid(modelStateKey);
            }

            return(addedError);
        }
Esempio n. 18
0
        public void NullCheckFailedHandler_ModelStateValid_AddsErrorString()
        {
            // Arrange
            var modelState        = new ModelStateDictionary();
            var modelMetadata     = GetMetadataForType(typeof(Person));
            var validationNode    = new ModelValidationNode(modelMetadata, "foo");
            var validationContext = new ModelValidationContext(new DataAnnotationsModelMetadataProvider(),
                                                               Mock.Of <IModelValidatorProvider>(),
                                                               modelState,
                                                               modelMetadata,
                                                               null);
            var e = new ModelValidatedEventArgs(validationContext, parentNode: null);

            // Act
            var handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(modelMetadata, incomingValue: null);

            handler(validationNode, e);

            // Assert
            Assert.True(modelState.ContainsKey("foo"));
            Assert.Equal("A value is required.", modelState["foo"].Errors[0].ErrorMessage);
        }
Esempio n. 19
0
        public IEnumerable <ModelValidationResult> Validate(ModelValidationContext context)
        {
            var model = context.ModelMetadata.Model;

            if (model == null)
            {
                return(Enumerable.Empty <ModelValidationResult>());
            }

            var validatable = model as IValidatableObject;

            if (validatable == null)
            {
                var message = Resources.FormatValidatableObjectAdapter_IncompatibleType(
                    typeof(IValidatableObject).Name,
                    model.GetType());

                throw new InvalidOperationException(message);
            }

            var validationContext = new ValidationContext(validatable, serviceProvider: null, items: null);

            return(ConvertResults(validatable.Validate(validationContext)));
        }
Esempio n. 20
0
        public void NullCheckFailedHandler_ModelStateAlreadyInvalid_DoesNothing()
        {
            // Arrange
            var modelState = new ModelStateDictionary();

            modelState.AddModelError("foo.bar", "Some existing error.");

            var modelMetadata     = GetMetadataForType(typeof(Person));
            var validationNode    = new ModelValidationNode(modelMetadata, "foo");
            var validationContext = new ModelValidationContext(new DataAnnotationsModelMetadataProvider(),
                                                               Mock.Of <IModelValidatorProvider>(),
                                                               modelState,
                                                               modelMetadata,
                                                               null);
            var e = new ModelValidatedEventArgs(validationContext, parentNode: null);

            // Act
            var handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(modelMetadata, incomingValue: null);

            handler(validationNode, e);

            // Assert
            Assert.False(modelState.ContainsKey("foo"));
        }
        public IEnumerable <ModelValidationResult> Validate(ModelValidationContext validationContext)
        {
            var metadata          = validationContext.ModelMetadata;
            var memberName        = metadata.PropertyName ?? metadata.ModelType.Name;
            var containerMetadata = validationContext.ContainerMetadata;
            var container         = containerMetadata != null ? containerMetadata.Model : null;
            var context           = new ValidationContext(container ?? metadata.Model)
            {
                DisplayName = metadata.GetDisplayName(),
                MemberName  = memberName
            };

            var result = Attribute.GetValidationResult(metadata.Model, context);

            if (result != ValidationResult.Success)
            {
                // ModelValidationResult.MemberName is used by invoking validators (such as ModelValidator) to
                // construct the ModelKey for ModelStateDictionary. When validating at type level we want to append
                // the returned MemberNames if specified (e.g. person.Address.FirstName). For property validation, the
                // ModelKey can be constructed using the ModelMetadata and we should ignore MemberName (we don't want
                // (person.Name.Name). However the invoking validator does not have a way to distinguish between these
                // two cases. Consequently we'll only set MemberName if this validation returns a MemberName that is
                // different from the property being validated.

                var errorMemberName = result.MemberNames.FirstOrDefault();
                if (string.Equals(errorMemberName, memberName, StringComparison.Ordinal))
                {
                    errorMemberName = null;
                }

                var validationResult = new ModelValidationResult(errorMemberName, result.ErrorMessage);
                return(new ModelValidationResult[] { validationResult });
            }

            return(Enumerable.Empty <ModelValidationResult>());
        }
Esempio n. 22
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);
        }
Esempio n. 23
0
 public void Validate(ModelValidationContext validationContext)
 {
     Validate(validationContext, parentNode: null);
 }
Esempio n. 24
0
 private static IEnumerable<IModelValidator> GetValidators(ModelValidationContext validationContext,
                                                           ModelMetadata metadata)
 {
     return validationContext.ValidatorProviders.SelectMany(vp => vp.GetValidators(metadata));
 }
Esempio n. 25
0
        public void NullCheckFailedHandler_ModelStateAlreadyInvalid_DoesNothing()
        {
            // Arrange
            var modelState = new ModelStateDictionary();
            modelState.AddModelError("foo.bar", "Some existing error.");

            var modelMetadata = GetMetadataForType(typeof(Person));
            var validationNode = new ModelValidationNode(modelMetadata, "foo");
            var validationContext = new ModelValidationContext(new DataAnnotationsModelMetadataProvider(),
                                                               Enumerable.Empty<IModelValidatorProvider>(),
                                                               modelState,
                                                               modelMetadata,
                                                               null);
            var e = new ModelValidatedEventArgs(validationContext, parentNode: null);

            // Act
            var handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(modelMetadata, incomingValue: null);
            handler(validationNode, e);

            // Assert
            Assert.False(modelState.ContainsKey("foo"));
        }
Esempio n. 26
0
        public void ProcessDto_BindRequiredFieldNull_RaisesModelError()
        {
            // Arrange
            var model = new ModelWithBindRequired
            {
                Name = "original value",
                Age = -20
            };

            var containerMetadata = GetMetadataForObject(model);
            var bindingContext = new ModelBindingContext()
            {
                ModelMetadata = containerMetadata,
                ModelName = "theModel",
                ModelState = new ModelStateDictionary(),
                ValidatorProviders = Enumerable.Empty<IModelValidatorProvider>()
            };
            var validationContext = new ModelValidationContext(new EmptyModelMetadataProvider(),
                                                               bindingContext.ValidatorProviders,
                                                               bindingContext.ModelState,
                                                               containerMetadata,
                                                               null);

            var dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties);
            var testableBinder = new TestableMutableObjectModelBinder();

            var propertyMetadata = dto.PropertyMetadata.Single(o => o.PropertyName == "Name");
            dto.Results[propertyMetadata] =
                new ComplexModelDtoResult("John Doe", new ModelValidationNode(propertyMetadata, "theModel.Name"));

            // Attempt to set non-Nullable property to null. BindRequiredAttribute should not be relevant in this
            // case because the binding exists.
            propertyMetadata = dto.PropertyMetadata.Single(o => o.PropertyName == "Age");
            dto.Results[propertyMetadata] =
                new ComplexModelDtoResult(null, new ModelValidationNode(propertyMetadata, "theModel.Age"));

            // Act; must also Validate because null-check error handler is late-bound
            testableBinder.ProcessDto(bindingContext, dto);
            bindingContext.ValidationNode.Validate(validationContext);

            // Assert
            var modelStateDictionary = bindingContext.ModelState;
            Assert.Equal(false, modelStateDictionary.IsValid);
            Assert.Equal(2, modelStateDictionary.Count);

            // Check Name field
            ModelState modelState;
            Assert.True(modelStateDictionary.TryGetValue("theModel.Name", out modelState));
            Assert.Equal(0, modelState.Errors.Count);
            Assert.Equal(ModelValidationState.Valid, modelState.ValidationState);

            // Check Age error.
            Assert.True(modelStateDictionary.TryGetValue("theModel.Age", out modelState));
            Assert.Equal(1, modelState.Errors.Count);
            Assert.Equal(ModelValidationState.Invalid, modelState.ValidationState);

            var modelError = modelState.Errors[0];
            Assert.Null(modelError.Exception);
            Assert.NotNull(modelError.ErrorMessage);
            Assert.Equal("A value is required.", modelError.ErrorMessage);
        }
Esempio n. 27
0
 public IEnumerable <ModelValidationResult> Validate(ModelValidationContext context)
 {
     return(Enumerable.Empty <ModelValidationResult>());
 }
Esempio n. 28
0
 public ModelValidatingEventArgs([NotNull] ModelValidationContext validationContext,
                                 [NotNull] ModelValidationNode parentNode)
 {
     ValidationContext = validationContext;
     ParentNode        = parentNode;
 }
Esempio n. 29
0
 public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
 {
     return Enumerable.Empty<ModelValidationResult>();
 }
Esempio n. 30
0
        protected virtual void SetProperty(
            ModelBindingContext bindingContext,
            ModelExplorer modelExplorer,
            ModelMetadata propertyMetadata,
            ModelBindingResult 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;
            }

            object value;
            var    hasDefaultValue = false;

            if (dtoResult.IsModelSet)
            {
                value = dtoResult.Model;
            }
            else
            {
                hasDefaultValue = TryGetPropertyDefaultValue(property, out 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.Key;
                var validationState = bindingContext.ModelState.GetFieldValidationState(modelStateKey);
                if (validationState == ModelValidationState.Unvalidated)
                {
                    if (requiredValidator != null)
                    {
                        var propertyExplorer  = modelExplorer.GetExplorerForExpression(propertyMetadata, model: null);
                        var validationContext = new ModelValidationContext(bindingContext, propertyExplorer);
                        foreach (var validationResult in requiredValidator.Validate(validationContext))
                        {
                            bindingContext.ModelState.TryAddModelError(modelStateKey, validationResult.Message);
                        }
                    }
                }
            }

            if (!dtoResult.IsModelSet && !hasDefaultValue)
            {
                // If we don't have a value, don't set it on the model and trounce a pre-initialized
                // value.
                return;
            }

            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.Key;
                    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.Key;
                var validationState = bindingContext.ModelState.GetFieldValidationState(modelStateKey);
                if (validationState == ModelValidationState.Unvalidated)
                {
                    var errorMessage = Resources.ModelBinderConfig_ValueRequired;
                    bindingContext.ModelState.TryAddModelError(modelStateKey, errorMessage);
                }
            }
        }
Esempio n. 31
0
 public IEnumerable <ModelValidationResult> Validate(ModelValidationContext context)
 {
     throw new InvalidOperationException(_errorMessage);
 }
Esempio n. 32
0
        public void ProcessDto_BindRequiredFieldNull_RaisesModelError()
        {
            // Arrange
            var model = new ModelWithBindRequired
            {
                Name = "original value",
                Age  = -20
            };

            var containerMetadata = GetMetadataForObject(model);
            var bindingContext    = new ModelBindingContext()
            {
                ModelMetadata     = containerMetadata,
                ModelName         = "theModel",
                ModelState        = new ModelStateDictionary(),
                ValidatorProvider = Mock.Of <IModelValidatorProvider>()
            };
            var validationContext = new ModelValidationContext(new EmptyModelMetadataProvider(),
                                                               bindingContext.ValidatorProvider,
                                                               bindingContext.ModelState,
                                                               containerMetadata,
                                                               null);

            var dto            = new ComplexModelDto(containerMetadata, containerMetadata.Properties);
            var testableBinder = new TestableMutableObjectModelBinder();

            var propertyMetadata = dto.PropertyMetadata.Single(o => o.PropertyName == "Name");

            dto.Results[propertyMetadata] =
                new ComplexModelDtoResult("John Doe", new ModelValidationNode(propertyMetadata, "theModel.Name"));

            // Attempt to set non-Nullable property to null. BindRequiredAttribute should not be relevant in this
            // case because the binding exists.
            propertyMetadata = dto.PropertyMetadata.Single(o => o.PropertyName == "Age");
            dto.Results[propertyMetadata] =
                new ComplexModelDtoResult(null, new ModelValidationNode(propertyMetadata, "theModel.Age"));

            // Act; must also Validate because null-check error handler is late-bound
            testableBinder.ProcessDto(bindingContext, dto);
            bindingContext.ValidationNode.Validate(validationContext);

            // Assert
            var modelStateDictionary = bindingContext.ModelState;

            Assert.Equal(false, modelStateDictionary.IsValid);
            Assert.Equal(2, modelStateDictionary.Count);

            // Check Name field
            ModelState modelState;

            Assert.True(modelStateDictionary.TryGetValue("theModel.Name", out modelState));
            Assert.Equal(0, modelState.Errors.Count);
            Assert.Equal(ModelValidationState.Valid, modelState.ValidationState);

            // Check Age error.
            Assert.True(modelStateDictionary.TryGetValue("theModel.Age", out modelState));
            Assert.Equal(1, modelState.Errors.Count);
            Assert.Equal(ModelValidationState.Invalid, modelState.ValidationState);

            var modelError = modelState.Errors[0];

            Assert.Null(modelError.Exception);
            Assert.NotNull(modelError.ErrorMessage);
            Assert.Equal("A value is required.", modelError.ErrorMessage);
        }
Esempio n. 33
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);
                }
            }
        }
Esempio n. 34
0
        // Returns true if validator execution adds a model error.
        private static bool RunValidator(IModelValidator validator,
                                         ModelBindingContext bindingContext,
                                         ModelMetadata propertyMetadata,
                                         string modelStateKey)
        {
            var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);

            var addedError = false;
            foreach (var validationResult in validator.Validate(validationContext))
            {
                bindingContext.ModelState.AddModelError(modelStateKey, validationResult.Message);
                addedError = true;
            }

            if (!addedError)
            {
                bindingContext.ModelState.MarkFieldValid(modelStateKey);
            }

            return addedError;
        }
        public void DoesNotReadPropertyValue()
        {
            // Arrange
            var provider = new DataAnnotationsModelValidatorProvider();
            var model = new ObservableModel();
            var metadata = _metadataProvider.GetMetadataForProperty(() => model.TheProperty, typeof(ObservableModel), "TheProperty");
            var context = new ModelValidationContext(null, null, null, metadata, null);

            // Act
            var validators = provider.GetValidators(metadata).ToArray();
            var results = validators.SelectMany(o => o.Validate(context)).ToArray();

            // Assert
            Assert.Empty(validators);
            Assert.False(model.PropertyWasRead());
        }
Esempio n. 36
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);
        }
Esempio n. 37
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.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);
                }
            }
        }
Esempio n. 38
0
        private void ValidateChildren(ModelValidationContext validationContext)
        {
            for (var i = 0; i < _childNodes.Count; i++)
            {
                var child = _childNodes[i];
                var childValidationContext = new ModelValidationContext(validationContext, child.ModelMetadata);
                child.Validate(childValidationContext, this);
            }

            if (ValidateAllProperties)
            {
                ValidateProperties(validationContext);
            }
        }
Esempio n. 39
0
        public void NullCheckFailedHandler_ModelStateValid_AddsErrorString()
        {
            // Arrange
            var modelState = new ModelStateDictionary();
            var modelMetadata = GetMetadataForType(typeof(Person));
            var validationNode = new ModelValidationNode(modelMetadata, "foo");
            var validationContext = new ModelValidationContext(new DataAnnotationsModelMetadataProvider(),
                                                               Enumerable.Empty<IModelValidatorProvider>(),
                                                               modelState,
                                                               modelMetadata,
                                                               null);
            var e = new ModelValidatedEventArgs(validationContext, parentNode: null);

            // Act
            var handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(modelMetadata, incomingValue: null);
            handler(validationNode, e);

            // Assert
            Assert.True(modelState.ContainsKey("foo"));
            Assert.Equal("A value is required.", modelState["foo"].Errors[0].ErrorMessage);
        }
Esempio n. 40
0
        private void ValidateProperties(ModelValidationContext validationContext)
        {
            var modelState = validationContext.ModelState;

            var model = ModelMetadata.Model;
            var updatedMetadata = validationContext.MetadataProvider.GetMetadataForType(() => model,
                                                                                        ModelMetadata.ModelType);

            foreach (var propertyMetadata in updatedMetadata.Properties)
            {
                // Only want to add errors to ModelState if something doesn't already exist for the property node,
                // else we could end up with duplicate or irrelevant error messages.
                var propertyKeyRoot = ModelBindingHelper.CreatePropertyModelName(ModelStateKey,
                                                                                 propertyMetadata.PropertyName);

                if (modelState.GetFieldValidationState(propertyKeyRoot) == ModelValidationState.Unvalidated)
                {
                    var propertyValidators = GetValidators(validationContext, propertyMetadata);
                    var propertyValidationContext = new ModelValidationContext(validationContext, propertyMetadata);
                    foreach (var propertyValidator in propertyValidators)
                    {
                        foreach (var propertyResult in propertyValidator.Validate(propertyValidationContext))
                        {
                            var thisErrorKey = ModelBindingHelper.CreatePropertyModelName(propertyKeyRoot,
                                                                                          propertyResult.MemberName);
                            modelState.AddModelError(thisErrorKey, propertyResult.Message);
                        }
                    }
                }
            }
        }
Esempio n. 41
0
 public void Validate(ModelValidationContext validationContext)
 {
     Validate(validationContext, parentNode: null);
 }
Esempio n. 42
0
        private void ValidateThis(ModelValidationContext validationContext, ModelValidationNode parentNode)
        {
            var modelState = validationContext.ModelState;
            if (modelState.GetFieldValidationState(ModelStateKey) == ModelValidationState.Invalid)
            {
                // If any item in the key's subtree has been identified as invalid, short-circuit
                return;
            }

            // If the Model at the current node 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
            var modelStateKey = ModelBindingHelper.CreatePropertyModelName(ModelStateKey,
                                                                           ModelMetadata.GetDisplayName());
            if (parentNode == null && ModelMetadata.Model == null)
            {
                modelState.AddModelError(modelStateKey, Resources.Validation_ValueNotFound);
                return;
            }

            var container = TryConvertContainerToMetadataType(parentNode);
            var validators = GetValidators(validationContext, ModelMetadata).ToArray();
            for (var i = 0; i < validators.Length; i++)
            {
                var validator = validators[i];
                foreach (var validationResult in validator.Validate(validationContext))
                {
                    var currentModelStateKey = ModelBindingHelper.CreatePropertyModelName(ModelStateKey,
                                                                                          validationResult.MemberName);
                    modelState.AddModelError(currentModelStateKey, validationResult.Message);
                }
            }
        }
Esempio n. 43
0
 private static IEnumerable <IModelValidator> GetValidators(ModelValidationContext validationContext,
                                                            ModelMetadata metadata)
 {
     return(validationContext.ValidatorProviders.SelectMany(vp => vp.GetValidators(metadata)));
 }
Esempio n. 44
0
 public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
 {
     throw new InvalidOperationException(_errorMessage);
 }