MVC-Modell erfordern true


83

Gibt es eine Möglichkeit durch Datenanmerkungen, dass eine boolesche Eigenschaft auf true gesetzt werden muss?

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

Was genau ist der Anwendungsfall dafür? Könnten Sie die Eigenschaft nicht einfach schreibgeschützt lassen und die ganze Zeit true zurückgeben?
Jan Thomä

1
Es ist ziemlich viel zu sagen ... Hey Kumpel, du hast vergessen zu überprüfen, ob ich damit einverstanden bin ... was das Modell ungültig machen sollte.
Marty Trenouth

Ich denke, das ist etwas, das Sie clientseitig behandeln möchten.
PsychoCoder

14
@ PsychoCoder: Es sollte auf beiden Seiten gehandhabt werden ... nicht nur auf der Client-Seite. Ich habe nur gesucht, ob dies durch Hinzufügen einer einfachen Datenanmerkung behoben werden kann.
Marty Trenouth

Antworten:


48

Sie können Ihren eigenen Validator erstellen:

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
}

Ich würde in Betracht ziehen, dies durch eine clientseitige Implementierung zu verbessern - anstatt die in anderen Antworten erwähnte Remote-Validierung zu verwenden, verwenden Sie die hier beschriebene unauffällige Schreibweise: jacopretorius.net/2011/01/client-side-validation-in-mvc-3 .html
SamStephens

Dies ist eine gute (und getestete) schnelle Lösung für uns. Wir können auf die clientseitige Validierung in der @ dazbradbury-Lösung verzichten (auch eine gute), da wir diese nur für ein einzelnes Kontrollkästchen auf der letzten Seite einer Umfrage benötigen.
Seth

return (bool) value == true;Dies ist ein redundanter Vergleich
T-Moty

129

Ich würde einen Validator sowohl für die Server- als auch für die Clientseite erstellen. Mit MVC und unauffälliger Formularvalidierung kann dies einfach durch Folgendes erreicht werden:

Erstellen Sie zunächst eine Klasse in Ihrem Projekt, um die serverseitige Validierung wie folgt durchzuführen:

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

Kommentieren Sie anschließend die entsprechende Eigenschaft in Ihrem Modell:

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

Aktivieren Sie schließlich die clientseitige Validierung, indem Sie Ihrer Ansicht das folgende Skript hinzufügen:

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

Hinweis: Wir haben bereits eine Methode erstellt, mit GetClientValidationRulesder unsere Anmerkung aus unserem Modell in die Ansicht verschoben wird.

Wenn Sie Ressourcendateien verwenden, um die Fehlermeldung für die Internationalisierung bereitzustellen, entfernen Sie den FormatErrorMessageAufruf (oder rufen Sie einfach die Basis auf) und optimieren Sie die GetClientValidationRulesMethode wie folgt :

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
Danke dafür - es funktioniert super! Es funktioniert besser, wenn die überschriebene FormatErrorMessage-Methode entfernt wurde. Auf diese Weise funktioniert die Lokalisierung von Fehlermeldungen aus Ressourcendateien. Meine Verwendung: [EnforceTrue (ErrorMessageResourceType = typeof (ValidationMessages), ErrorMessageResourceName = "TermsAndConditionsRequired")]
Matt Frear

2
Ich kann die clientseitige Validierung nicht zum Laufen bringen und kann anscheinend nicht sagen, was ich falsch mache. Wo genau soll ich das Javacsript ablegen? In der Kopfmarke? Neben dem Controller?
vsdev

Ich stimme zu, dies sollte die Antwort sein
Simua

1
Großartige Lösung, die die Leistungsfähigkeit benutzerdefinierter Validierungsattribute zeigt! Ich empfehle jedoch, das Skript zur Wiederverwendung in eine global referenzierte js-Datei und nicht in die Ansicht (en) zu legen. Außerdem ist es am besten, alle Arten zu behandeln, wie die Nachrichtenzeichenfolgen hinzugefügt werden können: Standard, wenn keine angegeben ist, oder die Nachrichtenzeichenfolge oder aus einer Ressourcendatei.
Jeepwran

