ASP.NET MVC सशर्त सत्यापन


129

मॉडल पर सशर्त सत्यापन करने के लिए डेटा एनोटेशन का उपयोग कैसे करें?

उदाहरण के लिए, हम कहते हैं कि हमारे पास निम्न मॉडल (व्यक्ति और वरिष्ठ) हैं:

public class Person
{
    [Required(ErrorMessage = "*")]
    public string Name
    {
        get;
        set;
    }

    public bool IsSenior
    {
        get;
        set;
    }

    public Senior Senior
    {
        get;
        set;
    }
}

public class Senior
{
    [Required(ErrorMessage = "*")]//this should be conditional validation, based on the "IsSenior" value
    public string Description
    {
        get;
        set;
    }
}

और निम्नलिखित दृश्य:

<%= Html.EditorFor(m => m.Name)%>
<%= Html.ValidationMessageFor(m => m.Name)%>

<%= Html.CheckBoxFor(m => m.IsSenior)%>
<%= Html.ValidationMessageFor(m => m.IsSenior)%>

<%= Html.CheckBoxFor(m => m.Senior.Description)%>
<%= Html.ValidationMessageFor(m => m.Senior.Description)%>

मैं "सीनियर डिस्क्रिप्शन" प्रॉपर्टी सशर्त आवश्यक फ़ील्ड होना चाहूंगा जो "इस्सेनिओर" के चयन के आधार पर उचित (सत्य -> ​​आवश्यक) हो। डेटा एनोटेशन के साथ ASP.NET MVC 2 में सशर्त मान्यता कैसे लागू करें?


1
मैंने हाल ही में इसी तरह का सवाल पूछा है: stackoverflow.com/questions/2280539/…
डारिन दिमित्रोव

मैं उलझन में हूं। एक Seniorवस्तु हमेशा एक वरिष्ठ होती है, इसलिए उस मामले में IsSenior गलत क्यों हो सकता है। क्या आपको Person.IsSeniorझूठे होने पर सिर्फ 'पर्सन.सिनियर' संपत्ति की जरूरत नहीं है। या IsSeniorसंपत्ति को इस प्रकार लागू क्यों नहीं किया जाता है bool IsSenior { get { return this.Senior != null; } }:।
स्टीवन

स्टीवन: "IsSenior" दृश्य में चेकबॉक्स क्षेत्र में अनुवाद करता है। जब उपयोगकर्ता "IsSenior" चेकबॉक्स की जाँच करता है, तो "सीनियर.डिस्क्रिप्शन" फ़ील्ड अनिवार्य हो जाता है।
पीटर स्टेग्नार

डारिन दिमित्रोव: अच्छी तरह से, लेकिन काफी नहीं। आप देखें, आप कैसे प्राप्त करेंगे कि त्रुटि मैसेज विशिष्ट क्षेत्र के लिए उपयुक्त है? यदि आप ऑब्जेक्ट स्तर पर मान्य हैं, तो आपको ऑब्जेक्ट स्तर पर एक त्रुटि मिलती है। मुझे संपत्ति के स्तर पर त्रुटि की आवश्यकता है।
पीटर स्टेग्नार

जवाबों:


150

MVC3 में सशर्त सत्यापन नियम जोड़ने का एक बेहतर तरीका है; अपने मॉडल को विरासत में लें IValidatableObjectऔर Validateविधि को लागू करें :

public class Person : IValidatableObject
{
    public string Name { get; set; }
    public bool IsSenior { get; set; }
    public Senior Senior { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
        if (IsSenior && string.IsNullOrEmpty(Senior.Description)) 
            yield return new ValidationResult("Description must be supplied.");
    }
}

ASP.NET MVC 3 (पूर्वावलोकन 1) का परिचय देते हुए अधिक पढ़ें ।


यदि संपत्ति "int" प्रकार है, तो उस मूल्य की आवश्यकता होती है, यदि उस क्षेत्र को भरें, वैधता काम नहीं करती है ..
Jeyhun Rahimov

