Deaktivieren Sie das erforderliche Validierungsattribut unter bestimmten Umständen

138

Ich habe mich gefragt, ob es möglich ist, das Attribut Erforderliche Validierung in bestimmten Controller-Aktionen zu deaktivieren. Ich frage mich, weil der Benutzer in einem meiner Bearbeitungsformulare keine Werte für Felder eingeben muss, die er zuvor angegeben hat. Allerdings implementiere ich dann die Logik, dass bei der Eingabe eines Werts eine spezielle Logik zum Aktualisieren des Modells verwendet wird, z. B. das Hashing eines Werts usw.

Irgendwelche Vorschläge, wie man dieses Problem umgehen kann?

BEARBEITEN:
Und ja, die Client-Validierung ist hier ein Problem, da sie das Formular nicht ohne Eingabe eines Werts senden kann.

Alex Hope O'Connor
quelle
3
+1 gut F. Wäre gut, hier die Client-Validierung zu erwähnen. Eine Möglichkeit besteht darin, das Gerät RequiredAttrvollständig zu entfernen und bei Bedarf eine serverseitige Überprüfung durchzuführen. Aber das wäre schwierig für den Kunden
Gideon
4
Punkte für alle, die auch das Deaktivieren bestimmter Felder von der Client-Validierung abdecken (kein Entfernen der Verweise auf die JQuery-Validierung)
Gideon
Vielleicht fehlt mir Ihr Punkt, aber wenn der Benutzer die Werte bereits vorher angegeben hat, sind diese Werte bereits vorhanden und bestehen daher die erforderliche Validierung. Meinten Sie etwas anderes?
Erik Funkenbusch
Da diese Werte inzwischen gehasht wurden, z. B. Kennwort und Sicherheitsantwort. Wenn sie also einen neuen Wert in das Bearbeitungsformular eingeben, möchte ich den neuen Wert vor dem Einfügen erneut hashen, aber ich möchte auch, dass die Option leer bleibt so etwas.
Alex Hope O'Connor
1
@gideon: siehe Adrian Smiths Antwort: stackoverflow.com/a/9781066/114029
Leniel Maccaferri

Antworten:

76

Dieses Problem kann mithilfe von Ansichtsmodellen leicht gelöst werden. Ansichtsmodelle sind Klassen, die speziell auf die Anforderungen einer bestimmten Ansicht zugeschnitten sind. In Ihrem Fall könnten Sie beispielsweise die folgenden Ansichtsmodelle haben:

public UpdateViewView
{
    [Required]
    public string Id { get; set; }

    ... some other properties
}

public class InsertViewModel
{
    public string Id { get; set; }

    ... some other properties
}

welche in ihren entsprechenden Controller-Aktionen verwendet werden:

[HttpPost]
public ActionResult Update(UpdateViewView model)
{
    ...
}

[HttpPost]
public ActionResult Insert(InsertViewModel model)
{
    ...
}
Darin Dimitrov
quelle
Nicht immer wahr, wenn Sie einen Booleschen Wert / Bit haben, der nicht nullwertfähig ist. Aber es macht wirklich keinen Unterschied, da es wahr oder falsch enden wird. Ich hatte CSS, um die erforderlichen Felder hervorzuheben, und das CheckBoxFor-Element wurde fälschlicherweise hervorgehoben. Meine Lösung: $ ("# IsValueTrue"). RemoveAttr ("data-val-required");
Robert Koch
Im Update haben wir in der Regel (FormCollection-Sammlung). Könnten Sie bitte erklären, wie Sie Modell als Parameter verwenden
Raj Kumar
4
Nein, das haben wir normalerweise nicht Update(FormCollection collection), zumindest tue ich das nie. Ich definiere und verwende immer ein bestimmtes Ansichtsmodell : Update(UpdateViewView model).
Darin Dimitrov
Überladungsmethoden mit derselben HTTP-Aktion sind nicht zulässig, daher scheint es mir, dass dies nicht funktionieren würde. Vermisse ich etwas
e11s
@edgi, nein, dir fehlt nichts. Es ist ein Fehler in meinem Beitrag. Die zweite Aktionsmethode sollte natürlich aufgerufen werden Insert. Vielen Dank für den Hinweis.
Darin Dimitrov
55

Wenn Sie die Validierung nur für ein einzelnes Feld auf der Clientseite deaktivieren möchten, können Sie die Validierungsattribute wie folgt überschreiben:

