My approach is to add a conditional annotation check attribute, which is learned from foolproof .
Make SaveMode part of the view model.
Mark nullable properties so that values ββare optional if SaveMode not Finalize .
But add the special annotation attribute [FinalizeRequired] :
[FinalizeRequired] public int? SomeProperty { get; set; } [FinalizeRequiredCollection] public List<Item> Items { get; set; }
Here is the code for the attribute:
[AttributeUsage(AttributeTargets.Property)] public abstract class FinalizeValidationAttribute : ValidationAttribute { public const string DependentProperty = "SaveMode"; protected abstract bool IsNotNull(object value); protected static SaveModeEnum GetSaveMode(ValidationContext validationContext) { var saveModeProperty = validationContext.ObjectType.GetProperty(DependentProperty); if (saveModeProperty == null) return SaveModeEnum.Save; return (SaveModeEnum) saveModeProperty.GetValue(validationContext.ObjectInstance); } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var saveMode = GetSaveMode(validationContext); if (saveMode != SaveModeEnum.SaveFinalize) return ValidationResult.Success; return (IsNotNull(value)) ? ValidationResult.Success : new ValidationResult(string.Format("{0} is required when finalizing", validationContext.DisplayName)); } }
For primitive data types, check value!=null :
[AttributeUsage(AttributeTargets.Property)] public class FinalizeRequiredAttribute : FinalizeValidationAttribute { protected override bool IsNotNull(object value) { return value != null; } }
For IEnumerable collections,
[AttributeUsage(AttributeTargets.Property)] public class FinalizeRequiredCollectionAttribute : FinalizeValidationAttribute { protected override bool IsNotNull(object value) { var enumerable = value as IEnumerable; return (enumerable != null && enumerable.GetEnumerator().MoveNext()); } }
This approach best fixes problems by removing validation logic from the controller. Data Annotation attributes must handle work for which the controller just needs to check !ModelState.IsValid . This is especially useful in my application because I could not reorganize to the base controller if the ModelState check in each controller is different.
source share