2012-04-11 10 views
9

मैंने एसओ पर यहां बहुत सारे शोध किए हैं, और मुझे स्पष्ट दिशा नहीं मिल रही है। मेरे पास वर्तमान में एक एएसपी.नेट एमवीसी 3 एप्लीकेशन है, एक सेवा परत के साथ जो एक भंडार के शीर्ष पर बैठता है।मैं सेवा परत सत्यापन संदेशों को कॉलर पर वापस कैसे पास कर सकता हूं?

public class MyService{ 

    public void CreateDebitRequest(int userId, int cardId, decimal Amount, ....) 
    { 
    //perform some sort of validation on parameters, save to database 
    } 

    public void CreateCreditRequest(.....) 
    } 
     //perform some sort of validation on parameters, save to database 
    } 

    public void CreateBatchFile() 
    { 
     //construct a file using a semi-complex process which could fail 
     //write the file to the server, which could fail 
    } 


    public PaymentTransaction ChargePaymentCard(int paymentCardId, decimal amount) 
    { 
     //validate customer is eligible for amount, call 3rd party payments api call, 
     //...save to database, other potential failures, etc. 
    } 

} 

मैंने देखा है लोगों का कहना है कि पैरामीटर मान्यता बहुत असाधारण नहीं है, और इसलिए एक अपवाद फेंकने बहुत फिटिंग नहीं है:

मेरी सेवा परत में, मैं इस तरह के रूप में कार्य करता है। मुझे एक स्ट्रिंग जैसे आउट पैरामीटर में गुजरने के विचार से भी प्यार नहीं है, और एक खाली मूल्य की जांच कर रहा है। मैंने एक वैलिडेशन डिक्शनरी क्लास को कार्यान्वित करने पर विचार किया है, और इसे किसी दिए गए सेवा वर्ग की संपत्ति बना रहा है (इसमें एक इस्वाइड बूलियन होगा, और त्रुटि संदेशों की एक सूची होगी, और यह देखने के लिए सेवा परत में दिए गए फ़ंक्शन कॉल के बाद चेक किया जा सकता है चीजें चली गईं)। मैं किसी भी समारोह चलाने के बाद ValidationDictionary स्थिति की जांच कर सकते हैं:

var svc = new MyService(); 
svc.CreateBatchFile(); 
if (svc.ValidationDictionary.IsValid) 
    //proceed 
else 
    //display values from svc.ValidationDictionary.Messages... 

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

क्या आपके पास कोई सिफारिश है? मुझे ऐसा करने का कोई साफ तरीका नहीं दिख रहा है। कभी-कभी फ़ंक्शन के लिए शून्य लौटने पर पर्याप्त जानकारी होती है, लेकिन कभी-कभी मैं कॉलर को वापस एक और अधिक सत्यापन जानकारी वापस लेना चाहता हूं। किसी भी सलाह की सराहना की जाएगी!

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

उत्तर

1

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

1

दृश्य और नियंत्रक क्रिया विधियों के बीच पारित व्यूमोडेल ऑब्जेक्ट्स का उपयोग करें। ViewModel ऑब्जेक्ट्स Validate(ValidationDictionary validationDictionary) विधि द्वारा प्रमाणीकरण को संभाल सकता है।

नियंत्रक को सेवा परत में किसी भी विधि को कॉल करने से पहले ViewModel ऑब्जेक्ट पर मान्य विधि को कॉल करना होगा। यह केवल http POST क्रियाओं के लिए आवश्यक होना चाहिए।

आपके विचारों को तब सत्यापन संदेश प्रदर्शित करना होगा।

इस समाधान के लिए यह आवश्यक है कि व्यूमोडेल ऑब्जेक्ट्स नियंत्रक कार्रवाई और दृश्य के बीच पारित हो जाएं, लेकिन आजकल ज्यादातर एमवीसी में मॉडलबिंडर द्वारा संभाला जाता है।

[HttpPost] 
public ActionResult Foo(BarViewModel viewModel) 
{ 
    viewModel.Validate(ValidationDictionary); 

    if (!ModelState.IsValid) 
    { 
     return View(viewModel); 
    } 

    // Calls to servicelayer 
} 

आपका अपने ViewModel में मान्य विधि इस तरह दिखेगा:

आपका नियंत्रक (http पोस्ट) कार्यों कुछ इस तरह दिखेगा

public void Validate(ValidationDictionary validationDictionary) 
{ 
    if (SomeProperty.Length > 30) 
    { 
     validationDictionary.AddError("SomeProperty", "Max length is 30 chars"); 
    } 
} 
+0