2
दुर्भाग्य से, Microsoft ने इसे गलत परत में डाल दिया - सत्यापन व्यावसायिक तर्क है और यह इंटरफ़ेस System.Web DLL में है। इसका उपयोग करने के लिए, आपको अपनी व्यावसायिक परत को एक प्रस्तुति तकनीक पर निर्भरता देनी होगी।
नाइटऑवल 88

7
यदि आप इसे लागू करते हैं तो
फाल्कनवेबटेक.

4
falconwebtech.com/post/… - @viperguynaz यह काम नहीं कर रहा है
स्मित पटेल

1
@RayLoveless आपको कॉल करना चाहिए ModelState.IsValid- सीधे Validate पर कॉल नहीं करना
viperguynaz

63

मैंने "ModelState" को संभाल कर इसे हल किया है शब्दकोश को , जो नियंत्रक द्वारा निहित है। ModelState डिक्शनरी में वे सभी सदस्य शामिल हैं जिन्हें मान्य किया जाना है।

यहाँ समाधान है:

यदि आपको कुछ फ़ील्ड के आधार पर एक सशर्त मान्यता को लागू करने की आवश्यकता है (जैसे यदि ए = सच है, तो बी की आवश्यकता है), जबकि उच्च स्तरीय संदेश संदेश को बनाए रखना (यह कस्टम सत्यापनकर्ताओं के लिए सही नहीं है जो ऑब्जेक्ट स्तर पर हैं) आप इसे प्राप्त कर सकते हैं "ModelState" को संभालने से, केवल अवांछित मान्यताओं को हटाने से।

... किसी वर्ग में ...

public bool PropertyThatRequiredAnotherFieldToBeFilled
{
  get;
  set;
}

[Required(ErrorMessage = "*")] 
public string DepentedProperty
{
  get;
  set;
}

... वर्ग जारी है ...

... कुछ नियंत्रक क्रिया में ...

if (!PropertyThatRequiredAnotherFieldToBeFilled)
{
   this.ModelState.Remove("DepentedProperty");
}

...

इसके साथ, हम सशर्त मान्यता प्राप्त करते हैं, जबकि बाकी सब समान छोड़ते हैं।


अपडेट करें:

यह मेरा अंतिम कार्यान्वयन है: मैंने मॉडल पर एक इंटरफ़ेस का उपयोग किया है और एक्शन विशेषता जो उस मॉडल को मान्य करता है जो उक्त इंटरफ़ेस को लागू करता है। इंटरफ़ेस वैलिडेट (मॉडलस्टैट मॉडल मॉडलस्टेट) विधि का वर्णन करता है। कार्रवाई पर विशेषता सिर्फ आईवीडीलेटर के लिए वैध (मॉडलस्टेट) को कॉल करता है।

मैं इस उत्तर को जटिल नहीं करना चाहता था, इसलिए मैंने अंतिम कार्यान्वयन विवरण (जो, अंत में, उत्पादन कोड में बात करता है) का उल्लेख नहीं किया।


17
नकारात्मक पक्ष यह है कि आपके सत्यापन तर्क का एक भाग मॉडल में और दूसरा भाग नियंत्रक (ओं) में स्थित है।
क्रिस्टोफ़ क्ले

बेशक यह आवश्यक नहीं है। मैं सिर्फ सबसे बुनियादी उदाहरण दिखाता हूं। मैंने इसे मॉडल पर इंटरफ़ेस के साथ और एक्शन विशेषता के साथ लागू किया है जो मॉडल को मान्य करता है जो उल्लिखित इंटरफ़ेस को लागू करता है। इंटरफ़ेस Validate (ModelStateDictionary modelState) विधि को पूरा करता है। तो अंत में आप मॉडल में सभी सत्यापन करते हैं। वैसे भी, अच्छी बात है।
पीटर स्टेग्नार

मुझे इस समय इस दृष्टिकोण की सादगी पसंद है जब तक कि एमवीसी टीम कुछ बेहतर बॉक्स का निर्माण नहीं करती। लेकिन क्या ग्राहक समाधान सत्यापन के साथ आपका समाधान सक्षम है ??
आरोन

