Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
        internal void ProcessDto(HttpActionContext actionContext, ModelBindingContext bindingContext, ComplexModelDto dto)
        {
            HashSet <string> requiredProperties;
            Dictionary <string, ModelValidator> requiredValidators;
            HashSet <string> skipProperties;

            GetRequiredPropertiesCollection(actionContext, bindingContext, out requiredProperties, out requiredValidators, out skipProperties);

            // Are all of the required fields accounted for?
            HashSet <string> missingRequiredProperties = new HashSet <string>(requiredProperties.Except(dto.Results.Select(r => r.Key.PropertyName)));

            foreach (string missingRequiredProperty in missingRequiredProperties)
            {
                string key = ModelBindingHelper.CreatePropertyModelName(bindingContext.ValidationNode.ModelStateKey, missingRequiredProperty);
                bindingContext.ModelState.AddModelError(key, Error.Format(SRResources.MissingRequiredMember, missingRequiredProperty));
            }

            // for each property that was bound, call the setter, recording exceptions as necessary
            foreach (var entry in dto.Results)
            {
                ModelMetadata propertyMetadata = entry.Key;

                ComplexModelDtoResult dtoResult = entry.Value;
                if (dtoResult != null)
                {
                    SetProperty(actionContext, bindingContext, propertyMetadata, dtoResult, requiredValidators[propertyMetadata.PropertyName]);
                    bindingContext.ValidationNode.ChildNodes.Add(dtoResult.ValidationNode);
                }
            }
        }
        public void SetProperty_PropertyIsReadOnly_DoesNothing()
        {
            // Arrange
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForType(typeof(Person))
            };

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

            TestableMutableObjectModelBinder testableBinder =
                new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(
                null,
                bindingContext,
                propertyMetadata,
                dtoResult,
                requiredValidator: null
                );
            // Assert
            // If didn't throw, success!
        }
        public void SetProperty_SettingNullableTypeToNull_RequiredValidatorNotPresent_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 == "NameNoAttribute");
            ModelValidationNode   validationNode    = new ModelValidationNode(propertyMetadata, "foo.NameNoAttribute");
            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);
            ModelError modelError = Assert.Single(bindingContext.ModelState["foo.NameNoAttribute"].Errors);

            Assert.Equal(
                "This is a different exception." + Environment.NewLine + "Parameter name: value",
                modelError.Exception.Message);
        }
Ejemplo n.º 7
0
        public void SetProperty_PropertyIsSettable_SetterThrows_RecordsError()
        {
            // Arrange
            Person model = new Person
            {
                DateOfBirth = new DateTime(1900, 1, 1)
            };
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForObject(model)
            };

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

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.Equal(@"Date of death can't be before date of birth.
Parameter name: value", bindingContext.ModelState["foo"].Errors[0].Exception.Message);
        }
        public void Constructor_SetsProperties()
        {
            // Arrange
            ModelValidationNode validationNode = GetValidationNode();

            // Act
            ComplexModelDtoResult result = new ComplexModelDtoResult("some string", validationNode);

            // Assert
            Assert.Equal("some string", result.Model);
            Assert.Equal(validationNode, result.ValidationNode);
        }
Ejemplo n.º 9
0
        public void Constructor_SetsProperties()
        {
            // Arrange
            ModelValidationNode validationNode = GetValidationNode();

            // Act
            ComplexModelDtoResult result = new ComplexModelDtoResult("some string", validationNode);

            // Assert
            Assert.Equal("some string", result.Model);
            Assert.Equal(validationNode, result.ValidationNode);
        }
