Removing creating ModelValidationNode by default in CompositeModelBinder.

This moves the responsibility of of MVN creation to individual model binders if they want the individual models to be validated.
This commit is contained in:
Harsh Gupta 2015-05-27 12:16:11 -07:00
parent 3fe0490b99
commit 4f419eee55
13 changed files with 83 additions and 44 deletions

View File

@ -89,12 +89,16 @@ namespace Microsoft.AspNet.Mvc
metadata, metadata,
modelBindingResult.Model); modelBindingResult.Model);
var validationContext = new ModelValidationContext( if (modelBindingResult.ValidationNode != null)
modelBindingContext.BindingSource, {
operationContext.ValidatorProvider, var validationContext = new ModelValidationContext(
modelState, modelBindingContext.BindingSource,
modelExplorer); operationContext.ValidatorProvider,
_validator.Validate(validationContext, modelBindingResult.ValidationNode); modelState,
modelExplorer);
_validator.Validate(validationContext, modelBindingResult.ValidationNode);
}
} }
return modelBindingResult; return modelBindingResult;

View File

@ -39,12 +39,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
try try
{ {
var model = Convert.FromBase64String(value); var model = Convert.FromBase64String(value);
var validationNode = new ModelValidationNode(
bindingContext.ModelName,
bindingContext.ModelMetadata,
model);
// We do not need to set an explict ModelValidationNode since CompositeModelBinder does that automatically.
return new ModelBindingResult( return new ModelBindingResult(
model, model,
bindingContext.ModelName, bindingContext.ModelName,
isModelSet: true); isModelSet: true,
validationNode: validationNode);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -17,7 +17,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
if (bindingContext.ModelType == typeof(CancellationToken)) if (bindingContext.ModelType == typeof(CancellationToken))
{ {
var model = bindingContext.OperationBindingContext.HttpContext.RequestAborted; var model = bindingContext.OperationBindingContext.HttpContext.RequestAborted;
return Task.FromResult(new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true)); var validationNode =
new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model);
return Task.FromResult(new ModelBindingResult(
model,
bindingContext.ModelName,
isModelSet: true,
validationNode: validationNode));
} }
return Task.FromResult<ModelBindingResult>(null); return Task.FromResult<ModelBindingResult>(null);

View File

@ -83,24 +83,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
} }
} }
// Update the model validation node if the model binding result was set but no validation node was provided.
// This would typically be the case where leaf level model binders, do not have to add a validation node
// for validation to take effect. The composite being the entry point for model binders, takes care or
// adding missing validation nodes.
var modelValidationNode = modelBindingResult.ValidationNode;
if (modelBindingResult.IsModelSet && modelValidationNode == null)
{
modelValidationNode = new ModelValidationNode(
bindingKey,
bindingContext.ModelMetadata,
modelBindingResult.Model);
}
return new ModelBindingResult( return new ModelBindingResult(
modelBindingResult.Model, modelBindingResult.Model,
bindingKey, bindingKey,
modelBindingResult.IsModelSet, modelBindingResult.IsModelSet,
modelValidationNode); modelBindingResult.ValidationNode);
} }
private async Task<ModelBindingResult> TryBind(ModelBindingContext bindingContext) private async Task<ModelBindingResult> TryBind(ModelBindingContext bindingContext)

View File

@ -46,7 +46,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
model = new FormCollection(new Dictionary<string, string[]>()); model = new FormCollection(new Dictionary<string, string[]>());
} }
return new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true); var validationNode =
new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model);
return new ModelBindingResult(
model,
bindingContext.ModelName,
isModelSet: true,
validationNode: validationNode);
} }
} }
} }

View File

@ -24,14 +24,26 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
var postedFiles = await GetFormFilesAsync(bindingContext); var postedFiles = await GetFormFilesAsync(bindingContext);
var value = postedFiles.FirstOrDefault(); var value = postedFiles.FirstOrDefault();
return new ModelBindingResult(value, bindingContext.ModelName, isModelSet: value != null); var validationNode =
new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value);
return new ModelBindingResult(
value,
bindingContext.ModelName,
isModelSet: value != null,
validationNode: validationNode);
} }
else if (typeof(IEnumerable<IFormFile>).GetTypeInfo().IsAssignableFrom( else if (typeof(IEnumerable<IFormFile>).GetTypeInfo().IsAssignableFrom(
bindingContext.ModelType.GetTypeInfo())) bindingContext.ModelType.GetTypeInfo()))
{ {
var postedFiles = await GetFormFilesAsync(bindingContext); var postedFiles = await GetFormFilesAsync(bindingContext);
var value = ModelBindingHelper.ConvertValuesToCollectionType(bindingContext.ModelType, postedFiles); var value = ModelBindingHelper.ConvertValuesToCollectionType(bindingContext.ModelType, postedFiles);
return new ModelBindingResult(value, bindingContext.ModelName, isModelSet: value != null); var validationNode =
new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value);
return new ModelBindingResult(
value,
bindingContext.ModelName,
isModelSet: value != null,
validationNode: validationNode);
} }
return null; return null;

