2015-06-17 5 views
5

मेरे दृश्य मॉडल में कुछ गुण हैं जो सहेजते समय वैकल्पिक होते हैं, लेकिन सबमिट करते समय आवश्यक होते हैं। एक शब्द में, हम आंशिक बचत की अनुमति देते हैं, लेकिन पूरा फॉर्म सबमिट किया जाता है, हम यह सुनिश्चित करना चाहते हैं कि सभी आवश्यक फ़ील्ड में मूल्य हों।कुछ डेटा एनोटेशन विशेषता को चुनिंदा रूप से कैसे सत्यापित करें?

केवल दृष्टिकोण इस पल में मैं के बारे में सोच सकते हैं:

ModelState त्रुटियों संग्रह में हेरफेर।

दृश्य मॉडल में सभी [Required] विशेषताएँ हैं। अगर अनुरोध आंशिक रूप से सहेजता है, तो नियंत्रक कार्रवाई में प्रवेश करते समय ModelState.IsValidfalse बन जाता है। फिर मैं सभी ModelState (जो ICollection<KeyValuePair<string, ModelState>> है) त्रुटियों के माध्यम से चलाता है और [Required] गुणों द्वारा उठाई गई सभी त्रुटियों को हटा देता है।

लेकिन अगर अनुरोध पूरा फॉर्म जमा करना है, तो मैं ModelState में हस्तक्षेप नहीं करूंगा और [Required] गुण प्रभावी होंगे। बचाने के लिए और प्रस्तुत

यह एक और भी अधिक बदसूरत है आंशिक के लिए

उपयोग अलग दृष्टिकोण मॉडल। एक दृश्य मॉडल में सभी [Required] विशेषताएँ शामिल होंगी, जो सबमिट करने के लिए एक क्रिया विधि द्वारा उपयोग की जाती हैं। लेकिन आंशिक रूप से सहेजने के लिए, मैं फॉर्म डेटा को एक अलग क्रिया में पोस्ट करता हूं जो सभी [Required] विशेषताओं के बिना एक समान दृश्य मॉडल का उपयोग करता है।

जाहिर है, मैं बहुत सारे डुप्लिकेट कोड/दृश्य मॉडल के साथ समाप्त होगा।

आदर्श समाधान

मैं सोच कर दिया गया है, तो मैं उन आवश्यक गुण के लिए एक कस्टम डेटा एनोटेशन विशेषता [SubmitRequired] बना सकते हैं। और किसी भी तरह से आधिकारिक बचत करते समय सत्यापन को अनदेखा कर दिया जाता है लेकिन जमा करते समय नहीं।

अभी भी एक स्पष्ट सुराग नहीं हो सका। कोई भी मदद कर सकता है? धन्यवाद।

+3