1
Tolle Lösung, danke fürs posten. Für diejenigen, die die clientseitige Validierung nicht zum Laufen bringen können: Sie müssen die jQuery-Validierung erweitern, bevor die zu validierenden Steuerelemente geladen wurden. Fügen Sie das Skript daher in den Kopf und nicht in das Fenster window.onload / $ (document) ein ) .ready () Ereignis.
Evert

91

Ich weiß, dass dies ein älterer Beitrag ist, wollte aber einen einfachen serverseitigen Weg teilen, um dies zu tun. Sie erstellen eine öffentliche Eigenschaft, die auf true festgelegt ist, und vergleichen Ihren Bool mit dieser Eigenschaft. Wenn Ihr Bool nicht aktiviert ist (standardmäßig false), wird das Formular nicht überprüft.

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

Rasiermessercode

@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
Der Einfachheit halber +1. Zu Ihrer Information: Ich musste die Eigenschaft 'isTrue' öffentlich machen, damit dies funktioniert.
Tod Birdsall

Vergleichen ist nicht für mich in MVC4
Michael Rudner Evanchik

Super Lösung tolle Lösung
Sreerejith SS

9
Und wenn Sie ein verstecktes für die "isTrue" -Eigenschaft hinzufügen, erhalten Sie eine clientseitige Validierung
billoreid

1
Es hat bei mir nicht funktioniert, diese großartig aussehende Lösung zu ärgern. Getestet auf Mvc 5.2.3.
Harvey

21

Ich habe mehrere Lösungen ausprobiert, aber keine davon hat für mich vollständig funktioniert, um sowohl eine clientseitige als auch eine serverseitige Validierung zu erhalten. Also, was ich in meiner MVC 5-Anwendung getan habe, um sie zum Laufen zu bringen:

In Ihrem ViewModel (zur serverseitigen Validierung):

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

Auf Ihrer Razor-Seite (zur clientseitigen Validierung):

<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
Charmante Lösung!
Tobias

3
Achten Sie auf den Wert für das versteckte Feld ("true")!
Tobias

10

Ich möchte die Leute nur auf die folgende Geige hinweisen: https://dotnetfiddle.net/JbPh0X

Der Benutzer hat [Range(typeof(bool), "true", "true", ErrorMessage = "You gotta tick the box!")]seiner booleschen Eigenschaft hinzugefügt , wodurch die serverseitige Validierung funktioniert.

Damit auch die clientseitige Validierung funktioniert, haben sie das folgende Skript hinzugefügt:

// 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

Überprüfen Sie einfach, ob die Zeichenfolgendarstellung gleich ist True:

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

@ JeradRose Es ist auf dem Server einwandfrei validiert. Beziehen Sie sich auf die clientseitige Validierung?
ta.speot.is

3
Bestätigt, dies funktioniert serverseitig, aber nicht clientseitig
Matt Frear

Ich dachte, dass die serverseitige Validierung eine Ausnahme vom Typ Mismatch aufweist, die versucht, einen Bool mit einem String zu vergleichen.
Jerad Rose

RegularExpressionAttributeWird intern verwendet Convert.ToString, um die Zeichenfolgendarstellung des Werts der Eigenschaft abzurufen (der als übergeben wird object).
ta.speot.is

Ich denke, diese Antwort ist einfacher als @ fields-cage +1 von mir
Aaron Hudon

6

[Required]Attribut steht für das Erfordernis eines beliebigen Wertes - es kann entweder wahr oder falsch sein. Dafür müssten Sie eine andere Validierung verwenden.


5

Sie können entweder Ihr eigenes Attribut erstellen oder das CustomValidationAttribute verwenden .

So würden Sie das CustomValidationAttribute verwenden:

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

Dabei ist BoolValidation definiert als:

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

3

Weiterverfolgung des Beitrags von ta.speot.is und des Kommentars von Jerad Rose:

Der angegebene Beitrag funktioniert nicht clientseitig mit unauffälliger Validierung. Dies sollte in beiden Lagern (Client & Server) funktionieren:

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