View File

@ -30,12 +30,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
newModel = valueProviderResult.ConvertTo(bindingContext.ModelType); newModel = valueProviderResult.ConvertTo(bindingContext.ModelType);
ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref newModel); ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref newModel);
var validationNode = new ModelValidationNode(
bindingContext.ModelName,
bindingContext.ModelMetadata,
newModel);
// We do not need to set an explict ModelValidationNode since CompositeModelBinder does that automatically.
return new ModelBindingResult( return new ModelBindingResult(
newModel, newModel,
bindingContext.ModelName, bindingContext.ModelName,
isModelSet: true); isModelSet: true,
validationNode: validationNode);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -19,12 +19,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
var model = valueProviderResult.RawValue; var model = valueProviderResult.RawValue;
ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref model); ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref model);
var validationNode = new ModelValidationNode(
bindingContext.ModelName,
bindingContext.ModelMetadata,
model);
// We do not need to set an explict ModelValidationNode since CompositeModelBinder does that automatically.
return new ModelBindingResult( return new ModelBindingResult(
model, model,
bindingContext.ModelName, bindingContext.ModelName,
isModelSet: true); isModelSet: true,
validationNode: validationNode);
} }
internal static async Task<ValueProviderResult> GetCompatibleValueProviderResult(ModelBindingContext context) internal static async Task<ValueProviderResult> GetCompatibleValueProviderResult(ModelBindingContext context)

View File

@ -309,7 +309,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
if (mbc.ModelType == typeof(int)) if (mbc.ModelType == typeof(int))
{ {
return Task.FromResult(new ModelBindingResult(42, mbc.ModelName, true)); var model = 42;
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 Task.FromResult<ModelBindingResult>(null);
}); });
@ -325,7 +327,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{ {
if (mbc.ModelType == typeof(string)) if (mbc.ModelType == typeof(string))
{ {
return Task.FromResult(new ModelBindingResult("some-value", mbc.ModelName, true)); 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 Task.FromResult<ModelBindingResult>(null);
}); });

View File

@ -588,10 +588,14 @@ namespace Microsoft.AspNet.Mvc.Core.Test
private static ActionBindingContext GetActionBindingContext(object model) private static ActionBindingContext GetActionBindingContext(object model)
{ {
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
binder binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) .Returns<ModelBindingContext>(mbc =>
.Returns(Task.FromResult( {
result: new ModelBindingResult(model: model, key: string.Empty, isModelSet: true))); var validationNode = new ModelValidationNode(string.Empty, mbc.ModelMetadata, model);
return Task.FromResult(
result: new ModelBindingResult(model, string.Empty, isModelSet: true, validationNode: validationNode));
});
return new ActionBindingContext() return new ActionBindingContext()
{ {
ModelBinder = binder.Object, ModelBinder = binder.Object,

View File

@ -74,7 +74,9 @@ namespace ModelBindingWebSite.Controllers
// by the type converter binder. // by the type converter binder.
OrderStatus model; OrderStatus model;
var isModelSet = Enum.TryParse<OrderStatus>("Status" + request.Query.Get("status"), out model); var isModelSet = Enum.TryParse<OrderStatus>("Status" + request.Query.Get("status"), out model);
return Task.FromResult(new ModelBindingResult(model, "status", isModelSet)); var validationNode =
new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model);
return Task.FromResult(new ModelBindingResult(model, "status", isModelSet, validationNode));
} }
return Task.FromResult<ModelBindingResult>(null); return Task.FromResult<ModelBindingResult>(null);
@ -99,7 +101,9 @@ namespace ModelBindingWebSite.Controllers
var value = await bindingContext.ValueProvider.GetValueAsync(key); var value = await bindingContext.ValueProvider.GetValueAsync(key);
model.ProductId = (int)value.ConvertTo(typeof(int)); model.ProductId = (int)value.ConvertTo(typeof(int));
return new ModelBindingResult(model, key, true); var validationNode =
new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value);
return new ModelBindingResult(model, key, true, validationNode);
} }
return null; return null;