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);
        }
示例#2
0
        internal static bool ValidateObject(object o, List <ValidationResultInfo> validationErrors, HttpActionContext actionContext)
        {
            // create a model validation node for the object
            ModelMetadataProvider metadataProvider = actionContext.GetMetadataProvider();
            string modelStateKey = String.Empty;
            ModelValidationNode validationNode = CreateModelValidationNode(o, metadataProvider, actionContext.ModelState, modelStateKey);

            validationNode.ValidateAllProperties = true;

            // add the node to model state
            ModelState modelState = new ModelState();

            modelState.Value = new ValueProviderResult(o, String.Empty, CultureInfo.CurrentCulture);
            actionContext.ModelState.Add(modelStateKey, modelState);

            // invoke validation
            validationNode.Validate(actionContext);

            if (!actionContext.ModelState.IsValid)
            {
                foreach (var modelStateItem in actionContext.ModelState)
                {
                    foreach (ModelError modelError in modelStateItem.Value.Errors)
                    {
                        validationErrors.Add(new ValidationResultInfo(modelError.ErrorMessage, new string[] { modelStateItem.Key }));
                    }
                }
            }

            return(actionContext.ModelState.IsValid);
        }
        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);
        }
示例#4
0
        public void SetProperty_SettingNullableTypeToNull_RequiredValidatorPresent_PropertySetterThrows_AddsRequiredMessageString()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext()
            {
                Controller = new EmptyController()
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext()
            {
                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);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.IsFalse(bindingContext.ModelState.IsValid, "ModelState should've been marked invalid.");
            Assert.AreEqual(1, bindingContext.ModelState["foo.Name"].Errors.Count);
            Assert.AreEqual("This message comes from the [Required] attribute.", bindingContext.ModelState["foo.Name"].Errors[0].ErrorMessage);
        }
            public Task <ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
            {
                if (bindingContext.ModelType != typeof(Address))
                {
                    return(null);
                }

                var address = new Address()
                {
                    Street = "SomeStreet"
                };

                bindingContext.ModelState.SetModelValue(
                    ModelNames.CreatePropertyModelName(bindingContext.ModelName, "Street"),
                    new ValueProviderResult(
                        address.Street,
                        address.Street,
                        CultureInfo.CurrentCulture));

                var validationNode = new ModelValidationNode(
                    bindingContext.ModelName,
                    bindingContext.ModelMetadata,
                    address)
                {
                    ValidateAllProperties = true
                };

                return(Task.FromResult(new ModelBindingResult(address, bindingContext.ModelName, true, validationNode)));
            }
