Xác thực ViewModel cho một danh sách


76

Tôi có định nghĩa mô hình xem sau

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

Vì vậy, trong ứng dụng của tôi phải có ít nhất 1 người cho một yêu cầu truy cập. Bạn có thể sử dụng cách tiếp cận nào để xác thực? Tôi không muốn xác thực này xảy ra trong bộ điều khiển của tôi, điều này sẽ đơn giản để thực hiện. Lựa chọn duy nhất có phải là thuộc tính xác thực tùy chỉnh không?

Chỉnh sửa: Hiện đang thực hiện xác thực này với FluentValidation (thư viện đẹp!)

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

Câu trả lời:


172

Nếu bạn đang sử dụng Chú thích dữ liệu để thực hiện xác thực, bạn có thể cần một thuộc tính tùy chỉnh:

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

và sau đó:

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

hoặc để làm cho nó chung chung hơn:

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

và sau đó:

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

Cá nhân tôi sử dụng FluentValidation.NET thay vì Chú thích dữ liệu để thực hiện xác thực vì tôi thích logic xác thực mệnh lệnh thay vì khai báo. Tôi nghĩ rằng nó mạnh mẽ hơn. Vì vậy, quy tắc xác thực của tôi sẽ đơn giản giống như sau:

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

Dường như tôi cần phải sử dụng quá tải Phải () để sử dụng persons.Count, vui lòng xem chỉnh sửa của tôi và cho tôi biết nếu bạn có một phiên bản đó là thân thiện hơn :)
ryan

1
@ryan, thực sự có hai quá tải của phương thức này như được hiển thị trong tài liệu . Vì vậy, phiên bản của tôi là thân thiện hơn. Đừng lo lắng nếu Visual Studio gạch chân nó là lỗi. Nó sẽ hoạt động nếu bạn cố gắng biên dịch. Chỉ là VS Intellisense không đủ cao cấp để hiểu nó :-) Vì vậy, RuleFor(x => x.Persons).Must(x => x.Count > 0).WithMessage("At least a person is required");sẽ biên dịch và hoạt động tốt.
Darin Dimitrov

Kỳ lạ, bây giờ nó không được gạch dưới. Cảm ơn!
ryan

Cảm ơn Darin, bạn đã chọn một tên thuộc tính thú vị (: Chỉ tò mò xem bạn có đang sử dụng bất kỳ khung xác thực nào cho phía máy khách hay không. Chú thích dữ liệu tích hợp mang lại lợi thế cho phía máy khách nếu thấy hữu ích.
Saro Taşciyan

Làm thế nào tôi nên sử dụng nó trong dao cạo? Nếu tôi viết @foreach (var p trong Model.Person) {...} @ Html.ValidationMessageFor (model => Model.Person), phương thức máy chủ xác thực được gọi nhưng thông báo xác thực không được hiển thị.
Kate,

18

Một cách có thể khác để xử lý xác nhận số lượng cho các thành viên bộ sưu tập của đối tượng mô hình xem, là có một thuộc tính được tính toán trả về bộ sưu tập hoặc số lượng danh sách. Sau đó, RangeAttribute có thể được áp dụng như trong đoạn mã bên dưới để thực thi xác thực số lượng:

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

Trong đoạn mã trên, ItemCount là một thuộc tính được tính toán ví dụ trên một mô hình chế độ xem đang được xác thực và Item là một thuộc tính tập hợp thành viên mẫu có số lượng đang được kiểm tra. Trong ví dụ này, ít nhất một mục được thực thi trên thành viên bộ sưu tập và giới hạn tối đa là giá trị lớn nhất mà một số nguyên có thể lấy, không bị ràng buộc đối với hầu hết các mục đích thực tế. Thông báo lỗi khi xác thực không thành công cũng có thể được đặt thông qua thành viên ErrorMessage của RangeAttribute trong ví dụ trên.


14

Mã sau hoạt động trong asp.net core 1.1.

[Required, MinLength(1, ErrorMessage = "At least one item required in work order")]
public ICollection<WorkOrderItem> Items { get; set; }

1
Có vẻ như điều này không còn hoạt động trong .NET Core 2.1.0 (Bản xem trước 1)
Sven

3
Điều này hoạt động trong .Net Core 2.2, tôi đã thử điều này trên loại Danh sách. Nếu bạn muốn có một thông báo tùy chỉnh riêng cho thuộc tính [Bắt buộc] thì cũng có thể. [Bắt buộc (ErrorMessage = "Thiếu mét"), MinLength (1, ErrorMessage = "Ít nhất là 1 mét là bắt buộc")] danh sách công khai <Meter> mét {get; bộ; }
Jeshwel

8

Câu trả lời của Darin là tốt nhưng phiên bản dưới đây sẽ tự động cung cấp cho bạn một thông báo lỗi hữu ích.

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

Sử dụng:

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

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

Thông báo lỗi:

  • Khách hàng yêu cầu ít nhất 1 yếu tố
  • Địa chỉ yêu cầu ít nhất 2 yếu tố

2

Bạn có hai lựa chọn ở đây, hoặc tạo Thuộc tính xác thực tùy chỉnh và trang trí thuộc tính với nó hoặc bạn có thể làm cho ViewModel của bạn triển khai IValidatableObjectgiao diện (xác định một Validatephương pháp)

Hi vọng điêu nay co ich :)


0

Sẽ rất sạch sẽ và thanh lịch nếu có một xác nhận tùy chỉnh. Một cái gì đó như thế này:

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

Hoặc [MinimumItems(1)].


0

Một cách tiếp cận có thể là sử dụng một phương thức khởi tạo riêng và một phương thức tĩnh để trả về một thể hiện của đối tượng.

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

Bằng cách luôn sử dụng nhà máy để khởi tạo ViewModel của bạn, bạn có thể đảm bảo rằng sẽ luôn có một người.

Điều này có thể không lý tưởng cho những gì bạn muốn, nhưng nó có thể sẽ hoạt động.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.