Mô hình MVC yêu cầu true


85

Có cách nào thông qua chú thích dữ liệu để yêu cầu thuộc tính boolean được đặt thành true không?

public class MyAwesomeObj{
    public bool ThisMustBeTrue{get;set;}
}

Chính xác thì trường hợp sử dụng của cái này là gì? Bạn không thể để thuộc tính chỉ đọc và trả về true mọi lúc?
Jan Thomä

1
Khá nhiều điều để nói ... này bạn, bạn đã quên kiểm tra Tôi đồng ý ... điều này sẽ làm cho mô hình không hợp lệ.
Marty Trenouth

Tôi nghĩ đây là điều bạn muốn xử lý ở phía khách hàng.
PsychoCoder

15
@PsychoCoder: Nó nên được xử lý ở cả hai phía ... không chỉ phía khách hàng. Tôi chỉ đang tìm xem liệu nó có thể được xử lý bằng cách thêm một chú thích dữ liệu đơn giản hay không.
Marty Trenouth

Câu trả lời:


49

Bạn có thể tạo trình xác thực của riêng mình:

public class IsTrueAttribute : ValidationAttribute
{
    #region Overrides of ValidationAttribute

    /// <summary>
    /// Determines whether the specified value of the object is valid. 
    /// </summary>
    /// <returns>
    /// true if the specified value is valid; otherwise, false. 
    /// </returns>
    /// <param name="value">The value of the specified validation object on which the <see cref="T:System.ComponentModel.DataAnnotations.ValidationAttribute"/> is declared.
    ///                 </param>
    public override bool IsValid(object value)
    {
        if (value == null) return false;
        if (value.GetType() != typeof(bool)) throw new InvalidOperationException("can only be used on boolean properties.");

        return (bool) value;
    }

    #endregion
}

Tôi sẽ cân nhắc việc tăng cường điều này bằng cách triển khai phía máy khách - thay vì sử dụng xác thực từ xa được đề cập trong các câu trả lời khác, hãy sử dụng cách viết không phô trương ở đây: jacopretorius.net/2011/01/client-side-validation-in-mvc-3 .html
SamStephens 10/10/11

Đây là một giải pháp nhanh (và đã được thử nghiệm) tốt cho chúng tôi. Chúng tôi có thể thực hiện mà không cần xác thực phía khách hàng trong giải pháp của @ dazbradbury (cũng là một giải pháp tốt) vì chúng tôi chỉ cần điều này trên một hộp kiểm duy nhất trên trang trước của một cuộc khảo sát.
Seth

return (bool) value == true;đây là một so sánh thừa
T-moty

130

Tôi sẽ tạo trình xác thực cho cả phía Máy chủ VÀ Máy khách. Sử dụng MVC và xác thực biểu mẫu không phô trương, điều này có thể đạt được chỉ đơn giản bằng cách thực hiện như sau:

Trước tiên, hãy tạo một lớp trong dự án của bạn để thực hiện xác thực phía máy chủ như sau:

public class EnforceTrueAttribute : ValidationAttribute, IClientValidatable
{
    public override bool IsValid(object value)
    {
        if (value == null) return false;
        if (value.GetType() != typeof(bool)) throw new InvalidOperationException("can only be used on boolean properties.");
        return (bool)value == true;
    }

    public override string FormatErrorMessage(string name)
    {
        return "The " + name + " field must be checked in order to continue.";
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new ModelClientValidationRule
        {
            ErrorMessage = String.IsNullOrEmpty(ErrorMessage) ? FormatErrorMessage(metadata.DisplayName) : ErrorMessage,
            ValidationType = "enforcetrue"
        };
    }
}

Sau đây, chú thích thuộc tính thích hợp trong mô hình của bạn:

[EnforceTrue(ErrorMessage=@"Error Message")]
public bool ThisMustBeTrue{ get; set; }

Và Cuối cùng, bật xác thực phía máy khách bằng cách thêm tập lệnh sau vào Chế độ xem của bạn:

<script type="text/javascript">
    jQuery.validator.addMethod("enforcetrue", function (value, element, param) {
        return element.checked;
    });
    jQuery.validator.unobtrusive.adapters.addBool("enforcetrue");
</script>

Lưu ý: Chúng tôi đã tạo một phương thức GetClientValidationRulesđẩy chú thích của chúng tôi đến chế độ xem từ mô hình của chúng tôi.