示例#6
0
        public void SetProperty_PropertyIsSettable_CallsSetter()
        {
            // Arrange
            Person            model             = new Person();
            ControllerContext controllerContext = new ControllerContext()
            {
                Controller = new EmptyController()
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext()
            {
                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);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            validationNode.Validate(controllerContext);
            Assert.IsTrue(controllerContext.Controller.ViewData.ModelState.IsValid, "ModelState shouldn't have been touched.");
            Assert.AreEqual(new DateTime(2001, 1, 1), model.DateOfBirth);
        }
示例#7
0
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorNotPresent_RegistersValidationCallback()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext()
            {
                Controller = new EmptyController()
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext()
            {
                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);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.IsTrue(controllerContext.Controller.ViewData.ModelState.IsValid, "ModelState shouldn't have been touched yet.");
            validationNode.Validate(controllerContext, bindingContext.ValidationNode);
            Assert.IsFalse(controllerContext.Controller.ViewData.ModelState.IsValid, "ModelState should've been marked invalid.");
        }
        public void Validate_SkipsValidationIfSuppressed()
        {
            // Arrange
            List <string>             log           = new List <string>();
            LoggingDataErrorInfoModel model         = new LoggingDataErrorInfoModel(log);
            ModelMetadata             modelMetadata = GetModelMetadata(model);

            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey")
            {
                SuppressValidation = true
            };

            node.Validating += (sender, e) => { log.Add("In OnValidating()"); };
            node.Validated  += delegate { log.Add("In OnValidated()"); };

            // Act
            node.Validate(controllerContext);

            // Assert
            Assert.Empty(log);
        }
        public void Validate_ValidateAllProperties_AddsValidationErrors()
        {
            // Arrange
            ValidateAllPropertiesModel model = new ValidateAllPropertiesModel
            {
                RequiredString = null /* error */,
                RangedInt      = 0 /* error */,
                ValidString    = "dog"
            };

            ModelMetadata     modelMetadata     = GetModelMetadata(model);
            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey")
            {
                ValidateAllProperties = true
            };

            controllerContext.Controller.ViewData.ModelState.AddModelError("theKey.RequiredString.Dummy", "existing Error Text");

            // Act
            node.Validate(controllerContext);

            // Assert
            Assert.Null(controllerContext.Controller.ViewData.ModelState["theKey.RequiredString"]);
            Assert.Equal("existing Error Text", controllerContext.Controller.ViewData.ModelState["theKey.RequiredString.Dummy"].Errors[0].ErrorMessage);
            Assert.Equal("The field RangedInt must be between 10 and 30.", controllerContext.Controller.ViewData.ModelState["theKey.RangedInt"].Errors[0].ErrorMessage);
            Assert.Null(controllerContext.Controller.ViewData.ModelState["theKey.ValidString"]);
            Assert.Null(controllerContext.Controller.ViewData.ModelState["theKey"]);
        }
        public void Validate_SkipsRemainingValidationIfModelStateIsInvalid()
        {
            // Because a property validator fails, the model validator shouldn't run

            // Arrange
            List <string>             log           = new List <string>();
            LoggingDataErrorInfoModel model         = new LoggingDataErrorInfoModel(log);
            ModelMetadata             modelMetadata = GetModelMetadata(model);

            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");

            ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "InvalidStringProperty");

            node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.InvalidStringProperty"));

            node.Validating += delegate { log.Add("In OnValidating()"); };
            node.Validated  += delegate { log.Add("In OnValidated()"); };

            // Act
            node.Validate(controllerContext);

            // Assert
            Assert.Equal(new[] { "In OnValidating()", "In IDataErrorInfo.get_Item('InvalidStringProperty')", "In OnValidated()" }, log.ToArray());
            Assert.Equal("Sample error message", controllerContext.Controller.ViewData.ModelState["theKey.InvalidStringProperty"].Errors[0].ErrorMessage);
        }
        public void Validate_SkipsValidationIfHandlerCancels()
        {
            // Arrange
            List <string>             log           = new List <string>();
            LoggingDataErrorInfoModel model         = new LoggingDataErrorInfoModel(log);
            ModelMetadata             modelMetadata = GetModelMetadata(model);

            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");

            node.Validating += (sender, e) =>
            {
                log.Add("In OnValidating()");
                e.Cancel = true;
            };
            node.Validated += delegate { log.Add("In OnValidated()"); };

            // Act
            node.Validate(controllerContext);

            // Assert
            Assert.Equal(new[] { "In OnValidating()" }, log.ToArray());
        }
        public void Validate_PassesNullContainerInstanceIfCannotBeConvertedToProperType()
        {
            // Arrange
            List <string>             log1           = new List <string>();
            LoggingDataErrorInfoModel model1         = new LoggingDataErrorInfoModel(log1);
            ModelMetadata             modelMetadata1 = GetModelMetadata(model1);

            List <string>             log2           = new List <string>();
            LoggingDataErrorInfoModel model2         = new LoggingDataErrorInfoModel(log2);
            ModelMetadata             modelMetadata2 = GetModelMetadata(model2);

            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata1, "theKey");

            node.ChildNodes.Add(new ModelValidationNode(modelMetadata2, "theKey.SomeProperty"));

            // Act
            node.Validate(controllerContext);

            // Assert
            Assert.Equal(new[] { "In IDataErrorInfo.get_Error()" }, log1.ToArray());
            Assert.Equal(new[] { "In IDataErrorInfo.get_Error()" }, log2.ToArray());
        }
        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>();
            LoggingDataErrorInfoModel model         = new LoggingDataErrorInfoModel(log);
            ModelMetadata             modelMetadata = GetModelMetadata(model);

            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");

            ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "ValidStringProperty");

            node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.ValidStringProperty"));

            node.Validating += delegate { log.Add("In OnValidating()"); };
            node.Validated  += delegate { log.Add("In OnValidated()"); };

            // Act
            node.Validate(controllerContext);

            // Assert
            Assert.Equal(new[] { "In OnValidating()", "In IDataErrorInfo.get_Item('ValidStringProperty')", "In IDataErrorInfo.get_Error()", "In OnValidated()" }, log.ToArray());
        }
示例#14
0
        public async Task BindModel_UsesTheValidationNodeOnModelBindingResult_IfPresent()
        {
            // Arrange
            var valueProvider = new SimpleHttpValueProvider();
            ModelValidationNode validationNode = null;

            var mockBinder = new Mock <IModelBinder>();

            mockBinder
            .Setup(o => o.BindModelAsync(It.IsAny <ModelBindingContext>()))
            .Returns(
                delegate(ModelBindingContext context)
            {
                validationNode = new ModelValidationNode("someName", context.ModelMetadata, 42);
                return(Task.FromResult(
                           new ModelBindingResult(42, "someName", isModelSet: true, validationNode: validationNode)));
            });
            var binder         = CreateCompositeBinder(mockBinder.Object);
            var bindingContext = CreateBindingContext(binder, valueProvider, typeof(SimplePropertiesModel));

            // Act
            var result = await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.NotNull(result);
            Assert.True(result.IsModelSet);
            Assert.Same(validationNode, result.ValidationNode);
        }
