A change in CompositeModelValidator.Validate method breaking some functionality of existing applications.
MVC 4,
```
public override IEnumerable<ModelValidationResult> Validate(object container)
{
bool propertiesValid = true;
foreach (ModelMetadata propertyMetadata in Metadata.Properties)
{
foreach (ModelValidator propertyValidator in propertyMetadata.GetValidators(ControllerContext))
{
foreach (ModelValidationResult propertyResult in propertyValidator.Validate(Metadata.Model))
{
propertiesValid = false;
yield return new ModelValidationResult
{
MemberName = DefaultModelBinder.CreateSubPropertyName(propertyMetadata.PropertyName, propertyResult.MemberName),
Message = propertyResult.Message
};
}
}
}
if (propertiesValid)
{
foreach (ModelValidator typeValidator in Metadata.GetValidators(ControllerContext))
{
foreach (ModelValidationResult typeResult in typeValidator.Validate(container))
{
yield return typeResult;
}
}
}
}
```
MVC 5,
```
public override IEnumerable<ModelValidationResult> Validate(object container)
{
bool propertiesValid = true;
ModelMetadata[] properties = Metadata.PropertiesAsArray;
// Performance sensitive loops
for (int propertyIndex = 0; propertyIndex < properties.Length; propertyIndex++)
{
ModelMetadata propertyMetadata = properties[propertyIndex];
foreach (ModelValidator propertyValidator in propertyMetadata.GetValidators(ControllerContext))
{
foreach (ModelValidationResult propertyResult in propertyValidator.Validate(Metadata.Model))
{
propertiesValid = false;
yield return CreateSubPropertyResult(propertyMetadata, propertyResult);
}
}
}
if (propertiesValid)
{
foreach (ModelValidator typeValidator in Metadata.GetValidators(ControllerContext))
{
foreach (ModelValidationResult typeResult in typeValidator.Validate(container))
{
yield return typeResult;
}
}
}
}
```
Pre MVC 5 calling the property getter again before triggering validation. But MVC 5 doesn't. For detail please see,
http://forums.asp.net/t/1962641.aspx?Data+annotation+model+validation+in+MVC5+different+than+in+MVC3
Comments: Hey @Imran and @Roger. The fix was made for performance reasons. And although it's a breaking change, changing the behavior again is in itself a break change (5.0 + 5.1 -> vNext). Hence we carefully want to look at the scenario we are trying to fix. Looking at the code posted in the discussion thread, making a property that mutates the data coming in is not a recommended coding practice. So regretfully we decided not to fix this. If you have another scenario please let us know.
MVC 4,
```
public override IEnumerable<ModelValidationResult> Validate(object container)
{
bool propertiesValid = true;
foreach (ModelMetadata propertyMetadata in Metadata.Properties)
{
foreach (ModelValidator propertyValidator in propertyMetadata.GetValidators(ControllerContext))
{
foreach (ModelValidationResult propertyResult in propertyValidator.Validate(Metadata.Model))
{
propertiesValid = false;
yield return new ModelValidationResult
{
MemberName = DefaultModelBinder.CreateSubPropertyName(propertyMetadata.PropertyName, propertyResult.MemberName),
Message = propertyResult.Message
};
}
}
}
if (propertiesValid)
{
foreach (ModelValidator typeValidator in Metadata.GetValidators(ControllerContext))
{
foreach (ModelValidationResult typeResult in typeValidator.Validate(container))
{
yield return typeResult;
}
}
}
}
```
MVC 5,
```
public override IEnumerable<ModelValidationResult> Validate(object container)
{
bool propertiesValid = true;
ModelMetadata[] properties = Metadata.PropertiesAsArray;
// Performance sensitive loops
for (int propertyIndex = 0; propertyIndex < properties.Length; propertyIndex++)
{
ModelMetadata propertyMetadata = properties[propertyIndex];
foreach (ModelValidator propertyValidator in propertyMetadata.GetValidators(ControllerContext))
{
foreach (ModelValidationResult propertyResult in propertyValidator.Validate(Metadata.Model))
{
propertiesValid = false;
yield return CreateSubPropertyResult(propertyMetadata, propertyResult);
}
}
}
if (propertiesValid)
{
foreach (ModelValidator typeValidator in Metadata.GetValidators(ControllerContext))
{
foreach (ModelValidationResult typeResult in typeValidator.Validate(container))
{
yield return typeResult;
}
}
}
}
```
Pre MVC 5 calling the property getter again before triggering validation. But MVC 5 doesn't. For detail please see,
http://forums.asp.net/t/1962641.aspx?Data+annotation+model+validation+in+MVC5+different+than+in+MVC3
Comments: Hey @Imran and @Roger. The fix was made for performance reasons. And although it's a breaking change, changing the behavior again is in itself a break change (5.0 + 5.1 -> vNext). Hence we carefully want to look at the scenario we are trying to fix. Looking at the code posted in the discussion thread, making a property that mutates the data coming in is not a recommended coding practice. So regretfully we decided not to fix this. If you have another scenario please let us know.