2
@ ऐरन: मुझे खुशी है कि आपको समाधान पसंद है, लेकिन दुर्भाग्य से यह समाधान क्लाइंट साइड सत्यापन के साथ काम नहीं करता है (जैसा कि प्रत्येक सत्यापन विशेषता को इसके जावास्क्रिप्ट कार्यान्वयन की आवश्यकता है)। आप अपने आप को "रिमोट" विशेषता के साथ मदद कर सकते हैं, इसलिए इसे मान्य करने के लिए सिर्फ अजाक्स कॉल का उत्सर्जन किया जाएगा।
पीटर स्टेनगनर

क्या आप इस उत्तर पर विस्तार कर पा रहे हैं? यह कुछ समझ में आता है, लेकिन मैं यह सुनिश्चित करना चाहता हूं कि मैं इस पर क्रिस्टल हूं। मैं इस सटीक स्थिति का सामना कर रहा हूं, और मैं इसे हल करना चाहता हूं।
रिचर्ड बी

36

मुझे कल भी यही समस्या थी लेकिन मैंने इसे बहुत साफ तरीके से किया जो क्लाइंट साइड और सर्वर साइड सत्यापन दोनों के लिए काम करता है।

शर्त: मॉडल में अन्य संपत्ति के मूल्य के आधार पर, आप आवश्यक एक और संपत्ति बनाना चाहते हैं। यहाँ कोड है

public class RequiredIfAttribute : RequiredAttribute
{
    private String PropertyName { get; set; }
    private Object DesiredValue { get; set; }

    public RequiredIfAttribute(String propertyName, Object desiredvalue)
    {
        PropertyName = propertyName;
        DesiredValue = desiredvalue;
    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        Object instance = context.ObjectInstance;
        Type type = instance.GetType();
        Object proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
        if (proprtyvalue.ToString() == DesiredValue.ToString())
        {
            ValidationResult result = base.IsValid(value, context);
            return result;
        }
        return ValidationResult.Success;
    }
}

यहाँ PropertyName वह संपत्ति है जिस पर आप अपनी स्थिति बनाना चाहते हैं DesiredValue प्रॉपर्टीनाम (संपत्ति) का विशेष मूल्य है जिसके लिए आपकी अन्य संपत्ति को आवश्यक रूप से मान्य किया जाना है।

कहो आपके पास निम्नलिखित है

public class User
{
    public UserType UserType { get; set; }

    [RequiredIf("UserType", UserType.Admin, ErrorMessageResourceName = "PasswordRequired", ErrorMessageResourceType = typeof(ResourceString))]
    public string Password
    {
        get;
        set;
    }
}

अंत में, लेकिन कम से कम नहीं, अपनी विशेषता के लिए एडॉप्टर रजिस्टर करें ताकि यह क्लाइंट साइड सत्यापन कर सके (मैंने इसे Global.asax, Application_Start में डाल दिया है)

 DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute),typeof(RequiredAttributeAdapter));

यह मूल शुरुआती बिंदु miroprocessordev.blogspot.com/2012/08/…
Dan Hunex

वहाँ asp.net mvc2 में कोई समान समाधान है? ValidationResult, ValidationContext classes asp.net mvc2 (.net Framework 3.5) में उपलब्ध नहीं हैं
User_MVC

2
यह केवल लिंक किए गए ब्लॉग के रूप में सर्वर-साइड काम करता है
Pakman

2
मैं MVC5 के साथ क्लाइंट पक्ष में इस काम को प्राप्त करने में कामयाब रहा, लेकिन क्लाइंट में यह पुष्टि करता है कि कोई भी बात नहीं है कि DesiredValue क्या है।
गीतांगना

1
@ डन हनेक्स: एमवीसी 4 में, मैं क्लाइंट साइड पर ठीक से काम करने में कामयाब नहीं हुआ हूं और यह इस बात की पुष्टि करता है कि डिस्एर्डवैल्यू कोई बात नहीं है। कोई मदद pls?
जैक

34

मैं इस अद्भुत नगेट का उपयोग कर रहा हूं जो डायनेमिक एनोटेशन ExpressiveAnnotations करता है

आप किसी भी तर्क को मान्य कर सकते हैं, जिसका आप सपना देख सकते हैं:

public string Email { get; set; }
public string Phone { get; set; }
[RequiredIf("Email != null")]
[RequiredIf("Phone != null")]
[AssertThat("AgreeToContact == true")]
public bool? AgreeToContact { get; set; }

3
ExpressiveAnnotation लाइब्रेरी यहां सभी उत्तरों का सबसे अधिक लचीला और सामान्य समाधान है। साझा करने के लिए धन्यवाद!
सुधांशु मिश्रा

2
मैं एक ठोस दिन के लिए एक समाधान खोजने की कोशिश कर रहा है मेरे सिर को पीट रहा है। ExpressiveAnnotations मेरे लिए ठीक लग रहा है!
कावरमैन

ExpressiveAnnotation लाइब्रेरी कमाल की है!
डग नूड्सन

1
इसमें क्लाइंट साइड सपोर्ट भी है!
नटरास

1
हालाँकि .NET Core के लिए कोई समर्थन नहीं है, और ऐसा नहीं लगता है कि ऐसा होगा।
गोसर

18

आप मॉडलस्टोर से त्रुटियों को हटाकर सत्यापनकर्ताओं को सशर्त रूप से अक्षम कर सकते हैं:

ModelState["DependentProperty"].Errors.Clear();


6

अब एक ढांचा है जो इस सशर्त सत्यापन (अन्य उपयोगी डेटा एनोटेशन सत्यापन के बीच) को बॉक्स से बाहर करता है: http://foolproof.codeplex.com/

विशेष रूप से, [RequiredIfTrue ("IsSenior")] सत्यापनकर्ता पर एक नज़र डालें। आप इसे सीधे उस संपत्ति पर डालते हैं जिसे आप मान्य करना चाहते हैं, इसलिए आपको "वरिष्ठ" संपत्ति से जुड़ी सत्यापन त्रुटि का वांछित व्यवहार मिलता है।

यह एक NuGet पैकेज के रूप में उपलब्ध है।


3

आपको व्यक्तिगत स्तर पर मान्य करने की आवश्यकता है, न कि वरिष्ठ स्तर पर, या वरिष्ठ को अपने मूल व्यक्ति के संदर्भ में होना चाहिए। यह मुझे लगता है कि आपको एक स्व मान्यता तंत्र की आवश्यकता है जो व्यक्ति पर मान्यता को परिभाषित करता है न कि उसके किसी गुण पर। मुझे यकीन नहीं है, लेकिन मुझे नहीं लगता कि DataAnnotations इस बॉक्स से बाहर का समर्थन करता है। आप क्या कर सकते हैं जो अपना स्वयं का बना Attributeहै, ValidationAttributeजो कि वर्ग स्तर पर सजाया जा सकता है और अगले एक कस्टम सत्यापनकर्ता बना सकता है जो उन वर्ग-स्तरीय सत्यापनकर्ताओं को चलाने की अनुमति देता है।

मुझे पता है कि सत्यापन आवेदन ब्लॉक बॉक्स के स्व-सत्यापन का समर्थन करता है, लेकिन VAB में बहुत अधिक सीखने की अवस्था है। फिर भी, यहाँ VAB का उपयोग करके एक उदाहरण दिया गया है:

[HasSelfValidation]
public class Person
{
    public string Name { get; set; }
    public bool IsSenior { get; set; }
    public Senior Senior { get; set; }

    [SelfValidation]
    public void ValidateRange(ValidationResults results)
    {
        if (this.IsSenior && this.Senior != null && 
            string.IsNullOrEmpty(this.Senior.Description))
        {
            results.AddResult(new ValidationResult(
                "A senior description is required", 
                this, "", "", null));
        }
    }
}

"आपको व्यक्तिगत स्तर पर मान्य करने की आवश्यकता है, न कि वरिष्ठ स्तर पर" हाँ यह एक विकल्प है, लेकिन आप उस क्षमता को ढीला कर देते हैं जिसमें त्रुटि को विशेष क्षेत्र में जोड़ा जाता है, जो कि वरिष्ठ वस्तु में आवश्यक है।
पीटर स्टेनगनर

3