@Html.TexBoxFor(model => model.SomeValue, 
                new Dictionary<string, object> { { "data-val", false }})
Adrian Smith
quelle
20
Was bei mir über jQuery funktioniert hat: $ ("# SomeValue"). RemoveAttr ("data-val-required");
Robert Koch
6
Ich mag diesen Ansatz, aber ich musste die Attribute für die Formularvalidierung neu analysieren mit: $ ('form'). RemoveData ('unobtrusiveValidation'); $ ('form'). removeData ('validator'); $ .validator.unobtrusive.parse ('Selektor für Ihr Formular');
Yannick Smits
15
@Html.TexBoxFor(model => model.SomeValue, new { data_val = false })- IMO leichter zu lesen.
eth0
Ich mochte den größten Teil dieses Ansatzes, um mir eine genaue Kontrolle über jedes Feld zu geben, aber Sie können hinzufügen, um ModelState.IsValid abzubrechen, wenn Sie Daten senden, um sie per POST zu speichern. Vielleicht ein Risiko verursachen?
Felipe FMMobile
4
Wenn Sie es durch jQuery deaktivieren möchten:$(".search select").attr('data-val', false);
Leniel Maccaferri
40

Ich weiß, dass diese Frage vor langer Zeit beantwortet wurde und die akzeptierte Antwort tatsächlich die Arbeit erledigen wird. Aber eines stört mich: Ich muss nur zwei Modelle kopieren, um eine Validierung zu deaktivieren.

Hier ist mein Vorschlag:

public class InsertModel
{
    [Display(...)]
    public virtual string ID { get; set; }

    ...Other properties
}

public class UpdateModel : InsertModel
{
    [Required]
    public override string ID
    {
        get { return base.ID; }
        set { base.ID = value; }
    }
}

Auf diese Weise müssen Sie sich nicht um clientseitige Validierungen kümmern, das Framework verhält sich so, wie es soll. Wenn Sie ein [Display]Attribut für die Basisklasse definieren , müssen Sie es in Ihrer nicht neu definieren UpdateModel.

Und Sie können diese Klassen immer noch auf die gleiche Weise verwenden:

[HttpPost]
public ActionResult Update(UpdateModel model)
{
    ...
}

[HttpPost]
public ActionResult Insert(InsertModel model)
{
    ...
}
PhilDulac
quelle
Ich mag diesen Ansatz besser, insbesondere wenn Sie eine lange Liste von Validierungsattributen haben. In Ihrem Beispiel können Sie der Basisklasse weitere Attribute hinzufügen, um den Nutzen deutlicher zu machen. Der einzige Nachteil, den ich sehen kann, ist, dass es keine Möglichkeit gibt, Eigenschaften zu erben, um die Attribute zu überschreiben. Wenn Sie beispielsweise eine [Erforderlich] -Eigenschaft für die Basisklasse haben, muss die erbende Eigenschaft auch [Erforderlich] sein, es sei denn, Sie haben ein benutzerdefiniertes [Optional] -Attribut.
Yorro
Ich habe auch an so etwas gedacht, obwohl ich ein viewModel habe, das ein Objekt 'Project' hat, das mehrere Attribute hat, und ich möchte nur, dass eines dieser Attribute unter bestimmten Umständen validiert wird. Ich glaube nicht, dass ich ein Attribut eines Objekts einfach überschreiben kann, oder? irgendein Rat?
Vincent de G
Sie können das Attribut nicht überschreiben. Die Basisklasse sollte nur gemeinsame Attribute für alle Unterklassen enthalten. Dann sollten Ihre Unterklassen die Attribute definieren, die sie benötigen.
PhilDulac
1
Eleganteste, wiederverwendbare, klare Lösung. Replikationen sind schlecht. Polymorphismus ist der Weg. +1
T-Moty
In meinem Fall hat eine Basisklasse ein erforderliches Attribut und ich möchte es in meiner übergeordneten Klasse nicht erforderlich machen. Ist es möglich, ohne zwei Kopien des Modells zu haben?
Alexey Strakh
27

Sie können alle Überprüfungen von einer Eigenschaft wie folgt in Ihrer Controller-Aktion entfernen.

ModelState.Remove<ViewModel>(x => x.SomeProperty);

@ Ians Kommentar zu MVC5

Folgendes ist noch möglich

ModelState.Remove("PropertyNameInModel");

