2011-11-14 7 views
8

मैं एक एपीआई लिख रहा हूं जो एक सेवा से जुड़ता है जो या तो एक सरल "सफलता" संदेश देता है या विफलता के 100 से अधिक विभिन्न स्वादों में से एक है।यह इंगित करने का सर्वोत्तम अभ्यास तरीका है कि एक सर्वर अनुरोध विफल रहा है?

मूल रूप से मैंने इस विधि को लिखने के लिए सोचा था कि अगर यह सफल हुआ तो विधि कुछ भी नहीं लौटाती है, लेकिन यदि यह किसी भी कारण से विफल हो जाती है, तो यह अपवाद फेंकता है।

मुझे इस डिजाइन को बहुत ज्यादा ध्यान नहीं दिया गया था, लेकिन दूसरी तरफ मैं आज जोशुआ ब्लोच के "How to Design a Good API and Why it Matters" पढ़ रहा था, जहां वह कहता है "असाधारण स्थितियों को इंगित करने के लिए अपवादों को फेंक दें ... ग्राहक को उपयोग करने के लिए बाध्य न करें नियंत्रण प्रवाह के लिए अपवाद। " (और "इसके विपरीत, चुपचाप विफल न करें।")

दूसरी तरफ, मैंने देखा कि अनुरोध करते समय HttpWebRequest एक अपवाद फेंकने लगता है, एक प्रतिक्रिया को वापस करने के बजाय " 500 आंतरिक सर्वर त्रुटि "संदेश।

इस मामले में त्रुटियों की रिपोर्ट करने के लिए सबसे अच्छा पैटर्न क्या है? अगर मैं हर असफल अनुरोध पर अपवाद फेंकता हूं, तो क्या मैं भविष्य में किसी बिंदु पर भारी दर्द के लिए हूं?

संपादित करें: प्रतिक्रियाओं के लिए बहुत दयालु धन्यवाद। कुछ विस्तार:

  • यह एक डीएलएल है जो ग्राहकों को उनके आवेदन में संदर्भित करने के लिए दिया जाएगा।
  • उपयोग का एक समान उदाहरण ChargeCreditCard(CreditCardInfo i) होगा - जाहिर है जब चार्ज क्रेडिट कार्ड() विधि विफल हो जाती है, यह एक बड़ा सौदा है; मैं सिर्फ 100% निश्चित नहीं हूं कि मुझे प्रेस को रोकना चाहिए या उस जिम्मेदारी को ग्राहक को पास करना चाहिए।

संपादित दूसरा: मूल रूप से मैं पूरी तरह आश्वस्त है जो इन दो विधियों के उपयोग करने के लिए नहीं कर रहा हूँ:

try { 
ChargeCreditCard(cardNumber, expDate, hugeAmountOMoney); 
} catch(ChargeFailException e) { 
    // client handles error depending on type of failure as specified by specific type of exception 
} 

या

var status = TryChargeCreditCard(cardNumber, expDate, hugeAmountOMoney); 

if(!status.wasSuccessful) { 
    // client handles error depending on type of failure as specified in status 
} 

उदा जब कोई उपयोगकर्ता क्रेडिट कार्ड चार्ज करने का प्रयास करता है, तो क्या कार्ड वास्तव में असाधारण परिस्थिति में अस्वीकार कर दिया गया है? क्या मैं इस प्रश्न को पहली जगह पूछकर खरगोश छेद में बहुत दूर जा रहा हूं?

1) कैसे एपीआई पहुँचा दिया जाएगा:

+1

"अपवाद, अपवाद, अपवाद!" (* बल्मर नृत्य *) –

+1

क्या यह आरईएसटी, या एसओएपी, या दोनों होगा? –

+0