示例#15
0
        public void NullCheckFailedHandler_ModelStateValid_CallbackReturnsNull_DoesNothing()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext()
            {
                Controller = new EmptyController()
            };

            ModelMetadata           modelMetadata  = GetMetadataForType(typeof(Person));
            ModelValidationNode     validationNode = new ModelValidationNode(modelMetadata, "foo");
            ModelValidatedEventArgs e = new ModelValidatedEventArgs(controllerContext, null /* parentNode */);

            // Act
            ModelBinderErrorMessageProvider originalProvider = ModelBinderConfig.ValueRequiredErrorMessageProvider;

            try {
                ModelBinderConfig.ValueRequiredErrorMessageProvider = delegate { return(null); };
                EventHandler <ModelValidatedEventArgs> handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(controllerContext, modelMetadata, null /* incomingValue */);
                handler(validationNode, e);
            }
            finally {
                ModelBinderConfig.ValueRequiredErrorMessageProvider = originalProvider;
            }

            // Assert
            Assert.IsTrue(controllerContext.Controller.ViewData.ModelState.IsValid, "ModelState shouldn't be marked invalid if the callback returns null.");
        }
        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 += delegate { log.Add("Validating parent1."); };
            parentNode1.Validated  += delegate { log.Add("Validated parent1."); };

            ModelValidationNode parentNode2 = new ModelValidationNode(GetModelMetadata(), "parent2");

            parentNode2.ChildNodes.Add(allChildNodes[1]);
            parentNode2.ChildNodes.Add(allChildNodes[2]);
            parentNode2.Validating += delegate { log.Add("Validating parent2."); };
            parentNode2.Validated  += delegate { log.Add("Validated parent2."); };

            // Act
            parentNode1.CombineWith(parentNode2);
            parentNode1.Validate(new ControllerContext {
                Controller = new EmptyController()
            });

            // Assert
            Assert.Equal(new[] { "Validating parent1.", "Validating parent2.", "Validated parent1.", "Validated parent2." }, log.ToArray());
            Assert.Equal(allChildNodes, parentNode1.ChildNodes.ToArray());
        }
示例#17
0
        public void SetProperty_PropertyHasDefaultValue_SetsDefaultValue()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext()
            {
                Controller = new EmptyController()
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext()
            {
                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);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.AreEqual(123.456m, ((Person)bindingContext.Model).PropertyWithDefaultValue);
            Assert.IsTrue(controllerContext.Controller.ViewData.ModelState.IsValid, "ModelState should be valid.");
        }
        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"));
        }
示例#19
0
        public void SetProperty_PropertyIsSettable_SetterThrows_RecordsError()
        {
            // Arrange
            Person model = new Person()
            {
                DateOfBirth = new DateTime(1900, 1, 1)
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext()
            {
                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);

            // Assert
            Assert.AreEqual(@"Date of death can't be before date of birth.
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!
        }
示例#21
0
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorPresent_AddsModelError()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext()
            {
                Controller = new EmptyController()
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext()
            {
                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);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.IsFalse(bindingContext.ModelState.IsValid, "ModelState should've been marked invalid.");
            Assert.AreEqual("Sample message", bindingContext.ModelState["foo.ValueTypeRequired"].Errors[0].ErrorMessage);
        }
        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 Task <ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
            {
                var validationNode =
                    new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, _model);

                return(Task.FromResult(new ModelBindingResult(_model, bindingContext.ModelName, true, validationNode)));
            }
        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 BindSimpleCollection_SubBindingSucceeds()
        {
            // Arrange
            CultureInfo         culture        = CultureInfo.GetCultureInfo("fr-FR");
            Mock <IModelBinder> mockIntBinder  = new Mock <IModelBinder>();
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(int)),
                ModelName     = "someName",
                ValueProvider = new SimpleHttpValueProvider()
            };
            HttpActionContext context = ContextUtil.CreateActionContext();

            context.ControllerContext.Configuration.Services.Replace(typeof(ModelBinderProvider), new SimpleModelBinderProvider(typeof(int), mockIntBinder.Object));

            ModelValidationNode childValidationNode = null;

            mockIntBinder
            .Setup(o => o.BindModel(context, It.IsAny <ModelBindingContext>()))
            .Returns((HttpActionContext ec, ModelBindingContext mbc) =>
            {
                Assert.Equal("someName", mbc.ModelName);
                childValidationNode = mbc.ValidationNode;
                mbc.Model           = 42;
                return(true);
            });

            // Act
            List <int> boundCollection = CollectionModelBinder <int> .BindSimpleCollection(context, bindingContext, new int[1], culture);

            // Assert
            Assert.Equal(new[] { 42 }, boundCollection.ToArray());
            Assert.Equal(new[] { childValidationNode }, bindingContext.ValidationNode.ChildNodes.ToArray());
        }
