मैं नीचे के रूप में मेरी सेवा कक्षाओं में से एक में एपीआई बुला रहा हूँ:

public GetCustomerApiResponse SearchCustomerByEmail(string email)
        {
            GetCustomerApiResponse customerApiResponse = null;
            try
            {
                var requestBody = JsonConvert.SerializeObject(new
                {
                    content = $@"{{""Email"":""{email}""}}",
                    key = _apiEnvironment,
                    name = "search-customer"
                });

                var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
                var res = _client.PostAsync(_baseUrl, content).Result.Content.ReadAsStringAsync().Result;
                customerApiResponse = JsonConvert.DeserializeObject<GetCustomerApiResponse>(res);
            }
            catch
            {
                // ignored
            }

            return customerApiResponse;
        }

यहाँ, मैं GetCustomerApiResponse प्रकार का Deserialized डेटा लौटा रहा हूँ। मैं पकड़ में विभिन्न प्रतिक्रिया प्रकार वापस करना चाहता हूं (उदाहरण के लिए GetCustomerApiResponseError टाइप करें)। इसे कैसे हासिल करें?

1
Shreekumar S 13 जिंदा 2022, 11:41
या तो आपके पास GetCustomerApiResponse और GetCustomerApiResponseError के लिए कुछ आधार प्रकार होना चाहिए और बहुरूपता का उपयोग करना चाहिए, या catch खंड में return का उपयोग करना चाहिए।
 – 
SᴇM
13 जिंदा 2022, 11:43
3
मुझे लगता है कि आप object वापस आ सकते हैं, लेकिन मैं इसकी अनुशंसा नहीं करूंगा। सी # में किसी कारण से मजबूत प्रकार हैं। ऐसा लगता है कि आप वास्तव में यहां क्या करना चाहते हैं एक टाइप किया गया अपवाद फेंकना है?
 – 
Liam
13 जिंदा 2022, 11:45
आप Tuple का उपयोग करने पर भी विचार कर सकते हैं।
 – 
Martin Costello
13 जिंदा 2022, 11:48

4 जवाब

यह मानते हुए कि यदि आप अपवाद फेंकते हैं तो आप कुछ करना चाहते हैं, मैं अनुशंसा करता हूं कि आप ऐसा कुछ और करें:

public GetCustomerApiResponse SearchCustomerByEmail(string email)
{
   try {}
   catch(Exception ex)
   {
       throw MyException(ex);
   }
   return customerApiResponse;

}

जहां MyException ऐसा दिखता है:

public MyException : Exception
{

   public MyException(Exception innerException) : base(innerException) {}
}

और कॉलिंग कोड इस तरह दिखता है:

try
{
    GetCustomerApiResponse response =  SearchCustomerByEmail(email);
}
catch(MyException ex)
{
     //do whatever you need to happen if it fails.
}

इस तरह कॉलिंग कोड को पता चलता है कि एक अपवाद फेंका गया है (यहां कोई छिपी हुई कार्यक्षमता नहीं है) लेकिन आप उस अपवाद को एक सुरुचिपूर्ण तरीके से भी संभाल सकते हैं। यदि आप अपने हैंडलिंग लॉजिक के लिए अधिक जानकारी प्रदान करना चाहते हैं, तो आप MyException का विस्तार कर सकते हैं।

4
Liam 13 जिंदा 2022, 12:19

दुर्भाग्य से आप विभिन्न प्रकार वापस नहीं कर सकते जब तक कि आप मूल प्रकार से निपट नहीं रहे हैं।

यदि आप कोड को कॉल करके अपवाद को संभालने के अलावा किसी विशिष्ट तरीके से त्रुटि को संभालना चाहते हैं, तो आप एक GetCustomerApiResult वापस कर सकते हैं

public class GetCustomerApiResponse {

    GetCustomerApiResponse CustomerApiResponse { get; set; }

    GetCustomerApiResponse CustomerApiError { get; set; }
}

तब आप कर सकते हैं