Nếu sử dụng tệp tài nguyên để cung cấp thông báo lỗi cho quá trình quốc tế hóa, hãy loại bỏ FormatErrorMessagecuộc gọi (hoặc chỉ gọi cơ sở) và chỉnh sửa GetClientValidationRulesphương thức như sau:

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
    string errorMessage = String.Empty;
    if(String.IsNullOrWhiteSpace(ErrorMessage))
    {
        // Check if they supplied an error message resource
        if(ErrorMessageResourceType != null && !String.IsNullOrWhiteSpace(ErrorMessageResourceName))
        {
            var resMan = new ResourceManager(ErrorMessageResourceType.FullName, ErrorMessageResourceType.Assembly);
            errorMessage = resMan.GetString(ErrorMessageResourceName);
        }
    }
    else
    {
        errorMessage = ErrorMessage;
    }

    yield return new ModelClientValidationRule
    {
        ErrorMessage = errorMessage,
        ValidationType = "enforcetrue"
    };
}

3
Cảm ơn vì điều này - nó hoạt động tuyệt vời! Nó hoạt động tốt hơn với phương pháp ghi đè FormatErrorMessage bị loại bỏ - theo cách đó, bản địa hóa thông báo lỗi từ tệp Tài nguyên hoạt động. Cách sử dụng của tôi: [EnforceTrue (ErrorMessageResourceType = typeof (ValidationMessages), ErrorMessageResourceName = "termsAndConditionsRequired")]
Matt Frear

2
Tôi không thể khiến xác thực phía máy khách hoạt động và dường như không thể biết tôi đang làm gì sai. Chính xác thì tôi nên đặt javacsript ở đâu? Trong thẻ head? Bên cạnh bộ điều khiển?
vsdev

Tôi đồng ý, đây phải là câu trả lời
Simua 14/09

1
Giải pháp tuyệt vời cho thấy sức mạnh của các thuộc tính xác thực tùy chỉnh! Mặc dù tôi khuyên bạn nên đặt tập lệnh vào tệp js được tham chiếu toàn cầu, không phải (các) chế độ xem, để sử dụng lại. Ngoài ra, tốt nhất nên xử lý tất cả các cách chuỗi thông báo có thể được thêm vào: mặc định nếu không có cung cấp nào, hoặc chuỗi thông báo hoặc từ tệp tài nguyên.
jeepwran

1
Giải pháp tuyệt vời, cảm ơn đã đăng. Đối với những người không thể làm việc xác thực phía máy khách: Bạn phải mở rộng xác thực jQuery trước khi các điều khiển mà nó sẽ xác thực được tải, vì vậy hãy đặt tập lệnh vào đầu chứ không phải trong window.onload / $ (tài liệu ) .ready () sự kiện.
Evert

92

Tôi biết đây là một bài đăng cũ hơn nhưng muốn chia sẻ một cách đơn giản phía máy chủ để thực hiện việc này. Bạn tạo thuộc tính công cộng được đặt thành true và so sánh bool của bạn với thuộc tính đó. Nếu bool của bạn không được chọn (theo mặc định là false) thì biểu mẫu sẽ không hợp lệ.

public bool isTrue
{ get { return true; } }

[Required]
[Display(Name = "I agree to the terms and conditions")]
[Compare("isTrue", ErrorMessage = "Please agree to Terms and Conditions")]
public bool AgreeTerms { get; set; }

Mã dao cạo

@Html.CheckBoxFor(m => Model.AgreeTerms, new { id = "AgreeTerms", @checked = "checked" })
<label asp-for="AgreeTerms" class="control-label"></label>
<a target="_blank" href="/Terms">Read</a>
<br />
@Html.ValidationMessageFor(model => model.AgreeTerms, "", new { @class = "text-danger" })
@Html.HiddenFor(x => Model.isTrue)

12
+1 cho đơn giản. FYI: Tôi đã phải đặt thuộc tính 'isTrue' ở chế độ công khai để điều này hoạt động.
Tod Birdsall

Hãy so sánh là không có đối với tôi trong MVC4
Michael Rudner Evanchik

Giải pháp siêu giải pháp tuyệt vời
Sreerejith SS

9
Và nếu bạn thêm một ẩn cho thuộc tính "isTrue", bạn sẽ nhận được xác thực phía khách hàng
billoreid

2
Làm phiền giải pháp tìm kiếm tuyệt vời này không làm việc cho tôi. Đã thử nghiệm trên Mvc 5.2.3.
harvzor 17/07/17

22

Tôi đã thử một số giải pháp nhưng không có giải pháp nào hoạt động hoàn toàn để tôi có được xác thực cả phía máy khách và máy chủ. Vì vậy, những gì tôi đã làm trong ứng dụng MVC 5 của mình để nó hoạt động:

Trong ViewModel của bạn (để xác thực phía máy chủ):

public bool IsTrue => true;

[Required]
[Display(Name = "I agree to the terms and conditions")]
[Compare(nameof(IsTrue), ErrorMessage = "Please agree to Terms and Conditions")]
public bool HasAcceptedTermsAndConditions { get; set; }

Trong trang Razor của bạn (để xác thực phía khách hàng):

<div class="form-group">
   @Html.CheckBoxFor(m => m.HasAcceptedTermsAndConditions)
   @Html.LabelFor(m => m.HasAcceptedTermsAndConditions)
   @Html.ValidationMessageFor(m => m.HasAcceptedTermsAndConditions)

   @Html.Hidden(nameof(Model.IsTrue), "true")
</div>

1
Giải pháp quyến rũ!
Tobias

3
Hãy quan tâm đến giá trị cho trường ẩn ("true")!
Tobias

10

Tôi chỉ muốn hướng mọi người đến Fiddle sau: https://dotnetfiddle.net/JbPh0X

Người dùng đã thêm [Range(typeof(bool), "true", "true", ErrorMessage = "You gotta tick the box!")]vào thuộc tính boolean của họ để xác thực phía máy chủ hoạt động.

Để xác thực phía máy khách cũng hoạt động, họ đã thêm tập lệnh sau:

// extend jquery range validator to work for required checkboxes
var defaultRangeValidator = $.validator.methods.range;
$.validator.methods.range = function(value, element, param) {
    if(element.type === 'checkbox') {
        // if it's a checkbox return true if it is checked
        return element.checked;
    } else {
        // otherwise run the default validation function
        return defaultRangeValidator.call(this, value, element, param);
    }
}

9

Chỉ cần kiểm tra xem liệu biểu diễn chuỗi của nó có bằng True:

[RegularExpression("True")]
public bool TermsAndConditions { get; set; }

@JeradRose Nó được xác nhận tốt trên máy chủ. Bạn đang đề cập đến xác thực phía máy khách?
ta.speot.is

3
Khẳng định, công trình này bên phía máy chủ nhưng không phải khách hàng
Matt Frear

Tôi nghĩ rằng xác thực phía máy chủ có thể có ngoại lệ kiểu không khớp khi cố gắng so sánh bool với một chuỗi.
Jerad Rose,

RegularExpressionAttributesử dụng nội bộ Convert.ToStringđể lấy biểu diễn chuỗi giá trị của thuộc tính (được phân phối đến nó dưới dạng một object).
ta.speot.is

Tôi nghĩ câu trả lời này đơn giản hơn @ fields-lồng +1 từ tôi
Aaron Hudon

5

Bạn có thể tạo thuộc tính của riêng mình hoặc sử dụng CustomValidationAttribute .

Đây là cách bạn sẽ sử dụng CustomValidationAttribute:

[CustomValidation(typeof(BoolValidation), "ValidateBool")]

trong đó BoolValidation được định nghĩa là:

