ASP.NET MVC: Xác thực tùy chỉnh bằng DataAnnotation


110

Tôi có một Mô hình với 4 thuộc tính thuộc loại chuỗi. Tôi biết bạn có thể xác thực độ dài của một thuộc tính bằng cách sử dụng chú thích StringLength. Tuy nhiên tôi muốn xác thực độ dài của 4 thuộc tính kết hợp.

Cách MVC để thực hiện việc này với chú thích dữ liệu là gì?

Tôi hỏi điều này vì tôi mới sử dụng MVC và muốn thực hiện theo cách chính xác trước khi đưa ra giải pháp của riêng mình.


2
Bạn đã nhìn vào Xác thực thông thạo chưa? Nó xử lý các tình huống phức tạp tốt hơn nhiều so với Chú thích dữ liệu
levelnis

Hãy xem các giải pháp được đề xuất cao .... dotnetcurry.com/ShowArticle.aspx?ID=776
Niks

Cảm ơn vì đã trả lời. Tôi sẽ kiểm tra Xác thực thông thạo, chưa bao giờ nghe nói về nó. Và Niks, Darin về cơ bản đã viết ra những gì bài báo ở liên kết bạn đăng đã giải thích. Vì vậy, cảm ơn bạn ... Công cụ tuyệt vời!
Danny van der Kraan

Câu trả lời:


177

Bạn có thể viết một thuộc tính xác thực tùy chỉnh:

public class CombinedMinLengthAttribute: ValidationAttribute
{
    public CombinedMinLengthAttribute(int minLength, params string[] propertyNames)
    {
        this.PropertyNames = propertyNames;
        this.MinLength = minLength;
    }

    public string[] PropertyNames { get; private set; }
    public int MinLength { get; private set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var properties = this.PropertyNames.Select(validationContext.ObjectType.GetProperty);
        var values = properties.Select(p => p.GetValue(validationContext.ObjectInstance, null)).OfType<string>();
        var totalLength = values.Sum(x => x.Length) + Convert.ToString(value).Length;
        if (totalLength < this.MinLength)
        {
            return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
        }
        return null;
    }
}

và sau đó bạn có thể có một mô hình dạng xem và trang trí một trong các thuộc tính của nó với nó:

public class MyViewModel
{
    [CombinedMinLength(20, "Bar", "Baz", ErrorMessage = "The combined minimum length of the Foo, Bar and Baz properties should be longer than 20")]
    public string Foo { get; set; }
    public string Bar { get; set; }
    public string Baz { get; set; }
}

4
Cảm ơn bạn đã trả lời, tôi đã chấp nhận câu trả lời của bạn. Thực sự cảm thấy hơi xấu hổ. Bạn đã viết ra toàn bộ giải pháp! Hehe. Chỉ phải thay đổi hàm IsValid để kiểm tra độ dài tối đa. Vì vậy, đây có phải là giải pháp MVC được chấp nhận cho các loại vấn đề này không?
Danny van der Kraan

7
@DannyvanderKraan, vâng, đây là cách được chấp nhận. Tất nhiên điều này tệ đến mức tôi không bao giờ sử dụng nó và thay vào đó sử dụng FluentValidation.NET để thực hiện xác thực.
Darin Dimitrov

11
Tại đây: wellvalidation.codeplex.com . Bạn có thể vừa viết một validator đơn giản cho các mô hình điểm cho rằng có thể trông như thế này (một dòng mã): this.RuleFor(x => x.Foo).Must((x, foo) => x.Foo.Length + x.Bar.Length + x.Baz.Length < 20).WithMessage("The combined minimum length of the Foo, Bar and Baz properties should be longer than 20");. Bây giờ hãy xem đoạn mã trong câu trả lời của tôi mà bạn cần viết với các chú thích dữ liệu và cho tôi biết bạn thích cái nào hơn. Mô hình xác thực khai báo rất kém so với mô hình mệnh lệnh.
Darin Dimitrov

1
Điều này hơi muộn, nhưng có ai biết nếu có một cài đặt khác mà bạn phải "bật" để cho phép chú thích dữ liệu tùy chỉnh không? Tôi biết về cách thêm không gian tên cho js không theo dõi trên tệp web.config, nhưng ở bất kỳ nơi nào khác?
Jose

1
Tôi đã tìm kiếm điều này cả buổi sáng! Tôi đã sửa nó, và thật không may khi IsValidnó được gọi validationContextlà null. Bất kỳ ý tưởng những gì tôi đã làm sai? :-(
Grimm The Opiner

95

Mô hình tự xác thực

Mô hình của bạn nên triển khai một giao diện IValidatableObject. Đặt mã xác thực của bạn trong Validatephương thức:

public class MyModel : IValidatableObject
{
    public string Title { get; set; }
    public string Description { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Title == null)
            yield return new ValidationResult("*", new [] { nameof(Title) });

        if (Description == null)
            yield return new ValidationResult("*", new [] { nameof(Description) });
    }
}