public GetCustomerApiResult SearchCustomerByEmail(string email)
{
    var result = new CuscustomerApiResult();
    try
    {
        ...

        customerApiResult.CustomerApiResponse = JsonConvert.DeserializeObject<GetCustomerApiResponse>(res);
    }
    catch
    {
        // Handle the exception but return some error information
        customerApiResult.CustomerApiError = ...
    }

    return customerApiResponse;
}

और अपने कॉलिंग कोड में आप जांच सकते हैं कि customerApiResult.CustomerApiError त्रुटि के लिए शून्य नहीं है या सफलता के लिए customerApiResult.CustomerApiResult जांचें।

2
phuzi 13 जिंदा 2022, 11:51

सबसे पहले, एक नियम के रूप में, आपको वास्तव में अपवादों (ए.के.ए. निगल) अपवादों को अनदेखा नहीं करना चाहिए।

निगलने वाले अपवादों को एक कोड गंध माना जाता है और आमतौर पर अच्छे कारणों के लिए उनका अपमान किया जाता है।

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

ऐसा उपयोग-मामला तब हो सकता है जब आप किसी सेवा से प्राप्त कुछ जटिल डेटा को सत्यापित करने का प्रयास कर रहे हों - उदाहरण के लिए, सुनिश्चित करें कि आपके लिए आवश्यक सभी गुणों में वास्तव में वे मान हैं जिनके साथ आप काम कर सकते हैं (उनमें से कोई भी डिफ़ॉल्ट नहीं है या ऐसा ही कुछ)।
एक "अमान्य" डेटा सेवा से वापस आने की उम्मीद की जा सकती है और इसलिए ऐसे मामले में अपवाद फेंकना सबसे अच्छा अभ्यास नहीं हो सकता है - इन स्थितियों के लिए मुझे वह उपयोग करना पसंद है जिसे मैंने Result<T> कहा है।

Result<T> मूल्य पर एक रैपर वर्ग जिसे अन्यथा वापस किया जाना चाहिए - कुछ और गुणों के साथ - सफलता या विफलता का संकेत देने वाला एक बूल और वैकल्पिक रूप से एक त्रुटि विवरण युक्त एक स्ट्रिंग।

आपके मामले में, कोड इस तरह दिखेगा:

public Result<GetCustomerApiResponse> SearchCustomerByEmail(string email)
{
    try
    {
        var requestBody = JsonConvert.SerializeObject(new
        {
            content = $@"{{""Email"":""{email}""}}",
            key = _apiEnvironment,
            name = "search-customer"
        });

        var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
        var res = _client.PostAsync(_baseUrl, content).Result.Content.ReadAsStringAsync().Result;
        
        return Result<GetCustomerApiResponse>
            .Success(JsonConvert.DeserializeObject<GetCustomerApiResponse>(res));
    }
    catch(Exception ex)
    {
        return Result<GetCustomerApiResponse>
            .Fail(ex.Message); // or ex.ToString() if you need more information
    }
}

कॉलिंग कोड ऐसा कुछ करेगा:

var result = SearchCustomerByEmail(email);
if(!result.Succeeded)
{
    Log(result.ErrorDescription);
    // Perhaps show the error description to the user (if you have one)
    return;
}
var customer = result.Value;
... rest of the code here

आप इसके बारे में परिणाम और परिणाम का उपयोग करके गैर असाधारण त्रुटियों को संभालना

2
Zohar Peled 13 जिंदा 2022, 12:16

मैं एक वर्ग CustomerApiResult का उपयोग करूंगा जिसमें एक संपत्ति GetCustomerApiResponse है और साथ ही ValidResponse + IEnumerable<string> ResponseErrors

public class CustomerApiResult
{
    // make the constructor private and use factory methods as below
    private CustomerApiResult(
        bool validResponse, 
        GetCustomerApiResponse apiResponse,
        //... other properties..., 
        string invalidReason,
        IEnumerable<string> responseErrors)
    {
        ValidResponse = validResponse;
        CustomerApiResponse = apiResponse;
        // other properties ...;
        InvalidReason = invalidReason;
        ResponseErrors = responseErrors ?? Enumerable.Empty<string>();
    }