public class BoolValidation
{
  public static ValidationResult ValidateBool(bool boolToBeTrue)
  {
    if (boolToBeTrue)
    {
      return ValidationResult.Success;
    }
    else
    {
      return new ValidationResult(
          "Bool must be true.");
    }
  }

5

[Required]thuộc tính là viết tắt của việc yêu cầu bất kỳ giá trị nào - nó có thể là true hoặc false. Bạn sẽ phải sử dụng một xác thực khác cho điều đó.


3

Theo dõi bài đăng của ta.speot.is và nhận xét từ Jerad Rose:

Bài đăng đã cho sẽ không hoạt động ở phía máy khách với xác thực không phô trương. Điều này sẽ hoạt động ở cả hai bên (máy khách và máy chủ):

[RegularExpression("(True|true)")]
public bool TermsAndConditions { get; set; }

Không biết đây có phải là sự cố phiên bản mới hơn không, nhưng nó không hoạt động với tôi với jquery.validate 1.19.2 và jquery.validate.unobtrilities 3.2.11. Vấn đề dường như là regexphương pháp xác định không phô trương trước tiên kiểm tra xem hộp kiểm có phải là tùy chọn hay không trước khi xác thực regex, điều này có ý nghĩa, ngoại trừ jquery.validate dường như coi bất kỳ hộp kiểm nào chưa được chọn là tùy chọn. tl; dr Nó chỉ chạy regex trên các hộp kiểm đã chọn. Chúng ta có thể thêm một miếng đệm cho regex validatorphương thức hoặc chỉ tạo một trình xác thực tùy chỉnh.
xr280xr

3

.NET Core MVC - Hộp kiểm bắt buộc có chú thích dữ liệu

public class MyModel
{
    [Display(Name = "Confirmation")]
    [Range(typeof(bool), "true", "true", ErrorMessage = "Please check the Confirmation checkbox.")]
    public bool IsConfirmed { get; set; }   
}

<div class="custom-control custom-checkbox col-10">
    <input type="checkbox" asp-for="IsConfirmed" class="custom-control-input" />
    <label class="custom-control-label" for="IsConfirmed">
        "By clicking 'submit', I confirm."
    </label>
    <span asp-validation-for="IsConfirmed" class="text-danger"></span>
</div>

<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

<script type="text/javascript">
    $(document).ready(function () {
        // extend range validator method to treat checkboxes differently
        var defaultRangeValidator = $.validator.methods.range;
        $.validator.methods.range = function (value, element, param) {
            if (element.type === 'checkbox') {
                // if it's a checkbox return true if it is checked
                return element.checked;
            } else {
                // otherwise run the default validation function
                return defaultRangeValidator.call(this, value, element, param);
            }
        }
    });
</script>


2

Tôi không biết có cách nào thông qua DataAnnotations, nhưng điều này có thể dễ dàng thực hiện trong bộ điều khiển của bạn.

public ActionResult Add(Domain.Something model)
{

    if (!model.MyCheckBox)
        ModelState.AddModelError("MyCheckBox", "You forgot to click accept");

    if (ModelState.IsValid) {
        //'# do your stuff
    }

}

Tùy chọn khác duy nhất sẽ là xây dựng trình xác thực tùy chỉnh cho phía máy chủ và trình xác thực từ xa cho phía máy khách (xác thực từ xa chỉ khả dụng trong MVC3 +)


Kinda đã mới làm thế nào để kiểm tra cờ boolean rồi .... muốn biết liệu có ghi chú dữ liệu cho nó hay không.
Marty Trenouth

2

Bạn đã thiết lập các mục thích hợp trong web.config chưa không?

Điều đó có thể khiến xác thực không hoạt động.

Bạn cũng có thể cố gắng tạo thuộc tính xác thực tùy chỉnh (vì [Required]chỉ quan tâm đến việc nó có tồn tại hay không và bạn quan tâm đến giá trị):

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
sealed public class RequiredTrueAttribute : ValidationAttribute
{
    // Internal field to hold the mask value.
    readonly bool accepted;

    public bool Accepted
    {
        get { return accepted; }
    }

    public RequiredTrueAttribute(bool accepted)
    {
        this.accepted = accepted;
    }

    public override bool IsValid(object value)
    {
        bool isAccepted = (bool)value;
        return (isAccepted == true);
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(CultureInfo.CurrentCulture,
          ErrorMessageString, name, this.Accepted);
    }
}

Sau đó, cách sử dụng:

[RequiredTrue(ErrorMessage="{0} requires acceptance to continue.")]
public bool Agreement {get; set;}

Từ đây .


2

Đây là những gì làm việc cho tôi. Không có gì khác đã làm. Mvc 5:

Mô hình

public string True
{
  get
  {
    return "true";
  }
}

[Required]
[Compare("True", ErrorMessage = "Please agree to the Acknowlegement")]
public bool Acknowlegement { get; set; }

Lượt xem

  @Html.HiddenFor(m => m.True)
  @Html.EditorFor(model => model.Acknowlegement, new { htmlAttributes = Model.Attributes })
  @Html.ValidationMessageFor(model => model.Acknowlegement, "", new { @class = "text-danger" })

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


2

Đối với ASP.NET Core MVC ở đây là xác thực máy khách và máy chủ, dựa trên giải pháp của dazbradbury

public class EnforceTrueAttribute : ValidationAttribute, IClientModelValidator
{
    public override bool IsValid(object value)
    {
        if (value == null) return false;
        if (value.GetType() != typeof(bool)) throw new InvalidOperationException("can only be used on boolean properties.");
        return (bool)value;
    }

    public void AddValidation(ClientModelValidationContext context)
    {
        MergeAttribute(context.Attributes, "data-val", "true");
        var errorMessage = ErrorMessage ?? 
            $"The value for field {context.ModelMetadata.GetDisplayName()} must be true.";
        MergeAttribute(context.Attributes, "data-val-enforcetrue", errorMessage);
    }

