如何有选择地验证一些数据注释属性?

Bla*_*ise 5 c# asp.net asp.net-mvc model-binding data-annotations

我的视图模型中有一些属性在保存时是可选的,但在提交时是必需的.总之,我们允许部分保存,但提交整个表单,我们确实希望确保所有必填字段都有值.

我现在能想到的唯一方法是:

操纵ModelState错误集合.

视图模型具有所有[Required]属性.如果请求是部分保存,则在进入控制器操作时ModelState.IsValid变为false.然后我运行所有ModelState(这是一个ICollection<KeyValuePair<string, ModelState>>)错误并删除[Required]属性引发的所有错误.

但是如果请求是提交整个表单,我不会干涉ModelState[Required]属性生效.

使用不同的视图模型进行部分保存和提交

这个更难看.一个视图模型将包含[Required]操作方法用于提交的所有属性.但是对于部分保存,我将表单数据发布到使用相同视图模型而没有所有[Required]属性的不同操作.

显然,我最终会遇到很多重复的代码/视图模型.

理想的解决方案

我一直在考虑是否可以[SubmitRequired]为这些必需的属性创建自定义数据注释属性.并且以某种方式使得验证在部分保存时忽略它,但在提交时则忽略.

仍然没有一个明确的线索.有人可以帮忙吗?谢谢.

Bla*_*ise 0

我的做法是添加条件检查注解属性,这个属性是从傻瓜学来的。

成为SaveMode视图模型的一部分。

SaveMode将属性标记为可为空,以便当不是时,其值是可选的Finalize

但添加一个自定义注释属性[FinalizeRequired]

[FinalizeRequired]
public int? SomeProperty { get; set; }

[FinalizeRequiredCollection]
public List<Item> Items { get; set; }
Run Code Online (Sandbox Code Playgroud)

这是属性的代码:

[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));
    }
}
Run Code Online (Sandbox Code Playgroud)

对于原始数据类型,请检查value!=null

[AttributeUsage(AttributeTargets.Property)]
public class FinalizeRequiredAttribute : FinalizeValidationAttribute
{
    protected override bool IsNotNull(object value)
    {
        return value != null;
    }
}
Run Code Online (Sandbox Code Playgroud)

对于IEnumerable收藏来说,

[AttributeUsage(AttributeTargets.Property)]
public  class FinalizeRequiredCollectionAttribute : FinalizeValidationAttribute
{
    protected override bool IsNotNull(object value)
    {
        var enumerable = value as IEnumerable;
        return (enumerable != null && enumerable.GetEnumerator().MoveNext());
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法通过从控制器中删除验证逻辑来​​最好地实现关注点分离。数据注释属性应该处理此类工作,哪个控制器只需要检查!ModelState.IsValid. ModelState这在我的应用程序中特别有用,因为如果每个控制器中的检查不同,我将无法重构为基本控制器。