Ich weiß nicht, ob dies ein neueres Versionsproblem ist, aber es funktioniert bei mir nicht mit jquery.validate 1.19.2 und jquery.validate.unobtrusive 3.2.11. Das Problem scheint zu sein, dass die regexMethode unauffällig definiert, dass zuerst überprüft wird, ob das Kontrollkästchen optional ist, bevor der reguläre Ausdruck überprüft wird. Dies ist sinnvoll, mit der Ausnahme, dass jquery.validate jedes nicht aktivierte Kontrollkästchen als optional betrachtet. tl; dr Es wird die Regex nur für aktivierte Kontrollkästchen ausgeführt. Wir können einen Shim für die regex validatorMethode hinzufügen oder einfach einen benutzerdefinierten Validator erstellen.
xr280xr

2

Haben Sie die entsprechenden Elemente in der web.config eingerichtet ?

Dies könnte dazu führen, dass die Validierung nicht funktioniert.

Sie können auch versuchen, ein benutzerdefiniertes Validierungsattribut zu erstellen (da es [Required]nur darum geht, ob es vorhanden ist oder nicht, und Sie sich um den Wert kümmern):

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

Dann Verwendung:

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

Von hier aus .


2

Für ASP.NET Core MVC gibt es hier eine Client- und Server-Validierung, die auf der Lösung von dazbradbury basiert

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

Und dann auf dem Client:

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

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

Dann ist die Verwendung:

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

2

.NET Core MVC - Erforderliches Kontrollkästchen mit Datenanmerkungen

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>


1

Ich kenne keinen Weg durch DataAnnotations, aber dies ist in Ihrem Controller einfach möglich.

public ActionResult Add(Domain.Something model)
{

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

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

}

Die einzige andere Möglichkeit wäre, einen benutzerdefinierten Validator für die Serverseite und einen Remote-Validator für die Client-Seite zu erstellen (Remote-Validierung ist nur in MVC3 + verfügbar).


Ein bisschen neu, wie man das Boolesche Flag bereits überprüft ... wollte wissen, ob es eine Datenanmerkung dafür gibt.
Marty Trenouth

1

Das hat bei mir funktioniert. Sonst nichts. Mvc 5:

Modell

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

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

Aussicht

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

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein


0

Ich denke, der beste Weg, dies zu handhaben, besteht darin, einfach in Ihrem Controller zu überprüfen, ob das Kästchen wahr ist. Andernfalls fügen Sie Ihrem Modell einfach einen Fehler hinzu und lassen Sie es Ihre Ansicht erneut anzeigen.

Wie bereits erwähnt, muss [Erforderlich] nur sicherstellen, dass ein Wert vorhanden ist. Wenn dies nicht aktiviert ist, werden Sie immer noch falsch angezeigt.


0

Schauen Sie sich hier die kinderleichte Validierung an . Sie können es über Nuget herunterladen / installieren.

Es ist eine großartige kleine Bibliothek für solche Dinge.


Ehhhh ... Standard-Validierungsattribute funktionieren jedoch ziemlich gut.
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 } };
    }
}

Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert.
Ravi Dhoriya

Es funktioniert Überprüfen Sie diesen Link mit Grund, warum es bei der Validierung fehlschlägt- itmeze.com/2010/12/06/…
dhandapani harikrishnan

Heute funktioniert es. Können Sie sicher sein, dass es in 5, 10 Jahren weiter funktioniert? Diese Q & A-Datenbank wurde auch für zukünftige Benutzer erstellt
Eliyahu

0

Ich habe versucht, die Antwort von fields.cage zu verwenden, und es hat bei mir nicht ganz funktioniert, aber etwas Einfacheres hat funktioniert, und ich bin mir nicht sicher, warum (vielleicht eine andere Razor-Version?), Aber alles, was ich tun musste, war Folgendes:

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

Und in der .cshtml-Datei:

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

Das funktioniert bei mir nicht clientseitig. Aus irgendeinem Grund befindet sich der an die Regelmethode jquery.validate übergebene Parameter dort, [NaN, NaN]wo er sein sollte[true, true]
xr280xr

@ xr280xr Auch wenn der Benutzer das Kontrollkästchen aktiviert hat?
Dronz
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.