मुझे एक ही समस्या थी, [आवश्यक] विशेषता के एक संशोधन की आवश्यकता थी - HTTP अनुरोध की निर्भरता में आवश्यक फ़ील्ड बनाओ। समाधान डान हुनक्स उत्तर के समान था, लेकिन उनका समाधान सही तरीके से काम नहीं करता था (टिप्पणियां देखें)। मैं विनीत सत्यापन का उपयोग नहीं करता, बस MicrosoftMvcValidation.js बॉक्स से बाहर। यही पर है। अपने कस्टम विशेषता को लागू करें:

public class RequiredIfAttribute : RequiredAttribute
{

    public RequiredIfAttribute(/*You can put here pararmeters if You need, as seen in other answers of this topic*/)
    {

    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {

    //You can put your logic here   

        return ValidationResult.Success;//I don't need its server-side so it always valid on server but you can do what you need
    }


}

तब आपको अपने कस्टम प्रदाता को अपने Global.asax में एडॉप्टर के रूप में उपयोग करने के लिए इसे लागू करने की आवश्यकता होती है

public class RequreIfValidator : DataAnnotationsModelValidator <RequiredIfAttribute>
{

    ControllerContext ccontext;
    public RequreIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute)
       : base(metadata, context, attribute)
    {
        ccontext = context;// I need only http request
    }

//override it for custom client-side validation 
     public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
     {       
               //here you can customize it as you want
         ModelClientValidationRule rule = new ModelClientValidationRule()
         {
             ErrorMessage = ErrorMessage,
    //and here is what i need on client side - if you want to make field required on client side just make ValidationType "required"    
             ValidationType =(ccontext.HttpContext.Request["extOperation"] == "2") ? "required" : "none";
         };
         return new ModelClientValidationRule[] { rule };
      }
}

और एक लाइन के साथ अपने Global.asax को संशोधित करें

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute), typeof(RequreIfValidator));

और यहाँ यह है

[RequiredIf]
public string NomenclatureId { get; set; }

मेरे लिए मुख्य लाभ यह है कि मुझे कस्टम ग्राहक सत्यापनकर्ता के रूप में कोड नहीं करना पड़ता है क्योंकि विनीत सत्यापन के मामले में। यह सिर्फ [आवश्यक] के रूप में काम करता है, लेकिन केवल उन मामलों में जो आप चाहते हैं।


विस्तार के बारे में वह हिस्सा DataAnnotationsModelValidatorथा जो मुझे देखने की जरूरत थी। धन्यवाद।
19


0

मॉडल राज्य से त्रुटि को हटाने के लिए विशिष्ट उपयोग:

  1. नियंत्रक कार्रवाई का पहला हिस्सा सशर्त बनाएं
  2. ModelState से त्रुटि को दूर करने के लिए तर्क निष्पादित करें
  3. शेष मौजूदा तर्क (आमतौर पर मॉडल राज्य सत्यापन, फिर बाकी सब कुछ) करें

उदाहरण:

public ActionResult MyAction(MyViewModel vm)
{
    // perform conditional test
    // if true, then remove from ModelState (e.g. ModelState.Remove("MyKey")

    // Do typical model state validation, inside following if:
    //     if (!ModelState.IsValid)

    // Do rest of logic (e.g. fetching, saving

अपने उदाहरण में, सब कुछ वैसा ही रखें और अपने कंट्रोलर के एक्शन में सुझाए गए तर्क को जोड़ें। मैं मान रहा हूं कि आपके ViewModel को कंट्रोलर एक्शन में पास किया गया है जिसमें यूआई से डेटा और पर्सनल पर्सन ऑब्जेक्ट्स पॉप्युलेट किए गए हैं।


0

मैं MVC 5 का उपयोग कर रहा हूं, लेकिन आप कुछ इस तरह की कोशिश कर सकते हैं:

public DateTime JobStart { get; set; }

[AssertThat("StartDate >= JobStart", ErrorMessage = "Time Manager may not begin before job start date")]
[DisplayName("Start Date")]
[Required]
public DateTime? StartDate { get; set; }

आपके मामले में आप "IsSenior == true" जैसा कुछ कहेंगे। फिर आपको अपनी पोस्ट कार्रवाई पर सत्यापन की जांच करने की आवश्यकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.