Xin lưu ý: đây là xác thực phía máy chủ . Nó không hoạt động ở phía máy khách. Việc xác nhận của bạn sẽ chỉ được thực hiện sau khi gửi biểu mẫu.


Cảm ơn vì đã trả lời Andrei. Mặc dù giải pháp của bạn cũng sẽ hiệu quả, tôi chọn Darin vì nó có thể tái sử dụng nhiều hơn.
Danny van der Kraan

6
lợi nhuận trả về mới ValidationResult ("Tiêu đề là bắt buộc.", "Tiêu đề"); sẽ thêm tên thuộc tính, hữu ích trong việc nhóm các lỗi xác thực để hiển thị nếu cần.
Mike Kingscott

5
Lưu ý rằng phương thức xác thực này chỉ được gọi sau khi tất cả các thuộc tính xác thực đã vượt qua quá trình xác nhận.
Pedro

3
Điều này hoạt động tốt cho tôi vì xác nhận của tôi rất cụ thể. Việc thêm một thuộc tính tùy chỉnh sẽ là quá mức cần thiết đối với tôi vì quá trình xác thực sẽ không được sử dụng lại.
Steve S

Đây là những gì tôi đang tìm kiếm. Cảm ơn bạn!
Amol Jadhav

26

ExpressiveAnnotations cung cấp cho bạn một khả năng như vậy:

[Required]
[AssertThat("Length(FieldA) + Length(FieldB) + Length(FieldC) + Length(FieldD) > 50")]
public string FieldA { get; set; }

Điều này là tuyệt vời! những lời cầu nguyện của tôi đã trả lời :)
Korayem

Chỉ cần tìm thấy câu trả lời này và nó chỉ tiết kiệm rất nhiều thời gian. ExpressiveAnnotations thật tuyệt vời!
Brad

10

Để cải thiện câu trả lời của Darin, nó có thể ngắn hơn một chút:

public class UniqueFileName : ValidationAttribute
{
    private readonly NewsService _newsService = new NewsService();

    public override bool IsValid(object value)
    {
        if (value == null) { return false; }

        var file = (HttpPostedFile) value;

        return _newsService.IsFileNameUnique(file.FileName);
    }
}

Mô hình:

[UniqueFileName(ErrorMessage = "This file name is not unique.")]

Lưu ý rằng thông báo lỗi là bắt buộc, nếu không lỗi sẽ trống.


8

Lý lịch:

Xác thực mô hình là bắt buộc để đảm bảo rằng dữ liệu đã nhận mà chúng tôi nhận được là hợp lệ và chính xác để chúng tôi có thể thực hiện các xử lý tiếp theo với dữ liệu này. Chúng ta có thể xác nhận một mô hình trong một phương thức hành động. Các thuộc tính xác thực được tích hợp sẵn là So sánh, Phạm vi, Biểu thức chính quy, Bắt buộc, Độ dài chuỗi. Tuy nhiên, chúng tôi có thể có các tình huống trong đó chúng tôi yêu cầu các thuộc tính xác thực khác với các thuộc tính tích hợp sẵn.

Thuộc tính xác thực tùy chỉnh

public class EmployeeModel 
{
    [Required]
    [UniqueEmailAddress]
    public string EmailAddress {get;set;}
    public string FirstName {get;set;}
    public string LastName {get;set;}
    public int OrganizationId {get;set;}
}

Để tạo một thuộc tính xác thực tùy chỉnh, bạn sẽ phải lấy lớp này từ ValidationAttribute.

public class UniqueEmailAddress : ValidationAttribute
{
    private IEmployeeRepository _employeeRepository;
    [Inject]
    public IEmployeeRepository EmployeeRepository
    {
        get { return _employeeRepository; }
        set
        {
            _employeeRepository = value;
        }
    }
    protected override ValidationResult IsValid(object value,
                        ValidationContext validationContext)
    {
        var model = (EmployeeModel)validationContext.ObjectInstance;
        if(model.Field1 == null){
            return new ValidationResult("Field1 is null");
        }
        if(model.Field2 == null){
            return new ValidationResult("Field2 is null");
        }
        if(model.Field3 == null){
            return new ValidationResult("Field3 is null");
        }
        return ValidationResult.Success;
    }
}

Hi vọng điêu nay co ich. Chúc mừng!

Người giới thiệu


1

Một chút muộn để trả lời, nhưng cho những người đang tìm kiếm. Bạn có thể dễ dàng thực hiện việc này bằng cách sử dụng một thuộc tính bổ sung với chú thích dữ liệu:

public string foo { get; set; }
public string bar { get; set; }

[MinLength(20, ErrorMessage = "too short")]
public string foobar 
{ 
    get
    {
        return foo + bar;
    }
}

Đó là tất cả quá nó thực sự. Nếu bạn thực sự muốn hiển thị lỗi xác thực ở một nơi cụ thể, bạn có thể thêm lỗi này vào chế độ xem của mình:

@Html.ValidationMessage("foobar", "your combined text is too short")

thực hiện điều này trong dạng xem có thể hữu ích nếu bạn muốn bản địa hóa.

Hi vọng điêu nay co ich!

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.