Etwas ärgerlich, dass Sie die statische Eingabe mit der aktualisierten API verlieren. Sie können etwas Ähnliches wie auf die alte Weise erreichen, indem Sie eine Instanz des HTML- Hilfsprogramms erstellen und NameExtensions-Methoden verwenden .

jps
quelle
Außer ... es gibt keine Methode ModelState, die dieser Signatur entspricht. Zumindest nicht in MVC 5.
Ian Kemp
Die Frage war nicht, wie alle Validierungen entfernt werden sollten. Auf diese Weise wurde die erforderliche Feldvalidierung entfernt. Möglicherweise möchten Sie dies tun, während Sie andere Validierungsregeln beibehalten.
Richard
15

Client-Seite Um die Validierung für ein Formular zu deaktivieren, werden im Folgenden mehrere Optionen angegeben, die auf meinen Recherchen basieren. Einer von ihnen würde hoffentlich für Sie arbeiten.

Option 1

Ich bevorzuge das und das funktioniert perfekt für mich.

(function ($) {
    $.fn.turnOffValidation = function (form) {
        var settings = form.validate().settings;

        for (var ruleIndex in settings.rules) {
            delete settings.rules[ruleIndex];
        }
    };
})(jQuery); 

und es wie aufrufen

$('#btn').click(function () {
    $(this).turnOffValidation(jQuery('#myForm'));
});

Option 2

$('your selector here').data('val', false);
$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");

Option 3

var settings = $.data($('#myForm').get(0), 'validator').settings;
settings.ignore = ".input";

Option 4

 $("form").get(0).submit();
 jQuery('#createForm').unbind('submit').submit();

Option 5

$('input selector').each(function () {
    $(this).rules('remove');
});

Serverseite

Erstellen Sie ein Attribut und markieren Sie Ihre Aktionsmethode mit diesem Attribut. Passen Sie dies an Ihre spezifischen Bedürfnisse an.

[AttributeUsage(AttributeTargets.All)]
public class IgnoreValidationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var modelState = filterContext.Controller.ViewData.ModelState;

        foreach (var modelValue in modelState.Values)
        {
            modelValue.Errors.Clear();
        }
    }
}

Ein besserer Ansatz wurde hier beschrieben. Aktivieren / Deaktivieren der serverseitigen Validierung von MVC dynamisch

int-i
quelle
$ ('Eingabeselektor'). each (function () {$ (this) .rules ('remove');}); hat mir geholfen
Sachin Pakale
Die Frage betraf speziell das Entfernen der erforderlichen Feldvalidierung und nicht das Entfernen aller Validierungen. Bei Ihrer Antwort geht es darum, alle Validierungen zu entfernen.
Richard
14

Persönlich würde ich eher den Ansatz verwenden, den Darin Dimitrov in seiner Lösung gezeigt hat. Dies gibt Ihnen die Möglichkeit, den Datenanmerkungsansatz mit Validierung zu verwenden UND auf jedem ViewModel separate Datenattribute zu haben, die der jeweiligen Aufgabe entsprechen. Um den Arbeitsaufwand für das Kopieren zwischen Modell und Ansichtsmodell zu minimieren, sollten Sie sich AutoMapper oder ValueInjecter ansehen . Beide haben ihre individuellen Stärken, also überprüfen Sie beide.

Ein weiterer möglicher Ansatz für Sie wäre, Ihr Ansichtsmodell oder Modell von IValidatableObject abzuleiten. Dies gibt Ihnen die Möglichkeit, eine Funktion Validieren zu implementieren. Bei der Validierung können Sie entweder eine Liste der ValidationResult-Elemente zurückgeben oder für jedes Problem, das Sie bei der Validierung feststellen, eine Ertragsrückgabe ausgeben.

Das ValidationResult besteht aus einer Fehlermeldung und einer Liste von Zeichenfolgen mit den Feldnamen. Die Fehlermeldungen werden an einer Stelle in der Nähe der Eingabefelder angezeigt.

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
  if( NumberField < 0 )
  {
    yield return new ValidationResult( 
        "Don't input a negative number", 
        new[] { "NumberField" } );
  }

  if( NumberField > 100 )
  {
    yield return new ValidationResult( 
        "Don't input a number > 100", 
        new[] { "NumberField" } );
  }

  yield break;
}
nttakr
quelle
Können wir dies auf Client-Seite einbinden?
Muhammad Adeel Zahid
Die clientseitige Validierung wird im Allgemeinen nur für einzelne Felder durchgeführt, wobei ein interaktives Feedback zur Feldvalidierung durchgeführt wird, um dem Benutzer die Arbeit zu erleichtern. Da der Objektvalidierungsschritt im Allgemeinen eine abhängige Validierung umfasst (mehrere Felder und / oder Bedingungen, die außerhalb des Objekts selbst liegen), kann dies nicht unbedingt auf der Clientseite durchgeführt werden, selbst wenn Sie den Code in JavaScript kompilieren könnten. Wenn eine komplexe / abhängige Validierung auf der Clientseite in Ihrem Fall einen Mehrwert bietet, müssen Sie den Onsubmit-Rückruf verwenden und die Validierungslogik auf der Clientseite duplizieren.
mindplay.dk
7