हमम ... मुझे लगता है कि मैं निचले स्तर के बारे में बात कर रहा हूं। हम मान लेंगे कि उपयोगकर्ता ने एक बटन दबाया है, और व्यूमोडेल सत्यापन बिना छेड़छाड़ के चला गया है। मेरा नियंत्रक तब सेवा परत के भीतर एक फ़ंक्शन कॉल करेगा, और यह फ़ंक्शन कई कारणों से विफल हो सकता है (या शायद दृश्यमान सत्यापन वास्तव में आवश्यक सेवा की तुलना में अधिक उदार था, इसलिए जब सेवा स्वयं के लिए पैराम को मान्य करती है, तो यह विफल हो जाती है) । मैं इस जानकारी को सेवा परत से नियंत्रक तक वापस कैसे पास करूंगा, यहां तक ​​कि उस बिंदु तक पहुंचने के लिए जहां मैं व्यूमोडेल या मॉडलस्टेट के साथ प्रदर्शित कर सकता हूं? – Josh

+1

मैं सुनिश्चित करता हूं कि सभी सत्यापन तर्क व्यूमोडेल में मौजूद हैं। आप सभी जगह पर सत्यापन तर्क क्यों फैलाना चाहते हैं? इनपुट सत्यापन उपयोगकर्ता इंटरफ़ेस मॉड्यूल में आता है। अगर सेवा परत में कुछ गड़बड़ है तो आपको बेहतर त्रुटि संदेशों के साथ लॉगिंग प्रदान करने के लिए अपवाद फेंकना चाहिए। आपका एमवीसी एप्लीकेशन अपवाद/http कोड के आधार पर दोस्ताना त्रुटि पृष्ठों पर रीडायरेक्ट कर सकता है। – Marcus

+0

मान लें कि मैं सेवा परत में हूं, और यह सत्यापित करता हूं कि CreateDebitRequest (...) में पारित दिनांक भविष्य में तीन दिनों से अधिक नहीं है। ऐसा लगता है कि मुझे सेवा परत में इसे यहां सत्यापित करना चाहिए, इसके अलावा जहां भी मैंने इसे श्रृंखला में उच्चतर मान्य किया है। क्या आप उस के साथ सहमत करेंगें? यदि ऐसा है, तो क्या आपको लगता है कि मुझे वास्तव में मेरी सेवा परत में सत्यापन करना चाहिए, लेकिन सत्यापन विफल होने पर केवल अपवाद फेंकना चाहिए? या मुझे इस सेवा को मेरी सेवा परत में बिल्कुल मान्य नहीं करना चाहिए (मैं सेवा उपभोक्ता पर भरोसा करने के बारे में परेशान होगा)? धन्यवाद ... – Josh

9

यह मैं क्या कर रहा है। अपने सत्यापन के लिए एक कक्षा है, और पैरामीटर पास करने के बजाय एक दृश्य मॉडल पास करें। तो इस तरह से अपने मामले कुछ है, जहां ValidationResult बस एक साधारण वर्ग डब्ल्यू/MemberName और त्रुटिसंदेश गुण है में:

public class DebitRequestValidator{ 

    public IEnumerable<ValidationResult> Validate(DebitRequestModel model){ 

    //do some validation 
    yield return new ValidationResult { 
     MemberName = "cardId", 
     ErrorMessage = "Invalid CardId." 
    } 
    } 

}

फिर मॉडल राज्य के लिए इन मान्यता परिणाम कॉपी करने के लिए एक नियंत्रक विस्तार विधि पैदा करते हैं।

public static class ControllerExtensions 
{ 
    public static void AddModelErrors(this ModelStateDictionary modelState, IEnumerable<ValidationResult> validationResults) 
    { 
     if (validationResults == null) return; 

     foreach (var validationResult in validationResults) 
     { 
      modelState.AddModelError(validationResult.MemberName, validationResult.ErrorMessage); 
     } 
    } 
} 

फिर अपने नियंत्रक में फिर अपने ध्यान में रखते हुए आप सामान्य की तरह त्रुटियों को प्रदर्शित कर सकते

[HttpPost] 
public ActionResult DebitRequest(DebitRequestModel model) { 
    var validator = new DebitRequestValidator(); 
    var results = validator.Validate(model); 
    ModelState.AddModelErrors(results); 
    if (!ModelState.IsValid) 
    return View(model) 

    //else do other stuff here 
} 

की तरह कुछ है।

@Html.ValidationMessageFor(m => m.CardId) 
+0

मेरी सेवा परत को पता नहीं है कि यह एक एमवीसी एप्लीकेशन है जो इसका उपभोग कर रहा है। इसमें केवल कुछ सार्वजनिक फ़ंक्शन हैं जैसे CreateBatchFile या AddDebitRequest। कभी-कभी नल लौटने से नियंत्रक के लिए यह पता चल जाता है कि क्या हुआ, और कभी-कभी नियंत्रक सेवा परत से कुछ और जानकारी ले सकता है (शायद मॉडलस्टेट और व्हाट्नॉट के साथ पास करने के लिए)। मैं सेवा परत से इसे कैसे बबल कर सकता हूं? – Josh

