2010-02-17 12 views
41

का उपयोग कर निर्भर गुणों का कस्टम मॉडल सत्यापन अब से मैंने अपने मॉडल वर्गों को सत्यापित करने के लिए उत्कृष्ट FluentValidation लाइब्रेरी का उपयोग किया है। वेब अनुप्रयोगों में मैं इसे क्लाइंट साइड सत्यापन करने के लिए jquery.validate प्लगइन के साथ संयोजन के रूप में भी उपयोग करता हूं। एक दोष यह है कि क्लाइंट पक्ष पर अधिकांश सत्यापन तर्क दोहराया जाता है और अब एक ही स्थान पर केंद्रीकृत नहीं किया जाता है।डेटा एनोटेशन

इसी कारण से मैं एक विकल्प तलाश रहा हूं। many उदाहरण हैं there मॉडल सत्यापन करने के लिए डेटा एनोटेशन का उपयोग दिखा रहा है। यह बहुत आशाजनक लग रहा है। एक चीज़ जो मुझे नहीं मिल सका वह एक संपत्ति को मान्य करने का तरीका है जो किसी अन्य संपत्ति मूल्य पर निर्भर करता है।

के उदाहरण के लिए निम्नलिखित मॉडल लेते हैं:

public class Event 
{ 
    [Required] 
    public DateTime? StartDate { get; set; } 
    [Required] 
    public DateTime? EndDate { get; set; } 
} 

मैं यह सुनिश्चित करें कि EndDateStartDate से अधिक है चाहते हैं। मैं कस्टम सत्यापन तर्क करने के लिए ValidationAttribute को विस्तारित सत्यापन विशेषता लिख ​​सकता हूं।

public class CustomValidationAttribute : ValidationAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     // value represents the property value on which this attribute is applied 
     // but how to obtain the object instance to which this property belongs? 
     return true; 
    } 
} 

मैंने पाया कि CustomValidationAttribute क्योंकि यह इस ValidationContext प्रॉपर्टी वाला है कि वस्तु उदाहरण सत्यापित किया जा रहा है काम करने के लिए लगता है: दुर्भाग्य से मैं एक तरह से मॉडल उदाहरण प्राप्त करने के लिए नहीं मिल सका। दुर्भाग्यवश यह विशेषता केवल .NET 4.0 में जोड़ दी गई है। तो मेरा सवाल है: क्या मैं .NET 3.5 SP1 में समान कार्यक्षमता प्राप्त कर सकता हूं?


अद्यतन:

ऐसा लगता है कि FluentValidation already supports clientside सत्यापन और ASP.NET MVC में मेटाडाटा 2.

फिर भी यह पता करने के लिए अच्छा होगा, हालांकि डेटा एनोटेशन निर्भर गुण मान्य करने के लिए इस्तेमाल किया जा सकता है, तो ।

+0

क्या आपने या किसी भी वर्ग/मॉडल पर डेटावोटेशन और फ़्लुएंट वैलिडेशन (सत्यापन के लिए) काम करने के लिए कोई तरीका निकाला है? यदि ऐसा है तो यह शानदार होगा, मेरे पास एफवी लेखक जेरेमी के साथ चर्चा करने के बारे में एक धागा है, आप यहां देख सकते हैं: http://fluentvalidation.codeplex.com/Thread/View.aspx?Tread_d=212371 –

उत्तर

28

एमवीसी 2 नमूना "PropertiesMustMatchAttribute" के साथ आता है जो दिखाता है कि आपके लिए डेटा एन्नोटेशन कैसे प्राप्त करें और इसे .NET 3.5 और .NET 4.0 दोनों में काम करना चाहिए।यही कारण है कि नमूना कोड इस तरह दिखता है:

[PropertiesMustMatch("NewPassword", "ConfirmPassword", ErrorMessage = "The new password and confirmation password do not match.")] 
public class ChangePasswordModel 
{ 
    public string NewPassword { get; set; } 
    public string ConfirmPassword { get; set; } 
} 

जब "अगर है:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] 
public sealed class PropertiesMustMatchAttribute : ValidationAttribute 
{ 
    private const string _defaultErrorMessage = "'{0}' and '{1}' do not match."; 

    private readonly object _typeId = new object(); 

    public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty) 
     : base(_defaultErrorMessage) 
    { 
     OriginalProperty = originalProperty; 
     ConfirmProperty = confirmProperty; 
    } 

    public string ConfirmProperty 
    { 
     get; 
     private set; 
    } 

    public string OriginalProperty 
    { 
     get; 
     private set; 
    } 

    public override object TypeId 
    { 
     get 
     { 
      return _typeId; 
     } 
    } 

    public override string FormatErrorMessage(string name) 
    { 
     return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString, 
      OriginalProperty, ConfirmProperty); 
    } 

    public override bool IsValid(object value) 
    { 
     PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value); 
     object originalValue = properties.Find(OriginalProperty, true /* ignoreCase */).GetValue(value); 
     object confirmValue = properties.Find(ConfirmProperty, true /* ignoreCase */).GetValue(value); 
     return Object.Equals(originalValue, confirmValue); 
    } 
} 