    private void MergeAttribute(IDictionary<string, string> attributes,
        string key,
        string value)
    {
        if (attributes.ContainsKey(key))
        {
            return;
        }
        attributes.Add(key, value);
    }
}

Và sau đó trên máy khách:

$.validator.addMethod("enforcetrue", function (value, element, param) {
    return element.checked;
});

$.validator.unobtrusive.adapters.addBool("enforcetrue");

Sau đó, cách sử dụng là:

[EnforceTrue(ErrorMessage = "Please tick the checkbox")]
public bool IsAccepted { get; set; }

1

Tôi đã cố gắng sử dụng câu trả lời của fields.cage và nó không hoàn toàn phù hợp với tôi, nhưng một cái gì đó đơn giản hơn đã xảy ra và tôi không chắc chính xác tại sao (có thể là phiên bản Razor khác?), Nhưng tất cả những gì tôi phải làm là:

[Required]
[Range(typeof(bool), "true", "true", ErrorMessage = "Agreement required.")]
[Display(Name = "By clicking here, I agree that my firstborn child will etc etc...")]
public bool Agreement1Checked { get; set; }

Và trong tệp .cshtml:

@Html.CheckBoxFor(m => m.Agreement1Checked)
@Html.LabelFor(m => m.Agreement1Checked)
@Html.ValidationMessageFor(m => m.Agreement1Checked)

Điều này không hoạt động phía khách hàng đối với tôi. Vì lý do nào đó, tham số được truyền cho phương thức quy tắc jquery.validate [NaN, NaN]ở nơi nó phải ở[true, true]
xr280xr

@ xr280xr Ngay cả khi người dùng đã chọn hộp kiểm?
Dronz

0

Tôi nghĩ rằng cách tốt nhất để xử lý điều này là chỉ cần kiểm tra trong bộ điều khiển của bạn nếu hộp là đúng, nếu không chỉ cần thêm lỗi vào mô hình của bạn và để nó hiển thị lại chế độ xem của bạn.

Như đã nêu trước đây, tất cả [Bắt buộc] làm là đảm bảo có một giá trị và trong trường hợp của bạn nếu không được chọn, bạn vẫn nhận được sai.


0

Kiểm tra xác thực Foolproof tại đây . Bạn có thể tải xuống / cài đặt nó qua Nuget.

Đó là một thư viện nhỏ tuyệt vời cho loại thứ này.


Ehhhh ... Các thuộc tính xác thực mặc định hoạt động khá tốt.
Pangamma

0
/// <summary> 
///  Summary : -CheckBox for or input type check required validation is not working the root cause and solution as follows
///
///  Problem :
///  The key to this problem lies in interpretation of jQuery validation 'required' rule. I digged a little and find a specific code inside a jquery.validate.unobtrusive.js file:
///  adapters.add("required", function (options) {
///  if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
///    setValidationValues(options, "required", true);
///    }
///   });
///   
///  Fix: (Jquery script fix at page level added in to check box required area)
///  jQuery.validator.unobtrusive.adapters.add("brequired", function (options) {
///   if (options.element.tagName.toUpperCase() == "INPUT" && options.element.type.toUpperCase() == "CHECKBOX") {
///              options.rules["required"] = true;
///   if (options.message) {
///                   options.messages["required"] = options.message;
///                       }
///  Fix : (C# Code for MVC validation)
///  You can see it inherits from common RequiredAttribute. Moreover it implements IClientValidateable. This is to make assure that rule will be propagated to client side (jQuery validation) as well.
///  
///  Annotation example :
///   [BooleanRequired]
///   public bool iAgree { get; set' }
/// </summary>


public class BooleanRequired : RequiredAttribute, IClientValidatable
{

    public BooleanRequired()
    {
    }

    public override bool IsValid(object value)
    {
        return value != null && (bool)value == true;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        return new ModelClientValidationRule[] { new ModelClientValidationRule() { ValidationType = "brequired", ErrorMessage = this.ErrorMessage } };
    }
}

Mặc dù liên kết này có thể trả lời câu hỏi, nhưng tốt hơn hết bạn nên đưa các phần thiết yếu của câu trả lời vào đây và cung cấp liên kết để tham khảo. Các câu trả lời chỉ có liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi.
Ravi Dhoriya ツ

Nó hoạt động Kiểm tra liên kết này với lý do tại sao nó không thành công trên validation- itmeze.com/2010/12/06/...
harikrishnan dhandapani

Hôm nay nó hoạt động. Bạn có thể chắc chắn rằng nó sẽ tiếp tục hoạt động trong 5, 10 năm sau không? Những Q & A DB được tạo ra cho người sử dụng trong tương lai quá
Eliyahu
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.