Ich glaube, der sauberste Weg hier ist, die clientseitige Validierung zu deaktivieren, und auf der Serverseite müssen Sie:

  1. ModelState ["SomeField"]. Errors.Clear (in Ihrem Controller oder erstellen Sie einen Aktionsfilter, um Fehler zu entfernen, bevor der Controller-Code ausgeführt wird)
  2. Fügen Sie ModelState.AddModelError aus Ihrem Controller-Code hinzu, wenn Sie eine Verletzung Ihrer erkannten Probleme feststellen.

Selbst ein benutzerdefiniertes Ansichtsmodell hier scheint das Problem nicht zu lösen, da die Anzahl dieser vorab beantworteten Felder variieren kann. Wenn dies nicht der Fall ist, ist ein benutzerdefiniertes Ansichtsmodell zwar der einfachste Weg, aber mit der oben genannten Technik können Sie Ihre Validierungsprobleme umgehen.

Adam Tuliper - MSFT
quelle
1
Das ist genau das, was ich brauchte. Ich hatte eine Ansicht und in dieser Ansicht wurden verschiedene Aktionen ausgeführt, sodass ich es mit verschiedenen ViewModels nicht schaffen konnte. Dies funktioniert wie ein Zauber
ggderas
6

Dies war die Antwort eines anderen in den Kommentaren ... aber es sollte eine echte Antwort sein:

$("#SomeValue").removeAttr("data-val-required")

getestet auf MVC 6 mit einem Feld mit dem [Required]Attribut

Antwort gestohlen von https://stackoverflow.com/users/73382/rob oben

Mike_Matthews_II
quelle
1
Was ist mit der serverseitigen Validierung?
T-Moty
ModelState.Remove, richtig? Für mich war das Problem jedenfalls, dass eine zweite Entität in mein Modell aufgenommen wurde ... die primäre, für die ich eine Validierung wollte, aber die sekundäre musste auf dieser Seite nicht validiert werden ... also in diesem Szenario war nur die JQuery notwendig.
Mike_Matthews_II
Ich denke, dass der Link defekt ist, also bitte bearbeiten. Dies ist eine teilweise Antwort
T-Moty
Es ist seltsam, dass Sie sagen, dass dies in MVC6 funktioniert (ich habe derzeit keine Option zum Testen auf MVC6), aber nicht auf MVC4, das ich derzeit verwende.
eaglei22
Die Frage ist für MVC / C # - nicht JS, die Antwort würde nicht serverseitig funktionieren
mtbennett
2

Ich hatte dieses Problem beim Erstellen einer Bearbeitungsansicht für mein Modell und möchte nur ein Feld aktualisieren.

Meine Lösung für den einfachsten Weg besteht darin, die beiden Felder wie folgt zu setzen:

 <%: Html.HiddenFor(model => model.ID) %>
 <%: Html.HiddenFor(model => model.Name)%>
 <%: Html.HiddenFor(model => model.Content)%>
 <%: Html.TextAreaFor(model => model.Comments)%>

Kommentare ist das Feld, das ich nur in der Bearbeitungsansicht aktualisiere und das kein erforderliches Attribut hat.

ASP.NET MVC 3-Entität

Felipe FMMobile
quelle
1

AFAIK Sie können Attribute nicht zur Laufzeit entfernen, sondern nur ihre Werte ändern (dh: schreibgeschützt wahr / falsch). Suchen Sie hier nach etwas Ähnlichem . Als eine andere Möglichkeit, das zu tun, was Sie wollen, ohne mit Attributen herumzuspielen, werde ich ein ViewModel für Ihre spezifische Aktion verwenden, damit Sie die gesamte Logik einfügen können, ohne die von anderen Controllern benötigte Logik zu beschädigen. Wenn Sie versuchen, eine Art Assistenten (ein Formular mit mehreren Schritten) zu erhalten, können Sie stattdessen die bereits kompilierten Felder serialisieren und mit TempData in Ihre Schritte einbeziehen. (Für Hilfe bei der Deserialisierung der Serialisierung können Sie MVC-Futures verwenden. )