+0

@ जोश - इस उदाहरण में सेवा परत पर एमवीसी पर निर्भरता नहीं है, केवल वैलिडेशन रिसेट क्लास, जो कि मैंने बनाई गई एक नियमित कक्षा है। आप मॉडलस्टेट में गुजरकर वही काम कर सकते हैं, लेकिन मुझे लगता है कि एक आईनेमरेबल <सत्यापनकरण> वापस लौटना एक बेहतर तरीका है क्योंकि परीक्षण करना आसान होगा। –

+0

मैं इस आईनंबरबल कहां वापस करूँगा?मैं समझता हूं कि सर्विस फ़ंक्शन कॉल पर जाने से पहले कुछ स्तर पर सत्यापन किया जाना चाहिए, लेकिन सेवा परत में उस वास्तविक फ़ंक्शन के भीतर त्रुटियां होने पर क्या होता है (उदाहरण के लिए svc.CreateBatchFile() के भीतर)? क्या मुझे सेवा फ़ंक्शन में एक खाली अपरिवर्तनीय में एक पैरामीटर के रूप में पास करना होगा, और फिर मेरे सेवा फ़ंक्शन को कॉल करने के बाद इसे जांचना होगा? पूर्व: svc.CreateBatchFile (बाहर प्रमाणीकरण परिणाम)? धन्यवाद – Josh

1

तुम सिर्फ ViewModel सत्यापन कर रहे हैं, FluentValidation एक उत्कृष्ट पुस्तकालय है।

यदि आप उपयोगकर्ता को प्रतिक्रिया के रूप में व्यावसायिक सत्यापन शामिल करना चाहते हैं, तो आप एडाप्टर पैटर्न का उपयोग कर सकते हैं, यह आपको वही देगा जो आप चाहते हैं।

एक इंटरफ़ेस बनाएं (IValidationDictionary या कुछ समान)। यह इंटरफ़ेस एक AddError विधि को परिभाषित करेगा और त्रुटि संदेशों को जोड़ने के लिए आपकी सेवा में पारित किया जाएगा।

public interface IValidationDictionary 
{ 
    void AddError(string key, string errorMessage); 
} 

अपने एमवीसी एप्लिकेशन के लिए मॉडलस्टेट एडाप्टर बनाएं।

public class ModelStateAdapter : IValidationDictionary 
{ 
    private ModelStateDictionary _modelState; 

    public ModelStateAdapter(ModelStateDictionary modelState) 
    { 
     _modelState = modelState; 
    } 

    public void AddError(string key, string errorMessage) 
    { 
     _modelState.AddModelError(key, errorMessage); 
    } 
} 

आपका सेवा कॉल का सत्यापन करना होगा कि IValidationDictionary

public class MyService 
    {   
     public void CreateDebitRequest(int userId, int cardId, decimal Amount, .... , IValidationDictionary validationDictionary) 
      { 
       if(userId == 0) 
        validationDictionary.AddError("UserId", "UserId cannot be 0"); 
      } 
    } 

की आवश्यकता होगी तब आप IValidationDictionary पर निर्भरता के लिए होता है लेकिन MVC पर नहीं जो भी अपने समाधान परीक्षण योग्य होगा।

यदि आपको किसी ऐसे ऐप में सेवाओं को लागू करने की आवश्यकता है जिसमें ModelStateDictionary नहीं है, तो आप अपनी त्रुटियों को रखने के लिए उपयोग की जाने वाली कक्षा पर IValidationDictionary इंटरफ़ेस को लागू करेंगे।

नियंत्रक उदाहरण:

public ActionResult Test(ViewModel viewModel) 
{ 
    var modelStateAdapter = new ModelStateAdapter(ModelState); 
    _serviceName.CreateDebitRequest(viewModel.UserId, viewModel.CardId, ... , modelStateAdapter); 

    if(ModelState.IsValid) 
     return View("Success") 

    return View(viewModel); 
} 

इस दृष्टिकोण का प्रो की:

  • बुला पुस्तकालयों
  • यह परीक्षण के लिए IValidationDictionary उपहास करने के लिए संभव है पर कोई निर्भरता।

कोन के इस दृष्टिकोण का:

  • आप हर विधि है कि आप उस उपयोगकर्ता को लौटा दी जा रहा है पर सत्यापन करना चाहते हैं IValidationDictionary पारित करने के लिए की जरूरत है।

    या

    आप सेवा का सत्यापन शब्दकोश आरंभ करने के लिए (यदि आप IValidationDictionary एक निजी क्षेत्र के रूप में करने का फैसला), प्रत्येक नियंत्रक कार्रवाई आप के सामने सत्यापित करना चाहते हैं की जरूरत है।

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