आप उस विशेषता का उपयोग करते हैं, बजाय यह अपने मॉडल वर्ग के एक संपत्ति पर डाल दिया, आप इसे वर्ग पर ही डाल "आपके कस्टम एट्रिब्यूट पर कॉल किया जाता है, पूरा मॉडल उदाहरण इसे पास कर दिया जाता है ताकि आप निर्भर संपत्ति मूल्यों को इस तरह से प्राप्त कर सकें। दिनांक तुलना विशेषता बनाने के लिए आप आसानी से इस पैटर्न का पालन कर सकते हैं, या यहां तक ​​कि एक सामान्य तुलना विशेषता भी।

Brad Wilson has a good example on his blog यह दर्शाता है कि प्रमाणीकरण के क्लाइंट-साइड भाग को कैसे जोड़ना है, हालांकि मुझे यकीन नहीं है कि यह उदाहरण .NET 3.5 और .NET 4.0 दोनों में काम करेगा या नहीं।

+2

मैंने कोशिश की है लेकिन मुझे अपने एएसपीएक्स पृष्ठों/विचारों पर प्रदर्शित करने के लिए सत्यापन त्रुटि कभी नहीं मिल सकती है। मैंने एक खाली स्ट्रिंग का उपयोग करने के लिए validationmessage को कॉल करने का प्रयास किया है, सत्यापन सत्यापन का उपयोग करने का भी प्रयास किया है और यह वहां प्रदर्शित नहीं हो रहा है (जैसा कि यह गुणों में उदाहरण देता है) –

+1

मैंने यह काम करने के लिए कुछ अच्छे घंटे बर्बाद कर दिए और सोच रहा था कि मेरा कोड गलत था, जब तक मुझे अंत में एहसास हुआ कि जब मैंने यह पोस्ट देखा तो मैं बस इसे ठीक से परीक्षण नहीं कर रहा था: http://stackoverflow.com/questions/3586324/custom-validation-attribute-is-not-called-asp-net-mvc (मूल रूप से क्षेत्र/संपत्ति-स्तरीय सत्यापन पहले आग लगती है, इसलिए आपको अपनी कक्षा-स्तर विशेषता isvalid() विधि को आग लगने से पहले पूरी तरह से सत्यापित करने की आवश्यकता है)। – jimasp

+0

बाद में मुझे क्षेत्र सत्यापन सत्यापन समस्या के बाद कक्षा सत्यापन पर एक बेहतर पोस्ट मिला: http://stackoverflow.com/questions/3099397/property-level- validation-errors-hinder-the- validation-of-class-level- validation – jimasp

3

क्योंकि .NET 3.5 के डेटा एन्नोटेशन के तरीकों से आप वास्तविक ऑब्जेक्ट को मान्य या सत्यापन संदर्भ प्रदान करने की अनुमति नहीं देते हैं, आपको इसे पूरा करने के लिए थोड़ा सा काम करना होगा। मुझे स्वीकार करना होगा कि मैं एएसपी.नेट एमवीसी से परिचित नहीं हूं, इसलिए मैं यह नहीं कह सकता कि एमसीवी के साथ वास्तव में इसे कैसे किया जाए, लेकिन आप तर्क को पारित करने के लिए थ्रेड-स्टेटिक वैल्यू का उपयोग करने का प्रयास कर सकते हैं। यहां कुछ ऐसा उदाहरण है जो काम कर सकता है।

पहले 'वस्तु विषय-क्षेत्र' आप कॉल स्टैक के माध्यम से उन्हें पारित करने के लिए बिना चारों ओर की वस्तुओं पारित करने के लिए अनुमति देता है कि किसी प्रकार का बनाने के लिए:

public sealed class ContextScope : IDisposable 
{ 
    [ThreadStatic] 
    private static object currentContext; 

    public ContextScope(object context) 
    { 
     currentContext = context; 
    } 

    public static object CurrentContext 
    { 
     get { return context; } 
    } 

    public void Dispose() 
    { 
     currentContext = null; 
    } 
} 

इसके बाद, ContextScope उपयोग करने के लिए अपने सत्यापनकर्ता बनाएँ:

public class CustomValidationAttribute : ValidationAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     Event e = (Event)ObjectContext.CurrentContext; 

     // validate event here. 
    } 
} 

और अंत में कम से कम, यह सुनिश्चित करें कि वस्तु ContextScope के माध्यम से चारों ओर अतीत है:

Event eventToValidate = [....]; 
using (var scope new ContextScope(eventToValidate)) 
{ 
    DataAnnotations.Validator.Validate(eventToValidate); 
} 

क्या यह उपयोगी है?

+0

स्टीवन, यह अच्छा लग रहा है। एकमात्र चीज जिसे मैं संशोधित करता हूं, वर्तमान संदर्भ को 'थ्रेडस्टैटिक' का उपयोग करने के बजाय HttpContext में संग्रहीत करना है। मैं बस एएसपी.नेट आवेदन में इससे बचूंगा। –

+0

क्या आप समझा सकते हैं कि आप क्यों मानते हैं कि हमें एएसपी.NET एप्लिकेशन में इससे बचना चाहिए।मैं अपने निर्माण अनुप्रयोगों में इस निर्माण का उपयोग करता हूं, इसलिए मुझे बहुत दिलचस्पी है कि यह क्यों बुरा है। – Steven

+4

इंटरनेट पर कई लेख हैं क्यों यह बुरा है। यहां एक है: http://www.hanselman.com/blog/ATaleOfTwoTechniquesTheThreadStaticAttributeAndSystemWebHttpContextCurrentItems.aspx थ्रेडस्टैटिक के साथ समस्या यह है कि एएसपी.नेट में आपके पास थ्रेड लाइफ पर नियंत्रण नहीं है और धागे का पुन: उपयोग किया जाता है, ऐसे परिस्थितियां हैं जहां चर संशोधित हो जाओ। यदि आप एसिंक्रोनस पेज और कंट्रोलर का उपयोग करते हैं तो चीजें भी उलझन में आती हैं। उदाहरण के लिए एक थ्रेड पर एक अनुरोध शुरू हो सकता है और एक अलग धागे पर खत्म हो सकता है। तो ASP.NET में ** ** ** ** सही सच्चाई अनुरोध करने का तरीका केवल HttpContext है। –

14

मैं यह बहुत ही समस्या थी और हाल ही में खुला मेरी समाधान sourced: http://foolproof.codeplex.com/

उदाहरण के लिए सीधा समाधान ऊपर होगा:

public class Event 
{ 
    [Required] 
    public DateTime? StartDate { get; set; } 

    [Required] 
    [GreaterThan("StartDate")] 
    public DateTime? EndDate { get; set; } 
} 
+0

मुझे लगता है कि ग्रेटरथान दिनांक सत्यापन केवल यूएस प्रारूप तिथियों के साथ काम करता है – GraemeMiller

7
PropertiesMustMatch CompareAttribute के बजाय

कि MVC3 में इस्तेमाल किया जा सकता ।

public class RegisterModel 
{ 
    // skipped 

    [Required] 
    [ValidatePasswordLength] 
    [DataType(DataType.Password)] 
    [Display(Name = "Password")] 
    public string Password { get; set; }      

    [DataType(DataType.Password)] 
    [Display(Name = "Confirm password")] 
    [Compare("Password", ErrorMessage = "The password and confirmation do not match.")] 
    public string ConfirmPassword { get; set; } 
} 

CompareAttribute एक नया, बहुत उपयोगी सत्यापनकर्ता कि System.ComponentModel.DataAnnotations की वास्तव में हिस्सा है, नहीं है, लेकिन System.Web में जोड़ दिया गया है: इस लिंक http://devtrends.co.uk/blog/the-complete-guide-to-validation-in-asp.net-mvc-3-part-1 के अनुसार टीम द्वारा एमवीसी डीएलएल। जबकि विशेष रूप से अच्छी तरह से नाम नहीं (केवल तुलना बनाता समानता के लिए जाँच करने के लिए है, तो शायद EqualTo और अधिक स्पष्ट होता है), यह से उपयोग देखना आसान है कि इस सत्यापनकर्ता चेकों है कि एक संपत्ति के मूल्य के बराबर अन्य संपत्ति का मूल्य। आप कोड से देख सकते हैं कि विशेषता एक स्ट्रिंग प्रॉपर्टी लेता है जो की अन्य संपत्ति का नाम है जो आप तुलना कर रहे हैं। इस प्रकार के सत्यापनकर्ता का क्लासिक उपयोग वह है जिसे हम यहां उपयोग कर रहे हैं: पासवर्ड पुष्टिकरण।

3

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

[Required] 
public DateTime? StartDate { get; set; }  
[Required] 
[AssertThat("StartDate != null && EndDate > StartDate")] 
public DateTime? EndDate { get; set; } 

यह सर्वर के साथ-साथ क्लाइंट पक्ष के लिए भी काम करता है। अधिक जानकारी can be found here

+0

आपको बहुत धन्यवाद, यह पुस्तकालय अधिकांश चीज़ों के लिए बहुत उपयोगी है। – Enzero

संबंधित मुद्दे