Iridio
quelle
1

Was @Darin gesagt hat, würde ich auch empfehlen. Ich möchte jedoch hinzufügen (und als Antwort auf einen der Kommentare), dass Sie diese Methode tatsächlich auch für primitive Typen wie Bit, Bool und sogar Strukturen wie Guid verwenden können, indem Sie sie einfach auf Null setzen. Sobald Sie dies tun, Requiredfunktioniert das Attribut wie erwartet.

public UpdateViewView
{
    [Required]
    public Guid? Id { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public int? Age { get; set; }
    [Required]
    public bool? IsApproved { get; set; }
    //... some other properties
}
Nick Albrecht
quelle
1

Ab MVC 5 kann dies leicht erreicht werden, indem Sie dies in Ihre hinzufügen global.asax.

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
Yom S.
quelle
1

Ich suchte nach einer Lösung, bei der ich dasselbe Modell für das Einfügen und Aktualisieren in der Web-API verwenden kann. In meiner Situation ist dies immer ein Körperinhalt. Die [Requiered]Attribute müssen übersprungen werden, wenn es sich um eine Aktualisierungsmethode handelt. In meiner Lösung platzieren Sie ein Attribut [IgnoreRequiredValidations]über der Methode. Dies ist wie folgt:

public class WebServiceController : ApiController
{
    [HttpPost]
    public IHttpActionResult Insert(SameModel model)
    {
        ...
    }

    [HttpPut]
    [IgnoreRequiredValidations]
    public IHttpActionResult Update(SameModel model)
    {
        ...
    }

    ...

Was muss noch getan werden? Beim Start muss ein eigener BodyModelValidator erstellt und hinzugefügt werden. Dies ist in der HttpConfiguration und sieht folgendermaßen aus:config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator());

using Owin;
using your_namespace.Web.Http.Validation;

[assembly: OwinStartup(typeof(your_namespace.Startup))]

namespace your_namespace
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            Configuration(app, new HttpConfiguration());
        }

        public void Configuration(IAppBuilder app, HttpConfiguration config)
        {
            config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator());
        }

        ...

Mein eigener BodyModelValidator wird vom DefaultBodyModelValidator abgeleitet. Und ich finde heraus, dass ich die 'ShallowValidate'-Methode überschreiben musste. Bei dieser Überschreibung filtere ich die erforderlichen Modellvalidatoren. Und jetzt die IgnoreRequiredOrDefaultBodyModelValidator-Klasse und die IgnoreRequiredValidations-Attributklasse:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Http.Controllers;
using System.Web.Http.Metadata;
using System.Web.Http.Validation;

namespace your_namespace.Web.Http.Validation
{
    public class IgnoreRequiredOrDefaultBodyModelValidator : DefaultBodyModelValidator
    {
        private static ConcurrentDictionary<HttpActionBinding, bool> _ignoreRequiredValidationByActionBindingCache;

        static IgnoreRequiredOrDefaultBodyModelValidator()
        {
            _ignoreRequiredValidationByActionBindingCache = new ConcurrentDictionary<HttpActionBinding, bool>();
        }

        protected override bool ShallowValidate(ModelMetadata metadata, BodyModelValidatorContext validationContext, object container, IEnumerable<ModelValidator> validators)
        {
            var actionContext = validationContext.ActionContext;

            if (RequiredValidationsIsIgnored(actionContext.ActionDescriptor.ActionBinding))
                validators = validators.Where(v => !v.IsRequired);          

            return base.ShallowValidate(metadata, validationContext, container, validators);
        }

        #region RequiredValidationsIsIgnored
        private bool RequiredValidationsIsIgnored(HttpActionBinding actionBinding)
        {
            bool ignore;

            if (!_ignoreRequiredValidationByActionBindingCache.TryGetValue(actionBinding, out ignore))
                _ignoreRequiredValidationByActionBindingCache.TryAdd(actionBinding, ignore = RequiredValidationsIsIgnored(actionBinding.ActionDescriptor as ReflectedHttpActionDescriptor));

            return ignore;
        }

