2013-01-11 16 views
14

मेरे पास एक बड़ा मॉडल है (बड़ा मेरा मतलब है कि मॉडल वर्ग में बहुत से फ़ील्ड/गुण हैं और प्रत्येक में कम से कम एक सत्यापन विशेषता है (जैसे Required, MaxLength, MinLength आदि))। डेटा के साथ मॉडल भरने के लिए उपयोगकर्ता के लिए बहुत सारे इनपुट के साथ एक दृश्य बनाने के बजाय मैं कई विचार बनाना चाहता हूं जहां उपयोगकर्ता मॉडल फ़ील्ड का हिस्सा भर देगा और अगले चरण पर जाएंगे (किसी प्रकार का "विज़ार्ड")। चरणों के बीच पुनर्निर्देशन करते समय मैं Session में पूर्ण वस्तु मॉडल ऑब्जेक्ट नहीं स्टोर करता हूं। कुछ नीचे की तरह:एएसपी .NET एमवीसी में मॉडल के केवल एक हिस्से को कैसे सत्यापित करें?

मॉडल:

public class ModelClass 
{ 
    [MaxLength(100)] ... 
    public string Prop1{get;set;} 
    [MaxLength(100)] ... 
    public string Prop2{get;set;} 
    ... 
    [Required][MaxLength(100)] ... 
    public string Prop20{get;set;} 
} 

नियंत्रक:

[HttpPost] 
public ActionResult Step1(ModelClass postedModel) 
{  
    // user posts only for example Prop1 and Prop2 
    // so while submit I have completly emty model object 
    // but with filled Prop1 and Prop2 
    // I pass those two values to Session["model"] 
    var originalModel = Session["model"] as ModelClass ?? new ModelClass(); 
    originalModel.Prop1 = postedModel.Prop1; 
    originalModel.Prop2 = postedModel.Prop2; 
    Session["model"] = originalModel; 

    // and return next step view 
    return View("Step2"); 
} 

[HttpPost] 
public ActionResult Step2(ModelClass postedModel) 
{ 
    // Analogically the same 
    // I have posted only Prop3 and Prop4 

    var originalModel = Session["model"] as ModelClass; 
    if (originalModel!=null) 
    { 
     originalModel.Prop3 = postedModel.Prop3; 
     originalModel.Prop4 = postedModel.Prop4; 
     Session["model"] = originalModel; 

     // return next step view 
     return View("Step3"); 
    } 
    return View("SomeErrorViewIfSessionBrokesSomeHow") 
} 

Step1 दृश्य केवल Prop1 और Prop2 के लिए आदानों है, चरण 2 दृश्य शामिल Prop3 और Prop4 आदि

के लिए आदानों लेकिन यहां बात है

जब उपयोगकर्ता चालू है, उदाहरण के लिए, चरण 1, और 100 से अधिक अक्षरों की लंबाई के साथ Prop1 भरता है तो क्लाइंट साइड सत्यापन ठीक काम करता है। लेकिन, ज़ाहिर है, मुझे इस मान को और सर्वर पक्ष पर नियंत्रक में मान्य करना होगा। अगर मेरे पास पूरा मॉडल था तो मैं बस निम्नलिखित करता हूं:

if(!ModelState.IsValid) return View("the same view with the same model object"); 

इसलिए उपयोगकर्ता को फ़ॉर्म को फिर से भरना और सही करना है। लेकिन चरण 1 उपयोगकर्ता पर ने 20 के केवल 2 गुण भर दिए हैं, और मुझे उन्हें सत्यापित करने की आवश्यकता है। मैं ModelState.IsValid का उपयोग नहीं कर सकता क्योंकि मॉडल स्थिति अमान्य होगी। जैसा कि आप देख सकते हैं Prop20[Required] विशेषता के साथ चिह्नित है, जब उपयोगकर्ता Prop1 और Prop2, Prop20 सबमिट करता है और इसलिए ModelState अमान्य है। निस्संदेह मैं उपयोगकर्ता को चरण 2 पर जाने की अनुमति दे सकता हूं, सभी चरणों को भर सकता हूं और केवल अंतिम चरण पर मॉडल स्थिति को मान्य कर सकता हूं, लेकिन यदि मैं चरण 1 गलत भरता हूं तो मैं उपयोगकर्ता को चरण 2 पर जाने की अनुमति नहीं देना चाहता। और मैं नियंत्रक में यह सत्यापन चाहता हूँ। तो सवाल यह है: मैं मॉडल के केवल एक हिस्से को कैसे सत्यापित कर सकता हूं? मैं कैसे सत्यापित कर सकता हूं कि केवल कुछ मॉडल गुण उनके सत्यापन गुणों से मेल खाते हैं?