'WebException'' WebRequest's 'GetResponse() 'द्वारा फेंक दिया गया है' प्रोटोकॉल प्रारूप के संबंध में _valid_ है 'WebResponse' है। तो आपके लिए, यह या तो 'बीसीएल' कक्षाओं के डिजाइन को बनाए रख रहा है और कुछ समान बना सकता है या नहीं ... नहीं। आपके आवेदन का लक्ष्य क्या है? क्या यह आवश्यक है कि सर्वर अनुरोध सफल हो जाए? फिर फेंक दो। या क्या अतिरिक्त डेटा रखना अच्छा है? – ordag

उत्तर

6

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

  1. क्या अन्य डेवलपर्स इसे पढ़ने में सक्षम होंगे? क्या यह औसत डेवलपर द्वारा समझा जा सकता है? उदाहरण: ServiceConnectionException बनाम एक भ्रमित ServiceDisconnectedConnectionStatusException
  2. अपवाद फेंकने के मामले में, असाधारण परिस्थिति क्या है? विधि को लागू करने के लिए कॉलर को क्या करना है?
  3. क्या यह अपवाद घातक है? अगर यह पकड़ा जाता है तो क्या इस अपवाद के साथ वास्तव में कुछ भी किया जा सकता है? थ्रेड, स्मृति से बाहर, .. आप कुछ भी उपयोगी नहीं कर सकते हैं। इसे पकड़ो मत
  4. अपवाद अपवाद है? मान लें कि आपके पास Car GetCarFromBigString(string desc) नामक एक विधि है जो एक स्ट्रिंग लेती है और Car ऑब्जेक्ट देता है। यदि उस विधि के लिए बहुमत का उपयोग-केस Car उस string से ऑब्जेक्ट उत्पन्न करना है, तो Carstring से निर्धारित नहीं किया जा सकता है, तो अपवाद फेंक न दें। इसके बजाय, bool TryGetCarFromBigString(string desc, out Car) जैसी विधि लिखें।
  5. क्या इसे आसानी से रोका जा सकता है? क्या मैं कुछ जांच सकता हूं, आइए सरणी का आकार या एक चर को शून्य कहें?

कोड पठनीयता के लिए, चलिए संभावित रूप से आपके संदर्भ को देखें।

bool IsServiceAlive() 
{ 
    bool connected = false; //bool is always initialized to false, but for readability in this context 

    try 
    { 
     //Some check 
     Service.Connect(); 
     connected = true; 
    } 
    catch (CouldNotConnectToSomeServiceException) 
    { 
     //Do what you need to do 
    } 

    return connected; 
} 

//or 
void IsServiceAlive() 
{ 
    try 
    { 
     //Some check 
     Service.Connect(); 
    } 
    catch (CouldNotConnectToSomeServiceException) 
    { 
     //Do what you need to do 
     throw; 
    } 
} 



static void Main(string[] args) 
{ 
    //sample 1 
    if (IsServiceAlive()) 
    { 
     //do something 
    } 

    //sample 2 
    try 
    { 
     if (IsServiceAlive()) 
     { 
      //do something 
     } 
    } 
    catch (CouldNotConnectToSomeServiceException) 
    { 
     //handle here 
    } 

    //sample 3 
    try 
    { 
     IsServiceAlive(); 
     //work 
    } 
    catch (CouldNotConnectToSomeServiceException) 
    { 
     //handle here 
    } 
} 

आप उपरोक्त देख सकते हैं, कि पकड़ने नमूना 3 में CouldNotConnectToSomeServiceException जरूरी नहीं कि कोई बेहतर पठनीयता उपज नहीं करता है तो संदर्भ बस एक द्विआधारी परीक्षण है। हालांकि, दोनों काम करते हैं। लेकिन क्या यह वास्तव में जरूरी है? क्या आपका प्रोग्राम छिपा हुआ है यदि आप कनेक्ट नहीं कर सकते हैं? वास्तव में यह कितना महत्वपूर्ण है? ये सभी कारक हैं जिन्हें आपको ध्यान में रखना होगा। यह कहना मुश्किल है क्योंकि हमारे पास आपके सभी कोड तक पहुंच नहीं है।