        private bool RequiredValidationsIsIgnored(ReflectedHttpActionDescriptor actionDescriptor)
        {
            if (actionDescriptor == null)
                return false;

            return actionDescriptor.MethodInfo.GetCustomAttribute<IgnoreRequiredValidationsAttribute>(false) != null;
        } 
        #endregion
    }

    [AttributeUsage(AttributeTargets.Method, Inherited = true)]
    public class IgnoreRequiredValidationsAttribute : Attribute
    {

    }
}

Quellen:

Roberto B.
quelle
0

Wenn Sie kein anderes ViewModel verwenden möchten, können Sie Client-Überprüfungen in der Ansicht deaktivieren und die Überprüfungen auf dem Server für die Eigenschaften entfernen, die Sie ignorieren möchten. Bitte überprüfen Sie diese Antwort für eine ausführlichere Erklärung https://stackoverflow.com/a/15248790/1128216

Jonathan Morales Vélez
quelle
0

In meinem Fall wurde auf vielen Seiten dasselbe Modell für Wiederverwendbarkeitszwecke verwendet. Also habe ich ein benutzerdefiniertes Attribut erstellt, das nach Ausschlüssen sucht

public class ValidateAttribute : ActionFilterAttribute
{
    public string Exclude { get; set; }
    public string Base { get; set; }
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (!string.IsNullOrWhiteSpace(this.Exclude))
        {
            string[] excludes = this.Exclude.Split(',');
            foreach (var exclude in excludes)
            {
                actionContext.ModelState.Remove(Base + "." + exclude);
            }
        }
        if (actionContext.ModelState.IsValid == false)
        {
            var mediaType = new MediaTypeHeaderValue("application/json");
            var error = actionContext.ModelState;

            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, error.Keys, mediaType);

        }
    }
}

und in Ihrem Controller

[Validate(Base= "person",Exclude ="Age,Name")]
    public async Task<IHttpActionResult> Save(User person)
    {

            //do something           

    }

Angenommen, das Modell ist

public class User
{
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    [Range(18,99)]
    public string Age { get; set; }
    [MaxLength(250)]
    public string Address { get; set; }
}
Nithin Chandran
quelle
-1

Ja, das erforderliche Attribut kann deaktiviert werden. Erstellen Sie Ihr eigenes benutzerdefiniertes Klassenattribut (Beispielcode mit dem Namen ChangeableRequired) in RequiredAtribute, fügen Sie eine deaktivierte Eigenschaft hinzu und überschreiben Sie die IsValid-Methode, um zu überprüfen, ob sie deaktiviert ist. Verwenden Sie Reflection, um die deaktivierte Poperty wie folgt festzulegen:

Benutzerdefiniertes Attribut:

namespace System.ComponentModel.DataAnnotations
{
    public class ChangeableRequired : RequiredAttribute
    {
       public bool Disabled { get; set; }

       public override bool IsValid(object value)
       {
          if (Disabled)
          {
            return true;
          }

          return base.IsValid(value);
       }
    }
}

Aktualisieren Sie Ihre Eigenschaft, um Ihr neues benutzerdefiniertes Attribut zu verwenden:

 class Forex
 {
 ....
    [ChangeableRequired]
    public decimal? ExchangeRate {get;set;}
 ....
 }

Wo Sie die Eigenschaft deaktivieren müssen, verwenden Sie Reflection, um sie festzulegen:

Forex forex = new Forex();
// Get Property Descriptor from instance with the Property name
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(forex.GetType())["ExchangeRate"];
//Search for Attribute
ChangeableRequired attrib =  (ChangeableRequired)descriptor.Attributes[typeof(ChangeableRequired)];

// Set Attribute to true to Disable
attrib.Disabled = true;

Das fühlt sich gut und sauber an?

NB: Die obige Validierung wird deaktiviert, solange Ihre Objektinstanz aktiv ist.

Ernest Gunning
quelle
Nach einigen Debatten möchte ich erwähnen, dass ich nicht empfehle, die Validierung zu deaktivieren, sondern die Regel zu überprüfen. Wenn Sie es deaktivieren, erstellen Sie eine Abhängigkeit, um die Regel wieder zu aktivieren, und ich würde vorschlagen, die Regel zu überprüfen.
Ernest Gunning
Das Ändern eines statischen Werts, um die gesamte Validierung dieses Felds, das innerhalb desselben Prozesses ausgeführt wird, vollständig zu deaktivieren, klingt nach einer schrecklichen Idee.
Jeremy Lakeman