2015-10-13 4 views
2

Я пишу простой и маленький API, который запускает кучу веб-запросов и работает с ответами. Пользователь только вызывает метод и обеспечивает обратный вызов, где он может работать с данными, что-то вроде следующего:Лучшая практика обработки ошибок и исключений для C# API

var someData = new SomeData(); 
API.GetSomeDataFromTheWeb((d)=>{someData = d;}); 

Для каждого ответа я реализовал конкретный класс проведения данных. Кроме того, я хочу, чтобы пользователь самостоятельно обрабатывал любую возникающую ошибку и исключение. Это может быть WebException, исключение JsonSerializationException или любая пользовательская ошибка, которая может произойти. Как передать эти разные исключения и ошибки пользователю, который затем может извлечь из него необходимую информацию для обработки этих исключений и ошибок?

+1

Вы просто бросаете исключение. До тех пор, пока он задокументирован, что ваш метод выбрасывает так и так исключение для этого и этого условия, ответственность за это требует кодер. Вы можете использовать встроенные классы исключений или [создать свой собственный] (https://msdn.microsoft.com/en-us/library/vstudio/ms229064 (v = vs.100) .aspx). – tnw

+0

или вы можете получить второе действие, которое будет вызываться при возникновении исключения. – pm100

+2

Либо разрешите исключение, либо поймать его, и обернуть его в настраиваемое исключение, которое предоставляет дополнительную информацию и бросает это. – David

ответ

4

библиотека (или API) разработка имеет дело с немного обработки исключений по-другому от того, как его обрабатываются в разработке приложений -

  1. Как вы уже писали в своем ответе, вы хотели бы, чтобы пользователь принял решение. Это важно, так как библиотека может использоваться в нескольких сценариях &, что невозможно предсказать каждую ситуацию, когда библиотека будет использоваться и иметь политику на месте. Это должно быть приложение, которое знает контекст & может иметь политику для него.

  2. Проверьте аргументы, переданные вашим API (приложением). Выбросьте исключение, если они неверны.

  3. Государство - Откат частично выполненной операции

    Обычно одного API, будет вызывать несколько интерфейсов API для выполнения операции. Допустим, что некоторые вызовы функций успешно завершены, а некоторые - нет.

    В таком случае желательно вернуться в исходное состояние и сообщить вызывающей стороне об ошибке.

    Пример

    try 
    { 
        // Database operations starts 
        // perform database operations 
        transaction.Commit(); 
    } 
    catch // anything goes wrong 
    { 
        // rollback 
        transaction.RollBack(); 
    
        // Rethowing the *Same* exception 
        throw; 
    } 
    
  4. скрытие деталей реализации от внешнего мира & держать его в безопасности. Это нужно использовать с осторожностью, но я передам свое мнение об этом.

В течение, например, вероятно, трассировка стека может выставить слишком много информации о моей реализации базы данных &, что это может поставить под угрозу по безопасности.

В таком случае может быть полезно поймать один тип &, выкинуть еще одно новое исключение.

try 
{ 
    // Database operations starts 
    // perform database operations 
    transaction.Commit(); 
} 
catch (DataException ex) 
{ 
    // rollback 
    transaction.RollBack(); 

    // I'm keeping the original error but lying about the stack stace 
    throw new InvalidOperationException(name, ex); 
} 

Теперь, позвольте мне рассказать о том, как создавать исключения.

Выбросить исключение, если API не может выполнить свою задачу полностью.Несколько вопросов, которые следует иметь в виду:

  1. Выберите тип (тип, основанный на исключении), который наиболее значим. Это даст возможность коду в стеке вызовов надлежащим образом обрабатывать конкретный случай.

    В случае отсутствия исключения .Net, которое соответствует точной семантике, создайте пользовательский.

  2. Если вы создаете иерархию пользовательских исключений. Лучше держать иерархию мелкой. Чтобы создать несколько базовых классов, поскольку базовые классы действуют как способ обработки всех ошибок как одна ошибка. В тех же строках никогда не бросайте System.Exception

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

Edit 1:

/// <summary> 
    /// Reads an Employee by its ID 
    /// </summary> 
    /// <param name="ID">Unique identifier</param> 
    /// <param name="dbContext">Contains inforamtion about how to connect to database</param> 
    /// <returns>Employee linked to ID; Null if no record is linked</returns> 
    public Employee ReadEmployee(string ID, IDataBaseContext dbContext) 
    { 
     if(string.IsNullOrWhiteSpace(ID)) 
      throw new ArgumentException("Unique id must be supplied to read the record"); 

     // Validate if the database can be accessed using db Context, if not throw another exception. 
     // Because it's preventing the API from doing its job 

     // read and return the record 
    } 

Я воскрешу ошибку только тогда, когда я не могу выполнить операцию чтения. Если после чтения данных возвращается null, все в порядке, API выполнил свою работу.

Что делать с нулевым значением, это то, что я разрешу вызывающему абоненту решить.

Возможно, в диалоговом окне поиска будет отображаться пустой результат при возврате null.

Но это может быть исключение в другом деловом случае.

+0

Спасибо за великолепное объяснение. Значит, вы всегда будете использовать исключения для обработки ошибок? Даже когда пользователь пытается получить данные по идентификатору, а идентификатор не существует (но будет ли он действительным), вы выбрали бы специальное исключение? Это означает, что пользователь должен обернуть каждый вызов API в блок catch try правильно? Разве это не проблема юзабилити? – zlZimon

+0

Я рад, что вы нашли полезную информацию. О вашем вопросе ... Да, инсус мой API (или метод утилиты) ** не может выполнить свою задачу **, я всегда позволяю вызывающему абоненту знать, что что-то не так - путем исключения исключений и никогда не сглаживания тех, которые возникают из-за функций внутри API (Я не использую специальные возвращаемые значения). Я поддерживаю целостность государства и освобождаю состояние, которое было повреждено без ремонта, возможно, лучше информировать пользователя о прекращении состояния, а не поддерживать приложение, работающее с поврежденным состоянием, которое может разразиться ошибками и выраженными курсами в системе. – Kapoor

+0

не найдя запись, когда был предоставлен идентификатор, нет, я не буду поднимать исключение, потому что API выполнил свою работу, чтобы прочитать запись. Я сделаю ошибку, только если не могу выполнить операцию чтения. Я объясню это на примере и отредактирую свой ответ. – Kapoor

0

Используйте throw WebException("your message") вот так. Используйте любое исключение, которое вы хотите. Пользователь должен будет поймать его и получить сообщение, используя ex.Message свойство (где ex это имя исключения)