示例#26
0
 /// <summary>
 /// Creates a new <see cref="ModelBindingResult"/>.
 /// </summary>
 /// <param name="model">The model which was created by the <see cref="IModelBinder"/>.</param>
 /// <param name="key">The key using which was used to attempt binding the model.</param>
 /// <param name="isModelSet">A value that represents if the model has been set by the
 /// <see cref="IModelBinder"/>.</param>
 /// <param name="validationNode">A <see cref="ModelValidationNode"/> which captures the validation information.
 /// </param>
 public ModelBindingResult(object model, string key, bool isModelSet, ModelValidationNode validationNode)
 {
     Model = model;
     Key = key;
     IsModelSet = isModelSet;
     ValidationNode = validationNode;
 }
        public void BindSimpleCollection_SubBindingSucceeds()
        {
            // Arrange
            ControllerContext             controllerContext = new ControllerContext();
            CultureInfo                   culture           = CultureInfo.GetCultureInfo("fr-FR");
            ExtensibleModelBindingContext bindingContext    = new ExtensibleModelBindingContext
            {
                ModelMetadata        = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(int)),
                ModelName            = "someName",
                ModelBinderProviders = new ModelBinderProviderCollection(),
                ValueProvider        = new SimpleValueProvider()
            };

            ModelValidationNode           childValidationNode = null;
            Mock <IExtensibleModelBinder> mockIntBinder       = new Mock <IExtensibleModelBinder>();

            mockIntBinder
            .Setup(o => o.BindModel(controllerContext, It.IsAny <ExtensibleModelBindingContext>()))
            .Returns(
                delegate(ControllerContext cc, ExtensibleModelBindingContext mbc)
            {
                Assert.Equal("someName", mbc.ModelName);
                childValidationNode = mbc.ValidationNode;
                mbc.Model           = 42;
                return(true);
            });
            bindingContext.ModelBinderProviders.RegisterBinderForType(typeof(int), mockIntBinder.Object, true /* suppressPrefixCheck */);

            // Act
            List <int> boundCollection = CollectionModelBinder <int> .BindSimpleCollection(controllerContext, bindingContext, new int[1], culture);

            // Assert
            Assert.Equal(new[] { 42 }, boundCollection.ToArray());
            Assert.Equal(new[] { childValidationNode }, bindingContext.ValidationNode.ChildNodes.ToArray());
        }