Ejemplo n.º 10
0
        internal void ProcessDto(HttpActionContext actionContext, ModelBindingContext bindingContext, ComplexModelDto dto)
        {
            HashSet <string> requiredProperties;
            Dictionary <string, ModelValidator> requiredValidators;
            HashSet <string> skipProperties;

            GetRequiredPropertiesCollection(actionContext, bindingContext, out requiredProperties, out requiredValidators, out skipProperties);

            // Eliminate provided properties from requiredProperties; leaving just *missing* required properties.
            requiredProperties.ExceptWith(dto.Results.Select(r => r.Key.PropertyName));

            foreach (string missingRequiredProperty in requiredProperties)
            {
                string modelStateKey = ModelBindingHelper.CreatePropertyModelName(
                    bindingContext.ValidationNode.ModelStateKey, missingRequiredProperty);

                // Update Model as SetProperty() would: Place null value where validator will check for non-null. This
                // ensures a failure result from a required validator (if any) even for a non-nullable property.
                // (Otherwise, propertyMetadata.Model is likely already null.)
                ModelMetadata propertyMetadata = bindingContext.PropertyMetadata[missingRequiredProperty];
                propertyMetadata.Model = null;

                // Execute validator (if any) to get custom error message.
                ModelValidator validator  = requiredValidators[missingRequiredProperty];
                bool           addedError = RunValidator(validator, bindingContext, propertyMetadata, modelStateKey);

                // Fall back to default message if HttpBindingBehaviorAttribute required this property or validator
                // (oddly) succeeded.
                if (!addedError)
                {
                    bindingContext.ModelState.AddModelError(modelStateKey,
                                                            Error.Format(SRResources.MissingRequiredMember, missingRequiredProperty));
                }
            }

            // for each property that was bound, call the setter, recording exceptions as necessary
            foreach (var entry in dto.Results)
            {
                ModelMetadata propertyMetadata = entry.Key;

                ComplexModelDtoResult dtoResult = entry.Value;
                if (dtoResult != null)
                {
                    SetProperty(actionContext, bindingContext, propertyMetadata, dtoResult, requiredValidators[propertyMetadata.PropertyName]);
                    bindingContext.ValidationNode.ChildNodes.Add(dtoResult.ValidationNode);
                }
            }
        }
 public virtual void SetPropertyPublic(
     HttpActionContext context,
     ModelBindingContext bindingContext,
     ModelMetadata propertyMetadata,
     ComplexModelDtoResult dtoResult,
     ModelValidator requiredValidator
     )
 {
     base.SetProperty(
         context,
         bindingContext,
         propertyMetadata,
         dtoResult,
         requiredValidator
         );
 }
 protected override void SetProperty(
     HttpActionContext actionContext,
     ModelBindingContext bindingContext,
     ModelMetadata propertyMetadata,
     ComplexModelDtoResult dtoResult,
     ModelValidator requiredValidator
     )
 {
     SetPropertyPublic(
         actionContext,
         bindingContext,
         propertyMetadata,
         dtoResult,
         requiredValidator
         );
 }
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorPresent_AddsModelError()
        {
            // Arrange
            HttpActionContext   context        = ContextUtil.CreateActionContext();
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForObject(new Person()),
                ModelName     = "foo"
            };

            ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(
                o => o.PropertyName == "ValueTypeRequired"
                );
            ModelValidationNode validationNode = new ModelValidationNode(
                propertyMetadata,
                "foo.ValueTypeRequired"
                );
            ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(
                null /* model */
                ,
                validationNode
                );
            ModelValidator requiredValidator = context
                                               .GetValidators(propertyMetadata)
                                               .Where(v => v.IsRequired)
                                               .FirstOrDefault();

            TestableMutableObjectModelBinder testableBinder =
                new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.False(bindingContext.ModelState.IsValid);
            Assert.Equal(
                "Sample message",
                bindingContext.ModelState["foo.ValueTypeRequired"].Errors[0].ErrorMessage
                );
        }
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorNotPresent_RegistersValidationCallback()
        {
            // Arrange
            HttpActionContext   context        = ContextUtil.CreateActionContext();
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForObject(new Person()),
            };

            ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(
                o => o.PropertyName == "DateOfBirth"
                );
            ModelValidationNode   validationNode = new ModelValidationNode(propertyMetadata, "foo");
            ComplexModelDtoResult dtoResult      = new ComplexModelDtoResult(
                null /* model */
                ,
                validationNode
                );
            ModelValidator requiredValidator = context
                                               .GetValidators(propertyMetadata)
                                               .Where(v => v.IsRequired)
                                               .FirstOrDefault();

            TestableMutableObjectModelBinder testableBinder =
                new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.True(context.ModelState.IsValid);
            validationNode.Validate(context, bindingContext.ValidationNode);
            Assert.False(context.ModelState.IsValid);
        }
 protected override void SetProperty(HttpActionContext actionContext, ModelBindingContext bindingContext, ModelMetadata propertyMetadata, ComplexModelDtoResult dtoResult, ModelValidator requiredValidator)
 {
     SetPropertyPublic(actionContext, bindingContext, propertyMetadata, dtoResult, requiredValidator);
 }
 public virtual void SetPropertyPublic(HttpActionContext context, ModelBindingContext bindingContext, ModelMetadata propertyMetadata, ComplexModelDtoResult dtoResult, ModelValidator requiredValidator)
 {
     base.SetProperty(context, bindingContext, propertyMetadata, dtoResult, requiredValidator);
 }
        public void SetProperty_SettingNullableTypeToNull_RequiredValidatorPresent_PropertySetterThrows_AddsRequiredMessageString()
        {
            // Arrange
            HttpActionContext context = ContextUtil.CreateActionContext();
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForObject(new ModelWhosePropertySetterThrows()),
                ModelName = "foo"
            };

            ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "Name");
            ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo.Name");
            ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(null /* model */, validationNode);
            ModelValidator requiredValidator = context.GetValidators(propertyMetadata).Where(v => v.IsRequired).FirstOrDefault();

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.False(bindingContext.ModelState.IsValid);
            Assert.Equal(1, bindingContext.ModelState["foo.Name"].Errors.Count);
            Assert.Equal("This message comes from the [Required] attribute.", bindingContext.ModelState["foo.Name"].Errors[0].ErrorMessage);
        }
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorPresent_AddsModelError()
        {
            // Arrange
            HttpActionContext context = ContextUtil.CreateActionContext();
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForObject(new Person()),
                ModelName = "foo"
            };

            ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "ValueTypeRequired");
            ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo.ValueTypeRequired");
            ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(null /* model */, validationNode);
            ModelValidator requiredValidator = context.GetValidators(propertyMetadata).Where(v => v.IsRequired).FirstOrDefault();

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.False(bindingContext.ModelState.IsValid);
            Assert.Equal("Sample message", bindingContext.ModelState["foo.ValueTypeRequired"].Errors[0].ErrorMessage);
        }
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorNotPresent_RegistersValidationCallback()
        {
            // Arrange
            HttpActionContext context = ContextUtil.CreateActionContext();
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForObject(new Person()),
            };

            ModelMetadata propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth");
            ModelValidationNode validationNode = new ModelValidationNode(propertyMetadata, "foo");
            ComplexModelDtoResult dtoResult = new ComplexModelDtoResult(null /* model */, validationNode);
            ModelValidator requiredValidator = context.GetValidators(propertyMetadata).Where(v => v.IsRequired).FirstOrDefault();

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.True(context.ModelState.IsValid);
            validationNode.Validate(context, bindingContext.ValidationNode);
            Assert.False(context.ModelState.IsValid);
        }
        public void SetProperty_PropertyIsSettable_SetterThrows_RecordsError()
        {
            // Arrange
            Person model = new Person
            {
                DateOfBirth = new DateTime(1900, 1, 1)
            };
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForObject(model)
            };

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

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            Assert.Equal("Date of death can't be before date of birth." + Environment.NewLine
                       + "Parameter name: value",
                         bindingContext.ModelState["foo"].Errors[0].Exception.Message);
        }
        public void SetProperty_PropertyIsSettable_CallsSetter()
        {
            // Arrange
            Person model = new Person();
            HttpActionContext context = ContextUtil.CreateActionContext();
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForObject(model)
            };

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

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            validationNode.Validate(context);
            Assert.True(context.ModelState.IsValid);
            Assert.Equal(new DateTime(2001, 1, 1), model.DateOfBirth);
        }
        public void SetProperty_PropertyIsReadOnly_DoesNothing()
        {
            // Arrange
            ModelBindingContext bindingContext = new ModelBindingContext
            {
                ModelMetadata = GetMetadataForType(typeof(Person))
            };

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

            TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder();

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

            // Assert
            // If didn't throw, success!
        }
        public void 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);
        }
        protected virtual void SetProperty(HttpActionContext actionContext, ModelBindingContext bindingContext, ModelMetadata propertyMetadata, ComplexModelDtoResult dtoResult, ModelValidator requiredValidator)
        {
            PropertyDescriptor propertyDescriptor = TypeDescriptorHelper.Get(bindingContext.ModelType).GetProperties().Find(propertyMetadata.PropertyName, true /* ignoreCase */);
            if (propertyDescriptor == null || propertyDescriptor.IsReadOnly)
            {
                return; // nothing to do
            }

            object value = dtoResult.Model ?? GetPropertyDefaultValue(propertyDescriptor);
            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. See comments in
            // DefaultModelBinder.SetProperty() for more information.
            if (value == null)
            {
                string modelStateKey = dtoResult.ValidationNode.ModelStateKey;
                if (bindingContext.ModelState.IsValidField(modelStateKey))
                {
                    if (requiredValidator != null)
                    {
                        foreach (ModelValidationResult validationResult in requiredValidator.Validate(propertyMetadata, bindingContext.Model))
                        {
                            bindingContext.ModelState.AddModelError(modelStateKey, validationResult.Message);
                        }
                    }
                }
            }

            if (value != null || TypeHelper.TypeAllowsNullValue(propertyDescriptor.PropertyType))
            {
                try
                {
                    propertyDescriptor.SetValue(bindingContext.Model, value);
                }
                catch (Exception ex)
                {
                    // don't display a duplicate error message if a binding error has already occurred for this field
                    string modelStateKey = dtoResult.ValidationNode.ModelStateKey;
                    if (bindingContext.ModelState.IsValidField(modelStateKey))
                    {
                        bindingContext.ModelState.AddModelError(modelStateKey, ex);
                    }
                }
            }
            else
            {
                // trying to set a non-nullable value type to null, need to make sure there's a message
                string modelStateKey = dtoResult.ValidationNode.ModelStateKey;
                if (bindingContext.ModelState.IsValidField(modelStateKey))
                {
                    dtoResult.ValidationNode.Validated += CreateNullCheckFailedHandler(propertyMetadata, value);
                }
            }
        }
        public void BindModel()
        {
            // Arrange
            MyModel             model              = new MyModel();
            ModelMetadata       modelMetadata      = new EmptyModelMetadataProvider().GetMetadataForType(() => model, typeof(MyModel));
            ComplexModelDto     dto                = new ComplexModelDto(modelMetadata, modelMetadata.Properties);
            Mock <IModelBinder> mockStringBinder   = new Mock <IModelBinder>();
            Mock <IModelBinder> mockIntBinder      = new Mock <IModelBinder>();
            Mock <IModelBinder> mockDateTimeBinder = new Mock <IModelBinder>();
            HttpActionContext   context            = ContextUtil.CreateActionContext();

            context.ControllerContext.Configuration.Services.ReplaceRange(typeof(ModelBinderProvider),
                                                                          new ModelBinderProvider[] {
                new SimpleModelBinderProvider(typeof(string), mockStringBinder.Object)
                {
                    SuppressPrefixCheck = true
                },
                new SimpleModelBinderProvider(typeof(int), mockIntBinder.Object)
                {
                    SuppressPrefixCheck = true
                },
                new SimpleModelBinderProvider(typeof(DateTime), mockDateTimeBinder.Object)
                {
                    SuppressPrefixCheck = true
                }
            });

            mockStringBinder
            .Setup(b => b.BindModel(context, It.IsAny <ModelBindingContext>()))
            .Returns((HttpActionContext ec, ModelBindingContext mbc) =>
            {
                Assert.Equal(typeof(string), mbc.ModelType);
                Assert.Equal("theModel.StringProperty", mbc.ModelName);
                mbc.ValidationNode = new ModelValidationNode(mbc.ModelMetadata, "theModel.StringProperty");
                mbc.Model          = "someStringValue";
                return(true);
            });
            mockIntBinder
            .Setup(b => b.BindModel(context, It.IsAny <ModelBindingContext>()))
            .Returns((HttpActionContext ec, ModelBindingContext mbc) =>
            {
                Assert.Equal(typeof(int), mbc.ModelType);
                Assert.Equal("theModel.IntProperty", mbc.ModelName);
                mbc.ValidationNode = new ModelValidationNode(mbc.ModelMetadata, "theModel.IntProperty");
                mbc.Model          = 42;
                return(true);
            });
            mockDateTimeBinder
            .Setup(b => b.BindModel(context, It.IsAny <ModelBindingContext>()))
            .Returns((HttpActionContext ec, ModelBindingContext mbc) =>
            {
                Assert.Equal(typeof(DateTime), mbc.ModelType);
                Assert.Equal("theModel.DateTimeProperty", mbc.ModelName);
                return(false);
            });
            ModelBindingContext parentBindingContext = new ModelBindingContext
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => dto, typeof(ComplexModelDto)),
                ModelName     = "theModel",
            };
            ComplexModelDtoModelBinder binder = new ComplexModelDtoModelBinder();

            // Act
            bool retVal = binder.BindModel(context, parentBindingContext);

            // Assert
            Assert.True(retVal);
            Assert.Equal(dto, parentBindingContext.Model);

            ComplexModelDtoResult stringDtoResult = dto.Results[dto.PropertyMetadata.Where(m => m.ModelType == typeof(string)).First()];

            Assert.Equal("someStringValue", stringDtoResult.Model);
            Assert.Equal("theModel.StringProperty", stringDtoResult.ValidationNode.ModelStateKey);

            ComplexModelDtoResult intDtoResult = dto.Results[dto.PropertyMetadata.Where(m => m.ModelType == typeof(int)).First()];

            Assert.Equal(42, intDtoResult.Model);
            Assert.Equal("theModel.IntProperty", intDtoResult.ValidationNode.ModelStateKey);

            // Bind failed, so DateTime won't even be in the DTO dictionary
            bool containsMissingKey = dto.Results.ContainsKey(dto.PropertyMetadata.Where(m => m.ModelType == typeof(DateTime)).First());

            Assert.False(containsMissingKey);
        }