    public bool ValidResponse { get; }
    public GetCustomerApiResponse CustomerApiResponse { get; }
    // other properties
    public string InvalidReason { get; }
    public IEnumerable<string> ResponseErrors { get; private set; }

    public static CustomerApiResult Valid(
        GetCustomerApiResponse apiResponse,
        // other properties, 
        IEnumerable<string> responseErrors = null)
           => new CustomerApiResult(true, apiResponse, null, responseErrors);

    public static CustomerApiResult Invalid(
        GetCustomerApiResponse apiResponse,
        // other properties, 
       string invalidReason = null, 
       IEnumerable<string> responseErrors = null)
          => new CustomerApiResult(false, apiResponse, invalidReason, responseErrors);
}

अब आप इसे इस तरह इस्तेमाल कर सकते हैं:

public CustomerApiResult SearchCustomerByEmail(string email)
{
    try
    {
        var requestBody = JsonConvert.SerializeObject(new
        {
            content = $@"{{""Email"":""{email}""}}",
            key = _apiEnvironment,
            name = "search-customer"
        });

        var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
        var res = _client.PostAsync(_baseUrl, content).Result.Content.ReadAsStringAsync().Result;
        
        return CustomerApiResult.Valid(JsonConvert.DeserializeObject<GetCustomerApiResponse>(res));
    }
    catch(Exception ex)
    {
        return CustomerApiResult.Invalid(null, $"Could not convert to {nameof(GetCustomerApiResponse)}", new[]{ex.Message});
    }
}

इसलिए मैं परिवर्तित वस्तु नहीं लौटाता, लेकिन एक एपीआई-परिणाम वस्तु जिसमें वस्तु (या अशक्त) होती है और एक ValidResponse संपत्ति होती है जिसे आपको पहले जांचना चाहिए।

तो उदाहरण के लिए:

CustomerApiResult result = _api.SearchCustomerByEmail("jon.doe@gmail.com");
if(result.ValidResponse)
{
    GetCustomerApiResponse customer = result.CustomerApiResponse;
    // do something with the customer ...
}
else
{
    // log the response errors and/or the InvalidReason and inform the user
}

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

2
Tim Schmelter 13 जिंदा 2022, 12:28
तो मूल रूप से यह मेरे Result<T> उत्तर की तरह है, इस अपवाद के साथ कि मेरा प्रस्तावित समाधान अधिक सामान्य है। मुझे अपनी एकल ErrorDescription संपत्ति से अधिक IEnumerable<string> responseErrors का उपयोग पसंद है, लेकिन दूसरी ओर, मुझे यह तथ्य बेहतर लगता है कि मेरा प्रस्तावित समाधान अधिक सामान्य-उद्देश्य वाला है। ऑल-इन-ऑल, +1।
 – 
Zohar Peled
13 जिंदा 2022, 12:41
1
@ZoharPeled: यदि आपके पास कई अलग-अलग वस्तुएं हैं जिन्हें आप इस एकल वर्ग से संभालना चाहते हैं तो आप अपने सामान्य दृष्टिकोण का उपयोग कर सकते हैं। दूसरी ओर, एक अलग वर्ग के भी फायदे हैं, अर्थात यदि आवश्यक हो तो आप अतिरिक्त विशिष्ट गुण आसानी से प्रदान कर सकते हैं (उदाहरण के लिए यदि एपीआई-कॉल से एक से अधिक ऑब्जेक्ट लौटाए गए हैं) या आप CustomerId जैसी संपत्ति प्राप्त करते हैं। और परिणाम वर्ग में इसे बेनकाब करना चाहते हैं। लेकिन हाँ, एक सामान्य दृष्टिकोण एक अच्छा तरीका है, इसलिए शायद हमारे उत्तरों का मिश्रण अच्छा होगा।
 – 
Tim Schmelter
13 जिंदा 2022, 12:46