示例#28
0
        public virtual bool TryValidateModel([NotNull] object model, string prefix)
        {
            if (BindingContext == null)
            {
                var message = Resources.FormatPropertyOfTypeCannotBeNull(
                    nameof(BindingContext),
                    typeof(Controller).FullName);
                throw new InvalidOperationException(message);
            }

            var modelMetadata = MetadataProvider.GetMetadataForType(
                modelAccessor: () => model,
                modelType: model.GetType());

            var validationContext = new ModelValidationContext(
                MetadataProvider,
                BindingContext.ValidatorProvider,
                ModelState,
                modelMetadata,
                containerMetadata: null);

            var modelName = prefix ?? string.Empty;

            var validationNode = new ModelValidationNode(modelMetadata, modelName)
            {
                ValidateAllProperties = true
            };

            validationNode.Validate(validationContext);

            return(ModelState.IsValid);
        }
        public void CombineWith() {
            // Arrange
            List<string> log = new List<string>();

            ModelValidationNode[] allChildNodes = new ModelValidationNode[] {
                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 += delegate { log.Add("Validating parent1."); };
            parentNode1.Validated += delegate { log.Add("Validated parent1."); };

            ModelValidationNode parentNode2 = new ModelValidationNode(GetModelMetadata(), "parent2");
            parentNode2.ChildNodes.Add(allChildNodes[1]);
            parentNode2.ChildNodes.Add(allChildNodes[2]);
            parentNode2.Validating += delegate { log.Add("Validating parent2."); };
            parentNode2.Validated += delegate { log.Add("Validated parent2."); };

            // Act
            parentNode1.CombineWith(parentNode2);
            parentNode1.Validate(new ControllerContext() { Controller = new EmptyController() });

            // Assert
            CollectionAssert.AreEqual(
                new string[] { "Validating parent1.", "Validating parent2.", "Validated parent1.", "Validated parent2." },
                log);
            CollectionAssert.AreEqual(allChildNodes, parentNode1.ChildNodes.ToArray());
        }
示例#30
0
        public void DictionaryType_ValidationSuccessful()
        {
            // Arrange
            var modelStateDictionary = new ModelStateDictionary();

            modelStateDictionary.Add("items[0].Key", new ModelState());
            modelStateDictionary.Add("items[0].Value", new ModelState());
            modelStateDictionary.Add("items[1].Key", new ModelState());
            modelStateDictionary.Add("items[1].Value", new ModelState());

            var model = new Dictionary <string, string>()
            {
                { "FooKey", "FooValue" },
                { "BarKey", "BarValue" }
            };

            var testValidationContext = GetModelValidationContext(
                model,
                typeof(Dictionary <string, string>),
                excludedTypes: null,
                modelStateDictionary: modelStateDictionary);

            var excludeTypeFilters = new List <IExcludeTypeValidationFilter>();

            excludeTypeFilters.Add(new SimpleTypesExcludeFilter());
            testValidationContext.ExcludeFilters = excludeTypeFilters;

            var validationContext = testValidationContext.ModelValidationContext;

            var validator = new DefaultObjectValidator(
                testValidationContext.ExcludeFilters,
                testValidationContext.ModelMetadataProvider);

            var topLevelValidationNode =
                new ModelValidationNode(
                    "items",
                    testValidationContext.ModelValidationContext.ModelExplorer.Metadata,
                    testValidationContext.ModelValidationContext.ModelExplorer.Model)
            {
                ValidateAllProperties = true
            };

            // Act
            validator.Validate(validationContext, topLevelValidationNode);

            // Assert
            Assert.True(validationContext.ModelState.IsValid);
            Assert.Equal(4, validationContext.ModelState.Count);
            var modelState = validationContext.ModelState["items[0].Key"];

            Assert.Equal(ModelValidationState.Skipped, modelState.ValidationState);
            modelState = validationContext.ModelState["items[0].Value"];
            Assert.Equal(ModelValidationState.Skipped, modelState.ValidationState);
            modelState = validationContext.ModelState["items[1].Key"];
            Assert.Equal(ModelValidationState.Skipped, modelState.ValidationState);
            modelState = validationContext.ModelState["items[1].Value"];
            Assert.Equal(ModelValidationState.Skipped, modelState.ValidationState);
        }
示例#31
0
 public ComplexModelDtoResult(
     object model,
     bool isModelBound,
     [NotNull] ModelValidationNode validationNode)
 {
     Model          = model;
     IsModelBound   = isModelBound;
     ValidationNode = validationNode;
 }
        public void Validate_ThrowsIfControllerContextIsNull()
        {
            // Arrange
            ModelValidationNode node = new ModelValidationNode(GetModelMetadata(), "someKey");

            // Act & assert
            Assert.ThrowsArgumentNull(
                delegate { node.Validate(null); }, "controllerContext");
        }
        public void PropertiesAreSet() {
            // Arrange
            ModelMetadata metadata = GetModelMetadata();
            string modelStateKey = "someKey";

            // Act
            ModelValidationNode node = new ModelValidationNode(metadata, modelStateKey);

            // Assert
            Assert.AreEqual(metadata, node.ModelMetadata);
            Assert.AreEqual(modelStateKey, node.ModelStateKey);
            Assert.IsNotNull(node.ChildNodes);
            Assert.AreEqual(0, node.ChildNodes.Count);
        }
        public void ConstructorSetsCollectionInstance() {
            // Arrange
            ModelMetadata metadata = GetModelMetadata();
            string modelStateKey = "someKey";
            ModelValidationNode[] childNodes = new ModelValidationNode[] {
                new ModelValidationNode(metadata, "someKey0"),
                new ModelValidationNode(metadata, "someKey1")
            };

            // Act
            ModelValidationNode node = new ModelValidationNode(metadata, modelStateKey, childNodes);

            // Assert
            CollectionAssert.AreEqual(childNodes, (ICollection)node.ChildNodes);
        }
        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>();
            LoggingDataErrorInfoModel model = new LoggingDataErrorInfoModel(log);
            ModelMetadata modelMetadata = GetModelMetadata(model);

            ControllerContext controllerContext = new ControllerContext() {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");

            ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "ValidStringProperty");
            node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.ValidStringProperty"));

            node.Validating += delegate {
                log.Add("In OnValidating()");
            };
            node.Validated += delegate {
                log.Add("In OnValidated()");
            };

            // Act
            node.Validate(controllerContext);

            // Assert
            CollectionAssert.AreEqual(
                new string[] { "In OnValidating()", "In IDataErrorInfo.get_Item('ValidStringProperty')", "In IDataErrorInfo.get_Error()", "In OnValidated()" },
                log);
        }
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorPresent_AddsModelError()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                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);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.False(bindingContext.ModelState.IsValid);
            Assert.Equal("Sample message", bindingContext.ModelState["foo.ValueTypeRequired"].Errors[0].ErrorMessage);
        }
 public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
 {
     var validationNode =
         new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, _model);
     return Task.FromResult(new ModelBindingResult(_model, bindingContext.ModelName, true, validationNode));
 }
        public void Validate_ValidateAllProperties_AddsValidationErrors() {
            // Arrange
            ValidateAllPropertiesModel model = new ValidateAllPropertiesModel() {
                RequiredString = null /* error */,
                RangedInt = 0 /* error */,
                ValidString = "dog"
            };

            ModelMetadata modelMetadata = GetModelMetadata(model);
            ControllerContext controllerContext = new ControllerContext() {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey") {
                ValidateAllProperties = true
            };

            controllerContext.Controller.ViewData.ModelState.AddModelError("theKey.RequiredString.Dummy", "existing Error Text");

            // Act
            node.Validate(controllerContext);

            // Assert
            Assert.IsNull(controllerContext.Controller.ViewData.ModelState["theKey.RequiredString"]);
            Assert.AreEqual("existing Error Text", controllerContext.Controller.ViewData.ModelState["theKey.RequiredString.Dummy"].Errors[0].ErrorMessage);
            Assert.AreEqual("The field RangedInt must be between 10 and 30.", controllerContext.Controller.ViewData.ModelState["theKey.RangedInt"].Errors[0].ErrorMessage);
            Assert.IsNull(controllerContext.Controller.ViewData.ModelState["theKey.ValidString"]);
            Assert.IsNull(controllerContext.Controller.ViewData.ModelState["theKey"]);
        }
        public async Task BindSimpleCollection_SubBindingSucceeds()
        {
            // Arrange
            var culture = new CultureInfo("fr-FR");
            var bindingContext = GetModelBindingContext(new SimpleHttpValueProvider());
            ModelValidationNode childValidationNode = null;
            Mock.Get<IModelBinder>(bindingContext.OperationBindingContext.ModelBinder)
                .Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
                .Returns((ModelBindingContext mbc) =>
                {
                    Assert.Equal("someName", mbc.ModelName);
                    childValidationNode = new ModelValidationNode("someName", mbc.ModelMetadata, mbc.Model);
                    return Task.FromResult(new ModelBindingResult(42, mbc.ModelName, true, childValidationNode));
                });
            var modelBinder = new CollectionModelBinder<int>();

            // Act
            var boundCollection = await modelBinder.BindSimpleCollection(bindingContext, new int[1], culture);

            // Assert
            Assert.Equal(new[] { 42 }, boundCollection.Model.ToArray());
            Assert.Equal(new[] { childValidationNode }, boundCollection.ValidationNode.ChildNodes.ToArray());
        }
        public void Validate_SkipsValidationIfSuppressed() {
            // Arrange
            List<string> log = new List<string>();
            LoggingDataErrorInfoModel model = new LoggingDataErrorInfoModel(log);
            ModelMetadata modelMetadata = GetModelMetadata(model);

            ControllerContext controllerContext = new ControllerContext() {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey") {
                SuppressValidation = true
            };

            node.Validating += (sender, e) => {
                log.Add("In OnValidating()");
            };
            node.Validated += delegate {
                log.Add("In OnValidated()");
            };

            // Act
            node.Validate(controllerContext);

            // Assert
            CollectionAssert.AreEqual(new string[0], log, "Validate() should have been a no-op.");
        }
        public void Validate_ThrowsIfControllerContextIsNull() {
            // Arrange
            ModelValidationNode node = new ModelValidationNode(GetModelMetadata(), "someKey");

            // Act & assert
            ExceptionHelper.ExpectArgumentNullException(
                delegate {
                    node.Validate(null);
                }, "controllerContext");
        }
        public void SetProperty_PropertyIsSettable_SetterThrows_RecordsError()
        {
            // Arrange
            Person model = new Person
            {
                DateOfBirth = new DateTime(1900, 1, 1)
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                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);

            // 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 Validator_IfValidateAllPropertiesSet_WithChildNodes_DoesNotAutoExpand()
        {
            // Arrange
            var testValidationContext = GetModelValidationContext(
                LonelyPerson,
                typeof(Person));

            var validationContext = testValidationContext.ModelValidationContext;
            var validator = new DefaultObjectValidator(
                testValidationContext.ExcludeFilters,
                testValidationContext.ModelMetadataProvider);
            var modelExplorer = testValidationContext.ModelValidationContext.ModelExplorer;

            var topLevelValidationNode = new ModelValidationNode(
                "person",
                modelExplorer.Metadata,
                modelExplorer.Model)
            {
                ValidateAllProperties = true
            };

            var propertyExplorer = modelExplorer.GetExplorerForProperty("Profession");
            var childNode = new ModelValidationNode(
                "person.Profession",
                propertyExplorer.Metadata,
                propertyExplorer.Model);

            topLevelValidationNode.ChildNodes.Add(childNode);

            // Act
            validator.Validate(validationContext, topLevelValidationNode);

            // Assert
            var modelState = validationContext.ModelState;
            Assert.False(modelState.IsValid);

            // Since the model is invalid at property level there is no entry in the model state for top level node.
            Assert.Single(modelState.Keys, k => k == "person.Profession");
            Assert.Equal(1, modelState.Count);
        }
        public void NullCheckFailedHandler_ModelStateValid_CallbackReturnsNull_DoesNothing()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };

            ModelMetadata modelMetadata = GetMetadataForType(typeof(Person));
            ModelValidationNode validationNode = new ModelValidationNode(modelMetadata, "foo");
            ModelValidatedEventArgs e = new ModelValidatedEventArgs(controllerContext, null /* parentNode */);

            // Act
            ModelBinderErrorMessageProvider originalProvider = ModelBinderConfig.ValueRequiredErrorMessageProvider;
            try
            {
                ModelBinderConfig.ValueRequiredErrorMessageProvider = delegate { return null; };
                EventHandler<ModelValidatedEventArgs> handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(controllerContext, modelMetadata, null /* incomingValue */);
                handler(validationNode, e);
            }
            finally
            {
                ModelBinderConfig.ValueRequiredErrorMessageProvider = originalProvider;
            }

            // Assert
            Assert.True(controllerContext.Controller.ViewData.ModelState.IsValid);
        }
        public void SetProperty_PropertyIsReadOnly_DoesNothing()
        {
            // Arrange
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                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);

            // Assert
            // If didn't throw, success!
        }
        public void NullCheckFailedHandler_ModelStateAlreadyInvalid_DoesNothing()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            controllerContext.Controller.ViewData.ModelState.AddModelError("foo.bar", "Some existing error.");

            ModelMetadata modelMetadata = GetMetadataForType(typeof(Person));
            ModelValidationNode validationNode = new ModelValidationNode(modelMetadata, "foo");
            ModelValidatedEventArgs e = new ModelValidatedEventArgs(controllerContext, null /* parentNode */);

            // Act
            EventHandler<ModelValidatedEventArgs> handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(controllerContext, modelMetadata, null /* incomingValue */);
            handler(validationNode, e);

            // Assert
            Assert.False(controllerContext.Controller.ViewData.ModelState.ContainsKey("foo"));
        }
        public void CombineWith_OtherNodeIsSuppressed_DoesNothing()
        {
            // Arrange
            List<string> log = new List<string>();

            ModelValidationNode[] allChildNodes = new[]
            {
                new ModelValidationNode(GetModelMetadata(), "key1"),
                new ModelValidationNode(GetModelMetadata(), "key2"),
                new ModelValidationNode(GetModelMetadata(), "key3"),
            };

            ModelValidationNode[] expectedChildNodes = new[]
            {
                allChildNodes[0]
            };

            ModelValidationNode parentNode1 = new ModelValidationNode(GetModelMetadata(), "parent1");
            parentNode1.ChildNodes.Add(allChildNodes[0]);
            parentNode1.Validating += delegate { log.Add("Validating parent1."); };
            parentNode1.Validated += delegate { log.Add("Validated parent1."); };

            ModelValidationNode parentNode2 = new ModelValidationNode(GetModelMetadata(), "parent2");
            parentNode2.ChildNodes.Add(allChildNodes[1]);
            parentNode2.ChildNodes.Add(allChildNodes[2]);
            parentNode2.Validating += delegate { log.Add("Validating parent2."); };
            parentNode2.Validated += delegate { log.Add("Validated parent2."); };
            parentNode2.SuppressValidation = true;

            // Act
            parentNode1.CombineWith(parentNode2);
            parentNode1.Validate(new ControllerContext { Controller = new EmptyController() });

            // Assert
            Assert.Equal(new[] { "Validating parent1.", "Validated parent1." }, log.ToArray());
            Assert.Equal(expectedChildNodes, parentNode1.ChildNodes.ToArray());
        }
        public void SetProperty_SettingNullableTypeToNull_RequiredValidatorNotPresent_PropertySetterThrows_AddsRequiredMessageString() {
            // Arrange
            ControllerContext controllerContext = new ControllerContext() {
                Controller = new EmptyController()
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext() {
                ModelMetadata = GetMetadataForObject(new ModelWhosePropertySetterThrows()),
                ModelName = "foo"
            };

            ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "NameNoAttribute");
            ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo.NameNoAttribute");
            ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(null /* model */, validationNode);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.IsFalse(bindingContext.ModelState.IsValid, "ModelState should've been marked invalid.");
            Assert.AreEqual(1, bindingContext.ModelState["foo.NameNoAttribute"].Errors.Count);
            Assert.AreEqual(@"This is a different exception.
Parameter name: value", bindingContext.ModelState["foo.NameNoAttribute"].Errors[0].Exception.Message);
        }
 private static IModelBinder CreateStringBinder()
 {
     var mockStringBinder = new Mock<IModelBinder>();
     mockStringBinder
         .Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
         .Returns((ModelBindingContext mbc) =>
         {
             if (mbc.ModelType == typeof(string))
             {
                 var model = "some-value";
                 var validationNode = new ModelValidationNode(mbc.ModelName, mbc.ModelMetadata, model);
                 return Task.FromResult(new ModelBindingResult(model, mbc.ModelName, true, validationNode));
             }
             return Task.FromResult<ModelBindingResult>(null);
         });
     return mockStringBinder.Object;
 }
        private static IModelBinder CreateIntBinder()
        {
            Mock<IModelBinder> mockIntBinder = new Mock<IModelBinder>();
            mockIntBinder
                .Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
                .Returns(async (ModelBindingContext mbc) =>
                {
                    var value = await mbc.ValueProvider.GetValueAsync(mbc.ModelName);
                    if (value != null)
                    {
                        var model = value.ConvertTo(mbc.ModelType);
                        var modelValidationNode = new ModelValidationNode(mbc.ModelName, mbc.ModelMetadata, model);
                        return new ModelBindingResult(model, mbc.ModelName, true, modelValidationNode);
                    }

                    return null;
                });
            return mockIntBinder.Object;
        }
        public void NullCheckFailedHandler_ModelStateValid_AddsErrorString()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };

            ModelMetadata modelMetadata = GetMetadataForType(typeof(Person));
            ModelValidationNode validationNode = new ModelValidationNode(modelMetadata, "foo");
            ModelValidatedEventArgs e = new ModelValidatedEventArgs(controllerContext, null /* parentNode */);

            // Act
            EventHandler<ModelValidatedEventArgs> handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(controllerContext, modelMetadata, null /* incomingValue */);
            handler(validationNode, e);

            // Assert
            Assert.True(controllerContext.Controller.ViewData.ModelState.ContainsKey("foo"));
            Assert.Equal("A value is required.", controllerContext.Controller.ViewData.ModelState["foo"].Errors[0].ErrorMessage);
        }
        public void Validate_PassesNullContainerInstanceIfCannotBeConvertedToProperType() {
            // Arrange
            List<string> log1 = new List<string>();
            LoggingDataErrorInfoModel model1 = new LoggingDataErrorInfoModel(log1);
            ModelMetadata modelMetadata1 = GetModelMetadata(model1);

            List<string> log2 = new List<string>();
            LoggingDataErrorInfoModel model2 = new LoggingDataErrorInfoModel(log2);
            ModelMetadata modelMetadata2 = GetModelMetadata(model2);

            ControllerContext controllerContext = new ControllerContext() {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata1, "theKey");
            node.ChildNodes.Add(new ModelValidationNode(modelMetadata2, "theKey.SomeProperty"));

            // Act
            node.Validate(controllerContext);

            // Assert
            CollectionAssert.AreEqual(
                new string[] { "In IDataErrorInfo.get_Error()" },
                log1);

            CollectionAssert.AreEqual(
                new string[] { "In IDataErrorInfo.get_Error()" },
                log2);
        }
        public void SetProperty_PropertyHasDefaultValue_SetsDefaultValue()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                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);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            var person = Assert.IsType<Person>(bindingContext.Model);
            Assert.Equal(123.456m, person.PropertyWithDefaultValue);
            Assert.True(controllerContext.Controller.ViewData.ModelState.IsValid);
        }
        public void Validate_SkipsRemainingValidationIfModelStateIsInvalid() {
            // Because a property validator fails, the model validator shouldn't run

            // Arrange
            List<string> log = new List<string>();
            LoggingDataErrorInfoModel model = new LoggingDataErrorInfoModel(log);
            ModelMetadata modelMetadata = GetModelMetadata(model);

            ControllerContext controllerContext = new ControllerContext() {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");

            ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "InvalidStringProperty");
            node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.InvalidStringProperty"));

            node.Validating += delegate {
                log.Add("In OnValidating()");
            };
            node.Validated += delegate {
                log.Add("In OnValidated()");
            };

            // Act
            node.Validate(controllerContext);

            // Assert
            CollectionAssert.AreEqual(
                new string[] { "In OnValidating()", "In IDataErrorInfo.get_Item('InvalidStringProperty')", "In OnValidated()" },
                log);

            Assert.AreEqual("Sample error message", controllerContext.Controller.ViewData.ModelState["theKey.InvalidStringProperty"].Errors[0].ErrorMessage);
        }
        public void SetProperty_PropertyIsSettable_CallsSetter()
        {
            // Arrange
            Person model = new Person();
            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                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);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            validationNode.Validate(controllerContext);
            Assert.True(controllerContext.Controller.ViewData.ModelState.IsValid);
            Assert.Equal(new DateTime(2001, 1, 1), model.DateOfBirth);
        }
        public void Validate_SkipsValidationIfHandlerCancels() {
            // Arrange
            List<string> log = new List<string>();
            LoggingDataErrorInfoModel model = new LoggingDataErrorInfoModel(log);
            ModelMetadata modelMetadata = GetModelMetadata(model);

            ControllerContext controllerContext = new ControllerContext() {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");

            node.Validating += (sender, e) => {
                log.Add("In OnValidating()");
                e.Cancel = true;
            };
            node.Validated += delegate {
                log.Add("In OnValidated()");
            };

            // Act
            node.Validate(controllerContext);

            // Assert
            CollectionAssert.AreEqual(
                new string[] { "In OnValidating()" },
                log);
        }
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorNotPresent_RegistersValidationCallback()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                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);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.True(controllerContext.Controller.ViewData.ModelState.IsValid);
            validationNode.Validate(controllerContext, bindingContext.ValidationNode);
            Assert.False(controllerContext.Controller.ViewData.ModelState.IsValid);
        }
        public void Validator_IfValidateAllPropertiesIsNotSet_DoesNotAutoExpand()
        {
            // Arrange
            var testValidationContext = GetModelValidationContext(
                LonelyPerson,
                typeof(Person));

            var validationContext = testValidationContext.ModelValidationContext;
            var validator = new DefaultObjectValidator(
                testValidationContext.ExcludeFilters,
                testValidationContext.ModelMetadataProvider);
            var modelExplorer = testValidationContext.ModelValidationContext.ModelExplorer;

            // No ChildNode added
            var topLevelValidationNode = new ModelValidationNode(
                "person",
                modelExplorer.Metadata,
                modelExplorer.Model);

            // Act
            validator.Validate(validationContext, topLevelValidationNode);

            // Assert
            Assert.True(validationContext.ModelState.IsValid);

            // Since Person is not IValidatable and we do not look at its properties, the state is empty.
            Assert.Empty(validationContext.ModelState.Keys);
        }
        public void SetProperty_SettingNullableTypeToNull_RequiredValidatorPresent_PropertySetterThrows_AddsRequiredMessageString()
        {
            // Arrange
            ControllerContext controllerContext = new ControllerContext
            {
                Controller = new EmptyController()
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                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);

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // 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 async Task BindModel_UsesTheValidationNodeOnModelBindingResult_IfPresent()
        {
            // Arrange
            var valueProvider = new SimpleHttpValueProvider();
            ModelValidationNode validationNode = null;

            var mockBinder = new Mock<IModelBinder>();
            mockBinder
                .Setup(o => o.BindModelAsync(It.IsAny<ModelBindingContext>()))
                .Returns(
                    delegate (ModelBindingContext context)
                    {
                        validationNode = new ModelValidationNode("someName", context.ModelMetadata, 42);
                        return Task.FromResult(
                            new ModelBindingResult(42, "someName", isModelSet: true, validationNode: validationNode));
                    });
            var binder = CreateCompositeBinder(mockBinder.Object);
            var bindingContext = CreateBindingContext(binder, valueProvider, typeof(SimplePropertiesModel));

            // Act
            var result = await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.NotNull(result);
            Assert.True(result.IsModelSet);
            Assert.Same(validationNode, result.ValidationNode);
        }