चलिए कुछ अन्य विकल्पों पर नज़र डालें जो अधिकतर समस्याओं का कारण बनते हैं।

//how will the code look when you have to do 50 string comparisons? Not pretty or scalable. 
public class ServiceConnectionStatus 
{ 
    public string Description { get; set; } 
} 

और

//how will your code look after adding 50 more of these? 
public enum ServiceConnectionStatus 
{ 
    Success, 
    Failure, 
    LightningStormAtDataCenter, 
    UniverseExploded 
} 
3

मैं आप अपने डिजाइन में कुछ बातों पर विचार करने की जरूरत है लगता है? यदि आप इसे वेब सेवाओं पर उजागर कर रहे हैं, तो अपवाद फेंकना शायद एक अच्छा विचार नहीं है। यदि एपीआई एक डीएलएल में है जिसे आप लोगों को उनके अनुप्रयोगों में संदर्भित करने के लिए उपलब्ध करा रहे हैं, तो अपवाद ठीक हो सकते हैं।

2) एपीआई उपभोक्ता के लिए विफलता प्रतिक्रिया उपयोगी बनाने के लिए वापसी मूल्य के साथ कितना अतिरिक्त डेटा यात्रा करने की आवश्यकता है? यदि आपको उस विफलता संदेश के साथ एक स्ट्रिंग के विपरीत आपके विफलता संदेश (यानी उपयोगकर्ता आईडी और लॉगिन) में उपयोगी जानकारी प्रदान करने की आवश्यकता है, तो आप या तो कस्टम अपवाद या "त्रुटि एन्काउंटर्ड" श्रेणी का उपयोग कर सकते हैं जिसमें त्रुटि कोड और अन्य उपयोग योग्य जानकारी है । यदि आपको केवल एक कोड वापस पास करने की आवश्यकता है, तो एक ENum या तो सफलता (0) या विफलता (कोई गैर-शून्य मान) इंगित करता है उचित हो सकता है।

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

तो संक्षिप्त उत्तर यह है कि यह वास्तव में सटीक परिस्थितियों पर निर्भर करता है।

2

मुझे वास्तव में "असाधारण शर्तों को इंगित करने के लिए थ्रो अपवाद" विचार पसंद है। उनके पास उस कारण का नाम होना चाहिए।

एक नियमित आवेदन में, आप File.Open() से पहले File.Exists() का उपयोग करेंगे ताकि अपवाद को फेंकने से रोका जा सके। अपेक्षित त्रुटियों के रूप में अपवादों को संभालना मुश्किल है।

हालांकि क्लाइंट-सर्वर वातावरण में, आप दो अनुरोध भेजने और FileOpenResponse कक्षा को स्थिति और डेटा (जैसे फ़ाइल संभाल, इस मामले में) भेजने के लिए रोकना चाह सकते हैं।

+2

'अपवादों का फ्लिप पक्ष असाधारण है' - (एमएसडीएन दस्तावेज और .NET ढांचे डिजाइन दिशानिर्देशों से): "अपवाद रिपोर्टिंग त्रुटियों के लिए मानक तंत्र हैं।" इसके अलावा: http://blogs.msdn.com/b/kcwalina/archive/2008/07/17/exceptionalerror.aspx –

+0

भले ही कोई एप्लिकेशन अलग-अलग प्रकार के अपवादों को अलग-अलग संभाल सके, फिर भी मैं 'एपीआई' के साथ एक एपीआई देखूंगा() ''AllOfMemoryException' फेंकने वाले 'Alloc()' के साथ एक से अधिक विधि (लिंक में उदाहरण को देखकर)। यद्यपि इन दिशानिर्देशों को लिखने वाले लोगों के अनुभव को स्वीकार नहीं करना मेरे लिए मूर्खतापूर्ण होगा। कम से कम यह मुझे फिर से सोच रहा है :) –

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

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