आप एक [मूर्खतापूर्ण] (http://foolproof.codeplex.com/) '[RequiredIfTrue]' या इसी तरह की विशेषता का उपयोग कर सकते हैं (आपके दृश्य मॉडल में अतिरिक्त 'बूल सबमिट की गई' संपत्ति के आधार पर। 'false' है तो' [RequiredIfTrue "SubmitRequired"] 'से सजाए गए गुणों पर कोई सत्यापन नहीं किया जाएगा, अन्यथा गुण मान्य किए जाएंगे। –

+0

धन्यवाद, स्टीफन। यह पैकेज 2012 में अंतिम अपडेट के साथ बीटा है। लेकिन यह 'आवश्यक' ने सही दिशा को इंगित किया। वास्तव में सराहना करें। – Blaise

+0

मुझे उस कोड से लिंक संलग्न करने दें जो मैं उपयोग करूंगा: http://foolproof.codeplex.com/SourceControl/latest#Foolproof/RequiredIf.cs – Blaise

उत्तर

0

मेरे दृष्टिकोण सशर्त जाँच एनोटेशन विशेषता है, जो foolproof से सीखा है जोड़ना है।

व्यू मॉडल के SaveMode भाग बनाएं।

गुणों को शून्य से चिह्नित करें ताकि SaveModeFinalize पर वैकल्पिक मान वैकल्पिक हों।

लेकिन एक कस्टम एनोटेशन विशेषता [FinalizeRequired] जोड़ें:

[AttributeUsage(AttributeTargets.Property)] 
public abstract class FinalizeValidationAttribute : ValidationAttribute 
{ 
    public const string DependentProperty = "SaveMode"; 

    protected abstract bool IsNotNull(object value); 

    protected static SaveModeEnum GetSaveMode(ValidationContext validationContext) 
    { 
     var saveModeProperty = validationContext.ObjectType.GetProperty(DependentProperty); 

     if (saveModeProperty == null) return SaveModeEnum.Save; 

     return (SaveModeEnum) saveModeProperty.GetValue(validationContext.ObjectInstance); 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     var saveMode = GetSaveMode(validationContext); 

     if (saveMode != SaveModeEnum.SaveFinalize) return ValidationResult.Success; 

     return (IsNotNull(value)) 
      ? ValidationResult.Success 
      : new ValidationResult(string.Format("{0} is required when finalizing", validationContext.DisplayName)); 
    } 
} 

आदिम डेटा प्रकार के लिए, जाँच value!=null:

[AttributeUsage(AttributeTargets.Property)] 
public class FinalizeRequiredAttribute : FinalizeValidationAttribute 
{ 
    protected override bool IsNotNull(object value) 
    { 
     return value != null; 
    } 
} 

लिए

[FinalizeRequired] 
public int? SomeProperty { get; set; } 

[FinalizeRequiredCollection] 
public List<Item> Items { get; set; } 

यहाँ गुण के लिए कोड है IEnumerable संग्रह,

[AttributeUsage(AttributeTargets.Property)] 
public class FinalizeRequiredCollectionAttribute : FinalizeValidationAttribute 
{ 
    protected override bool IsNotNull(object value) 
    { 
     var enumerable = value as IEnumerable; 
     return (enumerable != null && enumerable.GetEnumerator().MoveNext()); 
    } 
} 

यह दृष्टिकोण नियंत्रक से सत्यापन तर्क को हटाकर चिंताओं को अलग करने से सर्वोत्तम रूप से प्राप्त होता है। डेटा एनोटेशन विशेषताओं को उस तरह के काम को संभालना चाहिए, जो नियंत्रक को केवल !ModelState.IsValid की जांच की आवश्यकता है। यह मेरे आवेदन में विशेष रूप से उपयोगी है, क्योंकि यदि ModelState प्रत्येक नियंत्रक में चेक अलग है तो मैं आधार नियंत्रक में पुन: सक्रिय नहीं कर पाऊंगा।

1

मुझे लगता है कि आपकी समस्या के लिए और अधिक सटीक समाधान है। आइए कहें कि आप एक विधि को सबमिट कर रहे हैं, मेरा मतलब है कि आप आंशिक और पूर्ण सबमिट के लिए एक ही विधि को कॉल कर रहे हैं। तो आपको नीचे की तरह करना चाहिए:

 [HttpPost] 
     [ValidateAntiForgeryToken] 
     public ActionResult YourMethod(ModelName model) 
     { 
      if(partialSave) // Check here whether it's a partial or full submit 
      { 
      ModelState.Remove("PropertyName"); 
      ModelState.Remove("PropertyName2"); 
      ModelState.Remove("PropertyName3"); 
      } 

      if (ModelState.IsValid) 
      { 
      } 
     } 

यह आपकी समस्या का समाधान करना चाहिए। अगर आपको किसी परेशानी का सामना करना पड़ता है तो मुझे बताएं।

संपादित करें:

@SBirthare के रूप में है कि जोड़ने के लिए या जब मॉडल अपडेट कर दिया गुण दूर करने के लिए अपनी संभव नहीं टिप्पणी की, मैं समाधान जो [Required] विशेषता के लिए काम करना चाहिए के नीचे पाया।

ModelState.Where(x => x.Value.Errors.Count > 0).Select(d => d.Key).ToList().ForEach(g => ModelState.Remove(g)); 

उपरोक्त कोड सभी कुंजी प्राप्त करेगा जो त्रुटि होगी और उन्हें मॉडल स्थिति से हटा देंगी। अगर आपको यह सुनिश्चित करने के लिए आंशिक रूप से प्रस्तुत किया जाता है तो आपको इस पंक्ति को अंदर रखना होगा। मैंने यह भी जांच लिया है कि त्रुटि [Required] केवल विशेषता के लिए आएगी (किसी भी तरह मॉडल बाइंडर इस विशेषता को उच्च प्राथमिकता दे रही है, भले ही आप इसे किसी अन्य विशेषता के बाद/नीचे रखें)। इसलिए आपको मॉडल अपडेट के बारे में चिंता करने की आवश्यकता नहीं है।

+0

यह वास्तव में पहला समाधान है जिसे मैंने प्रस्तावित किया - नियंत्रक कार्रवाई में 'मॉडलस्टेट' में हेरफेर करना। लेकिन इनपुट के लिए धन्यवाद। – Blaise

+0

आपका प्रस्तावित समाधान लागत प्रभावी नहीं है प्रिय। आपने सभी संपत्तियों के माध्यम से लूप करने का प्रस्ताव रखा है। जबकि मैं उन लोगों को हटाने का प्रस्ताव कर रहा हूं जो आवश्यक हैं लेकिन आंशिक पद के समय नहीं। –

+1

हालांकि यह एक साधारण समाधान हो सकता है और जब आपके पास कुछ गुण होते हैं तो मामलों में अच्छी तरह से काम करते हैं, यह सुरुचिपूर्ण नहीं है। कोई अपराध नहीं। यह सिर्फ एक के लिए ओसीपी तोड़ता है यानी मॉडल में जोड़ा गया एक नई संपत्ति, आपको यहां आना होगा और सूची में जोड़ना होगा। – SBirthare

2

यह एक दृष्टिकोण है जिसे मैं परियोजनाओं में उपयोग करता हूं।

ValidationService<T> बनाएं जो व्यवसाय तर्क युक्त है जो जांच करेगा कि आपका मॉडल IsValidForSubmission विधि के साथ सबमिट करने के लिए एक वैध स्थिति में है।

संपत्ति को उस दृश्य मॉडल में जोड़ें जिसे आप IsValidForSubmission विधि पर कॉल करने से पहले जांचते हैं। क्षेत्र लंबाई आदि यानी

केवल मान्यता में बनाया का उपयोग अमान्य डेटा के लिए जाँच के लिए जिम्मेदार बताते हैं

बनाएं कुछ कस्टम एक अलग नाम स्थान में विशेषताएं है कि कुछ निश्चित परिस्थितियों में मान्य होगा यानी [RequiredIfSubmitting] और फिर दोहराने में अपनी सेवा के भीतर प्रतिबिंब का उपयोग प्रत्येक प्रॉपर्टी पर विशेषताओं पर और IsValid विधि मैन्युअल रूप से कॉल करें (किसी भी को छोड़कर जो आपके नामस्थान में नहीं है)।

यह पॉप्युलेट और एक Dictionary<string, string> जो ModelState वापस यूआई को पॉप्युलेट करने के लिए इस्तेमाल किया जा सकता वापस आ जाएगी:

var validationErrors = _validationService.IsValidForSubmission(model); 

if (validationErrors.Count > 0) 
{ 
    foreach (var error in validationErrors) 
    { 
     ModelState.AddModelError(error.Key, error.Value); 
    } 
} 
संबंधित मुद्दे