Ejemplo n.º 26
0
        protected virtual void SetProperty(HttpActionContext actionContext, ModelBindingContext bindingContext, ModelMetadata propertyMetadata, ComplexModelDtoResult dtoResult, ModelValidator requiredValidator)
        {
            PropertyDescriptor propertyDescriptor = TypeDescriptorHelper.Get(bindingContext.ModelType).GetProperties().Find(propertyMetadata.PropertyName, true /* ignoreCase */);

            if (propertyDescriptor == null || propertyDescriptor.IsReadOnly)
            {
                return; // nothing to do
            }

            object value = dtoResult.Model ?? GetPropertyDefaultValue(propertyDescriptor);

            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. See comments in
            // DefaultModelBinder.SetProperty() for more information.
            if (value == null)
            {
                string modelStateKey = dtoResult.ValidationNode.ModelStateKey;
                if (bindingContext.ModelState.IsValidField(modelStateKey))
                {
                    RunValidator(requiredValidator, bindingContext, propertyMetadata, modelStateKey);
                }
            }

            if (value != null || TypeHelper.TypeAllowsNullValue(propertyDescriptor.PropertyType))
            {
                try
                {
                    propertyDescriptor.SetValue(bindingContext.Model, value);
                }
                catch (Exception ex)
                {
                    // don't display a duplicate error message if a binding error has already occurred for this field
                    string modelStateKey = dtoResult.ValidationNode.ModelStateKey;
                    if (bindingContext.ModelState.IsValidField(modelStateKey))
                    {
                        bindingContext.ModelState.AddModelError(modelStateKey, ex);
                    }
                }
            }
            else
            {
                // trying to set a non-nullable value type to null, need to make sure there's a message
                string modelStateKey = dtoResult.ValidationNode.ModelStateKey;
                if (bindingContext.ModelState.IsValidField(modelStateKey))
                {
                    dtoResult.ValidationNode.Validated += CreateNullCheckFailedHandler(propertyMetadata, value);
                }
            }
        }