Лучший способ указать, что запрос к серверу не выполнен? - PullRequest
8 голосов
/ 14 ноября 2011

Я пишу API, который подключается к сервису, который либо возвращает простое сообщение «Успех», либо один из более чем 100 различных типов ошибок.

Первоначально я подумал написать метод, который отправляет запрос в эту службу, чтобы в случае успеха метод ничего не возвращал, но если произошел сбой по какой-либо причине, он выдает исключение.

Я не возражал против этого дизайна, но с другой стороны, только сегодня я читал книгу Джошуа Блоха " Как разработать хороший API и почему это важно ", где он говорит "Бросьте исключения" чтобы указать исключительные условия ... Не заставляйте клиента использовать исключения для потока управления. " (и «И наоборот, не подводите молча.»)

С другой стороны, я заметил, что используемый мной HttpWebRequest, по-видимому, генерирует исключение при сбое запроса, а не возвращает ответ, содержащий сообщение «500 Internal Server Error».

Каков наилучший способ сообщения об ошибках в этом случае? Если я выброшу исключение при каждом неудавшемся запросе, буду ли я в будущем испытывать сильную боль?

Редактировать: Спасибо, очень любезно за ответы до сих пор. Некоторая разработка:

  • это DLL, которая будет предоставлена ​​клиентам для ссылки в их приложении.
  • аналогичным примером использования будет ChargeCreditCard(CreditCardInfo i) - очевидно, что когда метод ChargeCreditCard () не работает, это огромная сделка; Я просто не уверен на 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   
}

например. Когда пользователь пытается снять деньги с кредитной карты, действительно ли эта карта отклоняется исключительных обстоятельств? Я спускаюсь слишком далеко в кроличью нору, задавая этот вопрос в первую очередь?

Ответы [ 3 ]

6 голосов
/ 14 ноября 2011

Вот краткий список вещей, которые нужно учитывать. Хотя это и не является исчерпывающим, я считаю, что эти вещи могут помочь вам написать лучший код. Итог: не обязательно воспринимать обработку исключений как зло. Вместо этого, при написании их, спросите себя: насколько хорошо я действительно понимаю проблему, которую решаю? Чаще всего это поможет вам стать лучшим разработчиком.

  1. Смогут ли другие разработчики прочитать это? Может ли это быть понятным для среднего разработчика ? Пример: ServiceConnectionException против запутанного ServiceDisconnectedConnectionStatusException
  2. В случае возникновения исключения, как исключительная это обстоятельство? Что нужно сделать вызывающей стороне для реализации метода?
  3. Это исключение смертельно? Можно ли что-нибудь действительно сделать с этим исключением, если оно поймано? Прерывание потоков, нехватка памяти .. Вы не можете сделать ничего полезного. Не лови это.
  4. Смущает ли исключение? Допустим, у вас есть метод с именем Car GetCarFromBigString(string desc), который принимает строку и возвращает объект Car. Если основной сценарий использования этого метода заключается в создании объекта Car из этого string, не создавайте исключение, если Car не может быть определено из string. Вместо этого напишите метод, например 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
    }
}

Вы можете видеть выше, что перехват CouldNotConnectToSomeServiceException в примере 3 не обязательно дает лучшую читабельность, если контекст является просто двоичным тестом. Однако оба работают. Но действительно ли это необходимо? Ваша программа подключена, если вы не можете подключиться? Насколько это важно на самом деле? Это все факторы, которые вам необходимо принять во внимание. Трудно сказать, так как у нас нет доступа ко всему вашему коду.

Давайте рассмотрим некоторые другие варианты, которые, скорее всего, приводят к проблемам.

//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 голосов
/ 14 ноября 2011

Я думаю, вам нужно учесть несколько вещей в вашем дизайне:

1) Как получить доступ к API? Если вы выставляете это через веб-сервисы, то генерировать исключения, вероятно, не очень хорошая идея. Если API находится в DLL, которую вы предоставляете людям для ссылки в своих приложениях, то исключения могут быть в порядке.

2) Сколько дополнительных данных необходимо перенести с возвращаемым значением, чтобы сделать ответ об ошибке полезным для потребителя API? Если вам необходимо предоставить полезную информацию в сообщении об ошибке (т. Е. Идентификатор пользователя и логин), а не строку со встроенной информацией, вы можете использовать либо пользовательские исключения, либо класс «ErrorEncountered», содержащий код ошибки и другую полезную информацию , Если вам просто нужно передать код обратно, то может быть уместным ENum, указывающий либо на успех (0), либо на сбой (любое ненулевое значение).

3) Забыл об этом в первоначальном ответе: исключения являются дорогостоящими в .Net Framework. Если ваш API будет вызываться время от времени, это не должно учитываться. Однако, если API вызывается для каждой веб-страницы, которая обслуживается, например, на сайте с большим трафиком, вы определенно не хотите выдает исключения, указывающие на ошибку запроса.

Итак, краткий ответ: действительно зависит от конкретных обстоятельств.

2 голосов
/ 14 ноября 2011

Мне очень нравится идея «Бросить исключения для обозначения исключительных условий». У них должно быть это имя по причине.

В обычном приложении вы должны использовать File.Exists() перед File.Open(), чтобы исключить исключение. Ожидаемые ошибки как исключения трудно обрабатывать.

Однако в среде клиент-сервер вы можете отказаться от отправки двух запросов и создать класс FileOpenResponse для отправки как состояния, так и данных (например, дескриптора файла в данном случае).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...