82

我有以下视图模型定义

public class AccessRequestViewModel
{
    public Request Request { get; private set; }
    public SelectList Buildings { get; private set; }
    public List<Person> Persons { get; private set; }
}

因此,在我的应用程序中,访问请求必须至少有 1 人。您可以使用什么方法进行验证?我不希望这种验证发生在我的控制器中,这很容易做到。唯一的选择是自定义验证属性吗?

编辑:目前使用 FluentValidation 执行此验证(不错的库!)

RuleFor(vm => vm.Persons)
                .Must((vm, person) => person.Count > 0)
                .WithMessage("At least one person is required");
4

7 回答 7

179

如果您使用数据注释来执行验证,您可能需要一个自定义属性:

public class EnsureOneElementAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        var list = value as IList;
        if (list != null)
        {
            return list.Count > 0;
        }
        return false;
    }
}

进而:

[EnsureOneElement(ErrorMessage = "At least a person is required")]
public List<Person> Persons { get; private set; }

或使其更通用:

public class EnsureMinimumElementsAttribute : ValidationAttribute
{
    private readonly int _minElements;
    public EnsureMinimumElementsAttribute(int minElements)
    {
        _minElements = minElements;
    }

    public override bool IsValid(object value)
    {
        var list = value as IList;
        if (list != null)
        {
            return list.Count >= _minElements;
        }
        return false;
    }
}

进而:

[EnsureMinimumElements(1, ErrorMessage = "At least a person is required")]
public List<Person> Persons { get; private set; }

我个人使用FluentValidation.NET而不是 Data Annotations 来执行验证,因为我更喜欢命令式验证逻辑而不是声明式。我认为它更强大。所以我的验证规则看起来像这样:

RuleFor(x => x.Persons)
    .Must(x => x.Count > 0)
    .WithMessage("At least a person is required");
于 2011-02-28T19:44:59.167 回答
21

以下代码适用于 asp.net core 1.1。

[Required, MinLength(1, ErrorMessage = "At least one item required in work order")]
public ICollection<WorkOrderItem> Items { get; set; }
于 2017-08-31T19:37:35.760 回答
18

处理视图模型对象集合成员的计数验证的另一种可能方法是让计算属性返回集合或列表计数。然后可以像下面的代码一样应用 RangeAttribute 来强制计数验证:

[Range(minimum: 1, maximum: Int32.MaxValue, ErrorMessage = "At least one item needs to be selected")]
public int ItemCount
{
    get
    {
        return Items != null ? Items.Length : 0;
    }
}

在上面的代码中,ItemCount 是正在验证的视图模型上的示例计算属性,而 Items 是正在检查其计数的示例成员集合属性。在此示例中,对集合成员强制执行至少一项,并且最大限制是整数可以取的最大值,对于大多数实际目的而言,该值是无界的。验证失败的错误信息也可以通过上例中 RangeAttribute 的 ErrorMessage 成员来设置。

于 2015-08-14T14:33:40.200 回答
9

Darin 的回答很好,但是下面的版本会自动给你一个有用的错误信息。

public class MinimumElementsAttribute : ValidationAttribute
{
    private readonly int minElements;

    public MinimumElementsAttribute(int minElements)
    {
        this.minElements = minElements;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var list = value as IList;

        var result = list?.Count >= minElements;

        return result
            ? ValidationResult.Success
            : new ValidationResult($"{validationContext.DisplayName} requires at least {minElements} element" + (minElements > 1 ? "s" : string.Empty));
    }
}

用法:

[MinimumElements(1)]
public List<Customer> Customers {get;set}

[MinimumElements(2)]
public List<Address> Addresses {get;set}

错误信息:

  • 客户至少需要 1 个元素
  • 地址至少需要 2 个元素
于 2018-01-16T09:34:36.333 回答
2

你有两个选择,要么创建一个自定义验证属性并用它装饰属性,要么你可以让你的 ViewModel 实现IValidatableObject接口(它定义了一个Validate方法)

希望这可以帮助 :)

于 2011-02-28T19:52:47.437 回答
0

一种方法是使用私有构造函数和静态方法来返回对象的实例。

public class AccessRequestViewModel
{
    private AccessRequesetViewModel() { };

    public static GetAccessRequestViewModel (List<Person> persons)
    {
            return new AccessRequestViewModel()
            {
                Persons = persons,
            };
    }

    public Request Request { get; private set; }
    public SelectList Buildings { get; private set; }
    public List<Person> Persons { get; private set; }
}

通过始终使用工厂来实例化您的 ViewModel,您可以确保始终有人。

这可能不适合您想要的,但它可能会起作用。

于 2011-02-28T19:45:09.190 回答
0

进行自定义验证会非常干净和优雅。像这样的东西:

public class AccessRequestViewModel
{
    public Request Request { get; private set; }
    public SelectList Buildings { get; private set; }
    [AtLeastOneItem]
    public List<Person> Persons { get; private set; }
}

[MinimumItems(1)]

于 2011-02-28T19:48:09.717 回答