public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { ModelBindingHelper.ValidateBindingContext( bindingContext, typeof(ComplexModelDto), false /* allowNullModel */ ); ComplexModelDto dto = (ComplexModelDto)bindingContext.Model; foreach (ModelMetadata propertyMetadata in dto.PropertyMetadata) { ModelBindingContext propertyBindingContext = new ModelBindingContext(bindingContext) { ModelMetadata = propertyMetadata, ModelName = ModelBindingHelper.CreatePropertyModelName( bindingContext.ModelName, propertyMetadata.PropertyName ) }; // bind and propagate the values // If we can't bind, then leave the result missing (don't add a null). if (actionContext.Bind(propertyBindingContext)) { dto.Results[propertyMetadata] = new ComplexModelDtoResult( propertyBindingContext.Model, propertyBindingContext.ValidationNode ); } } return(true); }
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { if (!CanBindType(bindingContext.ModelType)) { return false; } if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName)) { return false; } bindingContext.Model = Activator.CreateInstance(bindingContext.ModelType); ComplexModelDto dto = new ComplexModelDto(bindingContext.ModelMetadata, bindingContext.PropertyMetadata.Values); ModelBindingContext subContext = new ModelBindingContext(bindingContext) { ModelMetadata = actionContext.GetMetadataProvider().GetMetadataForType(() => dto, typeof(ComplexModelDto)), ModelName = bindingContext.ModelName }; actionContext.Bind(subContext); foreach (KeyValuePair<ModelMetadata, ComplexModelDtoResult> item in dto.Results) { ModelMetadata propertyMetadata = item.Key; ComplexModelDtoResult dtoResult = item.Value; if (dtoResult != null) { PropertyInfo propertyInfo = bindingContext.ModelType.GetProperty(propertyMetadata.PropertyName); if (propertyInfo.CanWrite) { propertyInfo.SetValue(bindingContext.Model, dtoResult.Model); } } } return true; }
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { ModelBindingHelper.ValidateBindingContext(bindingContext, typeof(ComplexModelDto), false /* allowNullModel */); ComplexModelDto dto = (ComplexModelDto)bindingContext.Model; foreach (ModelMetadata propertyMetadata in dto.PropertyMetadata) { ModelBindingContext propertyBindingContext = new ModelBindingContext(bindingContext) { ModelMetadata = propertyMetadata, ModelName = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName, propertyMetadata.PropertyName) }; // bind and propagate the values IModelBinder propertyBinder; if (actionContext.TryGetBinder(propertyBindingContext, out propertyBinder)) { if (propertyBinder.BindModel(actionContext, propertyBindingContext)) { dto.Results[propertyMetadata] = new ComplexModelDtoResult(propertyBindingContext.Model, propertyBindingContext.ValidationNode); } else { dto.Results[propertyMetadata] = null; } } } return(true); }
public void ProcessDto_BindRequiredFieldMissing_RaisesModelError() { // Arrange ModelWithBindRequired model = new ModelWithBindRequired { Name = "original value", Age = -20 }; ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = containerMetadata, ModelName = "theModel" }; ComplexModelDto dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties); ModelMetadata nameProperty = dto.PropertyMetadata.Single(o => o.PropertyName == "Name"); dto.Results[nameProperty] = new ComplexModelDtoResult("John Doe", new ModelValidationNode(nameProperty, "")); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act & assert testableBinder.ProcessDto(context, bindingContext, dto); Assert.False(bindingContext.ModelState.IsValid); }
public virtual bool BindModel( HttpActionContext actionContext, ModelBindingContext bindingContext ) { ModelBindingHelper.ValidateBindingContext(bindingContext); if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName)) { // no values to bind return(false); } if (!CanBindType(bindingContext.ModelType)) { return(false); } EnsureModel(actionContext, bindingContext); IEnumerable <ModelMetadata> propertyMetadatas = GetMetadataForProperties( actionContext, bindingContext ); ComplexModelDto dto = CreateAndPopulateDto( actionContext, bindingContext, propertyMetadatas ); // post-processing, e.g. property setters and hooking up validation ProcessDto(actionContext, bindingContext, dto); bindingContext.ValidationNode.ValidateAllProperties = true; // complex models require full validation return(true); }
private ComplexModelDto CreateAndPopulateDto( HttpActionContext actionContext, ModelBindingContext bindingContext, IEnumerable <ModelMetadata> propertyMetadatas ) { ModelMetadataProvider metadataProvider = MetadataProvider ?? actionContext.GetMetadataProvider(); // create a DTO and call into the DTO binder ComplexModelDto originalDto = new ComplexModelDto( bindingContext.ModelMetadata, propertyMetadatas ); ModelBindingContext dtoBindingContext = new ModelBindingContext(bindingContext) { ModelMetadata = metadataProvider.GetMetadataForType( () => originalDto, typeof(ComplexModelDto) ), ModelName = bindingContext.ModelName }; actionContext.Bind(dtoBindingContext); return((ComplexModelDto)dtoBindingContext.Model); }
public void ProcessDto_RequiredFieldNull_RaisesModelError() { // Arrange ModelWithRequired model = new ModelWithRequired(); ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = containerMetadata, ModelName = "theModel" }; ComplexModelDto dto = new ComplexModelDto( containerMetadata, containerMetadata.Properties ); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Make Age valid and City invalid. ModelMetadata propertyMetadata = dto.PropertyMetadata.Single( p => p.PropertyName == "Age" ); dto.Results[propertyMetadata] = new ComplexModelDtoResult( 23, new ModelValidationNode(propertyMetadata, "theModel.Age") ); propertyMetadata = dto.PropertyMetadata.Single(p => p.PropertyName == "City"); dto.Results[propertyMetadata] = new ComplexModelDtoResult( null, new ModelValidationNode(propertyMetadata, "theModel.City") ); // Act testableBinder.ProcessDto(context, bindingContext, dto); // Assert ModelStateDictionary modelStateDictionary = bindingContext.ModelState; Assert.False(modelStateDictionary.IsValid); Assert.Single(modelStateDictionary); // Check City error. ModelState modelState; Assert.True(modelStateDictionary.TryGetValue("theModel.City", out modelState)); ModelError modelError = Assert.Single(modelState.Errors); Assert.Null(modelError.Exception); Assert.NotNull(modelError.ErrorMessage); Assert.Equal("The City field is required.", modelError.ErrorMessage); }
public void ProcessDto_BindRequiredFieldNull_RaisesModelError() { // Arrange ModelWithBindRequired model = new ModelWithBindRequired { Name = "original value", Age = -20 }; ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext() { ModelMetadata = containerMetadata, ModelName = "theModel", ModelState = context.ModelState, }; ComplexModelDto dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); ModelMetadata propertyMetadata = dto.PropertyMetadata.Single(o => o.PropertyName == "Name"); dto.Results[propertyMetadata] = new ComplexModelDtoResult("John Doe", new ModelValidationNode(propertyMetadata, "theModel.Name")); // Attempt to set non-Nullable property to null. HttpBindRequiredAttribute should not be relevant in this // case because the binding exists. propertyMetadata = dto.PropertyMetadata.Single(o => o.PropertyName == "Age"); dto.Results[propertyMetadata] = new ComplexModelDtoResult(null, new ModelValidationNode(propertyMetadata, "theModel.Age")); // Act; must also Validate because null-check error handler is late-bound testableBinder.ProcessDto(context, bindingContext, dto); bindingContext.ValidationNode.Validate(context); // Assert ModelStateDictionary modelStateDictionary = bindingContext.ModelState; Assert.False(modelStateDictionary.IsValid); Assert.Equal(1, modelStateDictionary.Count); // Check Age error. ModelState modelState; Assert.True(modelStateDictionary.TryGetValue("theModel.Age", out modelState)); Assert.Equal(1, modelState.Errors.Count); ModelError modelError = modelState.Errors[0]; Assert.Null(modelError.Exception); Assert.NotNull(modelError.ErrorMessage); Assert.Equal("A value is required.", modelError.ErrorMessage); }
public void ProcessDto_Success() { // Arrange DateTime dob = new DateTime(2001, 1, 1); PersonWithBindExclusion model = new PersonWithBindExclusion { DateOfBirth = dob }; ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = containerMetadata }; ComplexModelDto dto = new ComplexModelDto( containerMetadata, containerMetadata.Properties ); ModelMetadata firstNameProperty = dto.PropertyMetadata.Single( o => o.PropertyName == "FirstName" ); dto.Results[firstNameProperty] = new ComplexModelDtoResult( "John", new ModelValidationNode(firstNameProperty, "") ); ModelMetadata lastNameProperty = dto.PropertyMetadata.Single( o => o.PropertyName == "LastName" ); dto.Results[lastNameProperty] = new ComplexModelDtoResult( "Doe", new ModelValidationNode(lastNameProperty, "") ); ModelMetadata dobProperty = dto.PropertyMetadata.Single( o => o.PropertyName == "DateOfBirth" ); dto.Results[dobProperty] = null; TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.ProcessDto(context, bindingContext, dto); // Assert Assert.Equal("John", model.FirstName); Assert.Equal("Doe", model.LastName); Assert.Equal(dob, model.DateOfBirth); Assert.True(bindingContext.ModelState.IsValid); }
public void ProcessDto_BindRequiredFieldMissing_RaisesModelError() { // Arrange ModelWithBindRequired model = new ModelWithBindRequired { Name = "original value", Age = -20 }; ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = containerMetadata, ModelName = "theModel" }; ComplexModelDto dto = new ComplexModelDto( containerMetadata, containerMetadata.Properties ); ModelMetadata nameProperty = dto.PropertyMetadata.Single(o => o.PropertyName == "Name"); dto.Results[nameProperty] = new ComplexModelDtoResult( "John Doe", new ModelValidationNode(nameProperty, "") ); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.ProcessDto(context, bindingContext, dto); // Assert ModelStateDictionary modelStateDictionary = bindingContext.ModelState; Assert.False(modelStateDictionary.IsValid); Assert.Single(modelStateDictionary); // Check Age error. ModelState modelState; Assert.True(modelStateDictionary.TryGetValue("theModel.Age", out modelState)); ModelError modelError = Assert.Single(modelState.Errors); Assert.Null(modelError.Exception); Assert.NotNull(modelError.ErrorMessage); Assert.Equal("The Age property is required.", modelError.ErrorMessage); }
public virtual bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { ModelBindingHelper.ValidateBindingContext(bindingContext); EnsureModel(actionContext, bindingContext); IEnumerable <ModelMetadata> propertyMetadatas = GetMetadataForProperties(actionContext, bindingContext); ComplexModelDto dto = CreateAndPopulateDto(actionContext, bindingContext, propertyMetadatas); // post-processing, e.g. property setters and hooking up validation ProcessDto(actionContext, bindingContext, dto); bindingContext.ValidationNode.ValidateAllProperties = true; // complex models require full validation return(true); }
public void ConstructorSetsProperties() { // Arrange ModelMetadata modelMetadata = GetModelMetadata(); ModelMetadata[] propertyMetadata = new ModelMetadata[0]; // Act ComplexModelDto dto = new ComplexModelDto(modelMetadata, propertyMetadata); // Assert Assert.Equal(modelMetadata, dto.ModelMetadata); Assert.Equal(propertyMetadata, dto.PropertyMetadata.ToArray()); Assert.Empty(dto.Results); }
public void ProcessDto_RequiredFieldMissing_RaisesModelError() { // Arrange ModelWithRequired model = new ModelWithRequired(); ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = containerMetadata, ModelName = "theModel" }; // Set no properties though Age (a non-Nullable struct) and City (a class) properties are required. ComplexModelDto dto = new ComplexModelDto( containerMetadata, containerMetadata.Properties ); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.ProcessDto(context, bindingContext, dto); // Assert ModelStateDictionary modelStateDictionary = bindingContext.ModelState; Assert.False(modelStateDictionary.IsValid); Assert.Equal(2, modelStateDictionary.Count); // Check Age error. ModelState modelState; Assert.True(modelStateDictionary.TryGetValue("theModel.Age", out modelState)); ModelError modelError = Assert.Single(modelState.Errors); Assert.Null(modelError.Exception); Assert.NotNull(modelError.ErrorMessage); Assert.Equal("The Age field is required.", modelError.ErrorMessage); // Check City error. Assert.True(modelStateDictionary.TryGetValue("theModel.City", out modelState)); modelError = Assert.Single(modelState.Errors); Assert.Null(modelError.Exception); Assert.NotNull(modelError.ErrorMessage); Assert.Equal("The City field is required.", modelError.ErrorMessage); }
private ComplexModelDto CreateAndPopulateDto(HttpActionContext actionContext, ModelBindingContext bindingContext, IEnumerable<ModelMetadata> propertyMetadatas) { ModelMetadataProvider metadataProvider = MetadataProvider ?? actionContext.GetMetadataProvider(); // create a DTO and call into the DTO binder ComplexModelDto originalDto = new ComplexModelDto(bindingContext.ModelMetadata, propertyMetadatas); ModelBindingContext dtoBindingContext = new ModelBindingContext(bindingContext) { ModelMetadata = metadataProvider.GetMetadataForType(() => originalDto, typeof(ComplexModelDto)), ModelName = bindingContext.ModelName }; IModelBinder dtoBinder = actionContext.GetBinder(dtoBindingContext); dtoBinder.BindModel(actionContext, dtoBindingContext); return (ComplexModelDto)dtoBindingContext.Model; }
public void ProcessDto_RequiredFieldMissing_RaisesModelErrorWithMessage() { // Arrange Person model = new Person(); ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = containerMetadata, ModelName = "theModel" }; // Set no properties though ValueTypeRequired (a non-Nullable struct) property is required. ComplexModelDto dto = new ComplexModelDto( containerMetadata, containerMetadata.Properties ); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.ProcessDto(context, bindingContext, dto); // Assert ModelStateDictionary modelStateDictionary = bindingContext.ModelState; Assert.False(modelStateDictionary.IsValid); Assert.Single(modelStateDictionary); // Check ValueTypeRequired error. ModelState modelState; Assert.True( modelStateDictionary.TryGetValue("theModel.ValueTypeRequired", out modelState) ); ModelError modelError = Assert.Single(modelState.Errors); Assert.Null(modelError.Exception); Assert.NotNull(modelError.ErrorMessage); Assert.Equal("Sample message", modelError.ErrorMessage); }
public void ProcessDto_RequiredFieldNull_RaisesModelErrorWithMessage() { // Arrange Person model = new Person(); ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = containerMetadata, ModelName = "theModel" }; ComplexModelDto dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Make ValueTypeRequired invalid. ModelMetadata propertyMetadata = dto.PropertyMetadata.Single(p => p.PropertyName == "ValueTypeRequired"); dto.Results[propertyMetadata] = new ComplexModelDtoResult(null, new ModelValidationNode(propertyMetadata, "theModel.ValueTypeRequired")); // Act testableBinder.ProcessDto(context, bindingContext, dto); // Assert ModelStateDictionary modelStateDictionary = bindingContext.ModelState; Assert.False(modelStateDictionary.IsValid); Assert.Equal(1, modelStateDictionary.Count); // Check ValueTypeRequired error. ModelState modelState; Assert.True(modelStateDictionary.TryGetValue("theModel.ValueTypeRequired", out modelState)); Assert.Equal(1, modelState.Errors.Count); ModelError modelError = modelState.Errors[0]; Assert.Null(modelError.Exception); Assert.NotNull(modelError.ErrorMessage); Assert.Equal("Sample message", modelError.ErrorMessage); }
public bool BindModel(System.Web.Http.Controllers.HttpActionContext actionContext, ModelBindingContext bindingContext) { if (!CanBindType(bindingContext.ModelType)) { return false; } if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))//前缀检查,查看valueprovider是否提供了该名称的数据 { return false; } //创建目标类型的空对象 bindingContext.Model = Activator.CreateInstance(bindingContext.ModelType); //创建针对目标类型的ComplexModelDto ComplexModelDto dto = new ComplexModelDto(bindingContext.ModelMetadata, bindingContext.PropertyMetadata.Values); ///创建一个子ModelBindingContext用于作为参数,直接调用HttpActionContextExtensions的里对HttpActionContext的扩展方法,进行模型绑定,命名空间:System.Web.Http.Controllers; ModelBindingContext subContext = new ModelBindingContext(bindingContext) { ModelMetadata = actionContext.GetMetadataProvider().GetMetadataForType(() => dto, typeof(ComplexModelDto)), ModelName = bindingContext.ModelName }; ///,直接调用HttpActionContextExtensions的里对HttpActionContext的扩展方法Bind,进行模型绑定,命名空间:System.Web.Http.Controllers; actionContext.Bind(subContext); foreach (KeyValuePair<ModelMetadata, ComplexModelDtoResult> item in dto.Results) { ModelMetadata metadata = item.Key; ComplexModelDtoResult result = item.Value; if (result != null) { /// PropertyInfo propertyinfo = bindingContext.ModelType.GetProperty(metadata.PropertyName); ///实现在Bin(l方 法之中的ModeI绑定完成之后,目 标对象相应的属性值将会保存到 CompIexMode1Dto对象的Rcsults属 性中。我们直接从中获取相应的属性值,并对创建的空 //对象对应的非只读属性进行赋值即可。 if (propertyinfo.CanWrite) { propertyinfo.SetValue(bindingContext.Model, result.Model); } } } return true; }
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 ProcessDto_RequiredFieldMissing_RaisesModelError() { // Arrange ModelWithRequired model = new ModelWithRequired(); ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = containerMetadata, ModelName = "theModel" }; // Set no properties though Age (a non-Nullable struct) and City (a class) properties are required. ComplexModelDto dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.ProcessDto(context, bindingContext, dto); // Assert ModelStateDictionary modelStateDictionary = bindingContext.ModelState; Assert.False(modelStateDictionary.IsValid); Assert.Equal(2, modelStateDictionary.Count); // Check Age error. ModelState modelState; Assert.True(modelStateDictionary.TryGetValue("theModel.Age", out modelState)); Assert.Equal(1, modelState.Errors.Count); ModelError modelError = modelState.Errors[0]; Assert.Null(modelError.Exception); Assert.NotNull(modelError.ErrorMessage); Assert.Equal("The Age field is required.", modelError.ErrorMessage); // Check City error. Assert.True(modelStateDictionary.TryGetValue("theModel.City", out modelState)); Assert.Equal(1, modelState.Errors.Count); modelError = modelState.Errors[0]; Assert.Null(modelError.Exception); Assert.NotNull(modelError.ErrorMessage); Assert.Equal("The City field is required.", modelError.ErrorMessage); }
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); }
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.ServiceResolver.SetServices(typeof(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); ComplexModelDtoResult dateTimeDtoResult = dto.Results[dto.PropertyMetadata.Where(m => m.ModelType == typeof(DateTime)).First()]; Assert.Null(dateTimeDtoResult); }
public void ProcessDto_BindRequiredFieldMissing_RaisesModelError() { // Arrange ModelWithBindRequired model = new ModelWithBindRequired { Name = "original value", Age = -20 }; ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = containerMetadata, ModelName = "theModel" }; ComplexModelDto dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties); ModelMetadata nameProperty = dto.PropertyMetadata.Single(o => o.PropertyName == "Name"); dto.Results[nameProperty] = new ComplexModelDtoResult("John Doe", new ModelValidationNode(nameProperty, "")); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.ProcessDto(context, bindingContext, dto); // Assert ModelStateDictionary modelStateDictionary = bindingContext.ModelState; Assert.False(modelStateDictionary.IsValid); Assert.Equal(1, modelStateDictionary.Count); // Check Age error. ModelState modelState; Assert.True(modelStateDictionary.TryGetValue("theModel.Age", out modelState)); Assert.Equal(1, modelState.Errors.Count); ModelError modelError = modelState.Errors[0]; Assert.Null(modelError.Exception); Assert.NotNull(modelError.ErrorMessage); Assert.Equal("The Age property is required.", modelError.ErrorMessage); }
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 void ProcessDto_RequiredFieldMissing_RaisesModelErrorWithMessage() { // Arrange Person model = new Person(); ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = containerMetadata, ModelName = "theModel" }; // Set no properties though ValueTypeRequired (a non-Nullable struct) property is required. ComplexModelDto dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties); TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.ProcessDto(context, bindingContext, dto); // Assert ModelStateDictionary modelStateDictionary = bindingContext.ModelState; Assert.False(modelStateDictionary.IsValid); Assert.Equal(1, modelStateDictionary.Count); // Check ValueTypeRequired error. ModelState modelState; Assert.True(modelStateDictionary.TryGetValue("theModel.ValueTypeRequired", out modelState)); Assert.Equal(1, modelState.Errors.Count); ModelError modelError = modelState.Errors[0]; Assert.Null(modelError.Exception); Assert.NotNull(modelError.ErrorMessage); Assert.Equal("Sample message", modelError.ErrorMessage); }
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 void ProcessDto_Success() { // Arrange DateTime dob = new DateTime(2001, 1, 1); PersonWithBindExclusion model = new PersonWithBindExclusion { DateOfBirth = dob }; ModelMetadata containerMetadata = GetMetadataForObject(model); HttpActionContext context = ContextUtil.CreateActionContext(); ModelBindingContext bindingContext = new ModelBindingContext { ModelMetadata = containerMetadata }; ComplexModelDto dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties); ModelMetadata firstNameProperty = dto.PropertyMetadata.Single(o => o.PropertyName == "FirstName"); dto.Results[firstNameProperty] = new ComplexModelDtoResult("John", new ModelValidationNode(firstNameProperty, "")); ModelMetadata lastNameProperty = dto.PropertyMetadata.Single(o => o.PropertyName == "LastName"); dto.Results[lastNameProperty] = new ComplexModelDtoResult("Doe", new ModelValidationNode(lastNameProperty, "")); ModelMetadata dobProperty = dto.PropertyMetadata.Single(o => o.PropertyName == "DateOfBirth"); dto.Results[dobProperty] = null; TestableMutableObjectModelBinder testableBinder = new TestableMutableObjectModelBinder(); // Act testableBinder.ProcessDto(context, bindingContext, dto); // Assert Assert.Equal("John", model.FirstName); Assert.Equal("Doe", model.LastName); Assert.Equal(dob, model.DateOfBirth); Assert.True(bindingContext.ModelState.IsValid); }
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); } } }