找到你要的答案

Q:ViewModel validation for a List

Q:视图模型验证列表

I have the following viewmodel definition

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

So in my application there must be at least 1 person for an access request. What approach might you use to validate? I don't want this validation to happen in my controller which would be simple to do. Is the only choice a custom validation attribute?

Edit: Currently performing this validation with FluentValidation (nice library!)

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

我有以下问题的定义

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");
answer1: 回答1:

If you are using Data Annotations to perform validation you might need a custom attribute:

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

and then:

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

or to make it more generic:

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;
    }
}

and then:

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

Personally I use FluentValidation.NET instead of Data Annotations to perform validation because I prefer the imperative validation logic instead of the declarative. I think it is more powerful. So my validation rule would simply look like this:

RuleFor(x => x.Persons)
    .Must(x => x.Count > 0)
    .WithMessage("At least a person is required");

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

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代替数据注释执行验证因为我喜欢命令验证逻辑而不是陈述。我认为它更强大。所以我的验证规则看起来就是这样:

RuleFor(x => x.Persons)
    .Must(x => x.Count > 0)
    .WithMessage("At least a person is required");
answer2: 回答2:

Another possible way to handle the count validations for view model object's collection members, is to have a calculated property returning the collection or list count. A RangeAttribute can then be applied like in the code below to enforce count validation:

[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;
    }
}

In the code above, ItemCount is an example calculated property on a view model being validated, and Items is an example member collection property whose count is being checked. In this example, at least one item is enforced on the collection member and the maximum limit is the maximum value an integer can take, which is, for most of the practical purposes, unbounded. The error message on validation failure can also be set through the RangeAttribute's ErrorMessage member in the example above.

处理视图模型对象的集合成员数验证的另一种可行的方法,就是要有一个计算属性返回集合或列表计数。然后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;
    }
}

In the code above, ItemCount is an example calculated property on a view model being validated, and Items is an example member collection property whose count is being checked. In this example, at least one item is enforced on the collection member and the maximum limit is the maximum value an integer can take, which is, for most of the practical purposes, unbounded. The error message on validation failure can also be set through the RangeAttribute's ErrorMessage member in the example above.

answer3: 回答3:

It would be very clean and elegant to have a custom validation. Something like this:

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

Or [MinimumItems(1)].

这将是非常干净和优雅有一个自定义验证。像这样的东西:

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

(1)]或[ minimumitems。

answer4: 回答4:

One approach could be to use a private constructor and a static method to return an instance of the object.

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; }
}

By always using the factory to instantiate your ViewModel, you can ensure that there will always be a person.

This probably isn't ideal for what you want, but it would likely work.

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

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; }
}

总是使用工厂实例化视图模型,可以确保始终会有一个人。

这可能不是你想要的理想,但它可能会工作。

answer5: 回答5:

You have two choices here, either create a Custom Validation Attribute and decorate the property with it, or you can make your ViewModel implement the IValidatableObject interface (which defines a Validate method)

Hope this helps :)

您有两种选择,要么创建一个自定义的验证属性与它的装饰性能,或者你可以让你的视图模型实现ivalidatableobject接口(它定义验证法)

希望这有帮助:

c#  asp.net  asp.net-mvc-3  fluentvalidation  model-validation