+8

आप प्रत्येक चरण के लिए एक अलग दृश्य मॉडल बना सकते हैं जो एक अलग दृश्य हो सकता है। ProductStep1ViewModel और ProductStep1View की तरह, लेकिन मैं उन्हें उससे बेहतर नाम दूंगा। –

+0

@ निकब्रे, मॉडल क्लास मूल मॉडल से मैप किए गए मॉडल क्लास को देखता है, इसलिए यदि मैं मॉडलक्लास को अन्य विशेष चरण वर्गों की संरचना के रूप में बना देता हूं तो मुझे उन मॉडल वर्गों को मैप करने के लिए मैपर के लिए लगभग 40 मैपिंग नियम जोड़ना होगा, और यह एक गुच्छा होगा कोड का मैंने पहले ही इसके बारे में सोचा है, लेकिन सलाह के लिए धन्यवाद। – Dmytro

+0

@DmytroTsiniavsky आप मैपिंग नियमों को स्पष्ट रूप से सेट अप करने से बचने के लिए [वैल्यू इंजेक्टर] (http://valueinjecter.codeplex.com/) जैसे कुछ उपयोग कर सकते हैं। – Mun

उत्तर

14

एक संभव समाधान:

  1. उपयोग ModelState।IsValidField (स्ट्रिंग कुंजी);

    if (ModelState.IsValidField("Name") && ModelState.IsValidField("Address")) 
    { ... } 
    

फिर अंत में जब सब कुछ किया जाता है उपयोग:

if(ModelState.IsValid) { .. } 
+0

यदि आप एक गैर-उत्पादक स्ट्रिंग भरते हैं तो यह हमेशा वापस आ जाएगा, सुनिश्चित करें कि आप इसे सही टाइप करते हैं। –

9

मुझे लगता है कि सबसे सुंदर तरीका है कि जैसे यह करने के लिए है:

List<string> PropertyNames = new List<string>() 
{ 
    "Prop1", 
    "Prop2" 
}; 

if (PropertyNames.Any(p => !ModelState.IsValidField(p))) 
{ 
    // Error 
} 
else 
{ 
    // Everything is okay 
} 

या :

List<string> PropertyNames = new List<string>() 
{ 
    "Prop1", 
    "Prop2" 
}; 

if (PropertyNames.All(p => ModelState.IsValidField(p))) 
{ 
    // Everything is okay 
} 
else 
{ 
    // Error 
} 
2

बस इसके लिए मौजूदा उत्तरों में जोड़ने के लिए। बल्कि संपत्ति के नाम हार्डकोड की तुलना में मैं एक विशेषता का प्रयोग करेंगे आपके सत्यापन के बाकी के साथ जोड़े जाने के लिए की तर्ज पर जिम्मेदार बताते हैं:

public class ValidationStageAttribute : Attribute 
{ 
    public StageNumber { get; private set; } 
    public ValidationStageAttribute(int stageNumber) 
    { 
     StageNumber = stageNumber 
    } 
} 

अब जब हम स्वयं मॉडल को आंशिक के ज्ञान के बिना संपत्ति के नाम प्राप्त कर सकते हैं सत्यापन को एक विधि में खींचा जा सकता है (यदि आप इसे बहुत उपयोग करते हैं, तो आपका बेस कंट्रोलर एक अच्छी जगह होगी)।

protected bool ValidateStage(object model, int stageToValidate) 
{ 
    var propertiesForStage = postedModel.GetType() 
     .GetProperties() 
     .Where(prop => prop.GetCustomAttributes(false).OfType<ValidationStageAttribute>().Where(attr => attr.StageNumber == stageToValidate)); 
     .Select(prop => prop.Name); 

    return propertiesForStage.All(p => ModelStage.IsValidField(p)); 
} 

अब सभी आप अपनी पोस्ट कार्रवाई में क्या करने की जरूरत होगी MVC कोर में ValidateStage(postedModel, 1)

2

कॉल करने के लिए हो सकता है, इस के बराबर हो जाएगा:

if (ModelState.GetFieldValidationState("Name") == Microsoft.AspNetCore.Mvc.ModelBinding.ModelValidationState.Valid) 
{ 
    // do something 
} 

हालांकि, मैं करूंगा इस उदाहरण में बस एक अलग दृश्य मॉडल बनाने की अनुशंसा करें।

आपका आंशिक दृश्य मॉडल आपके बड़े दृश्य मॉडल द्वारा विरासत में प्राप्त किया जा सकता है, इसलिए आपको कोड (DRY प्रिंसिपल) में खुद को दोहराना नहीं होगा।

संपत्ति नामों को कड़ी-कोडिंग से बचने के लिए बेहतर है!