2013-02-21 2 views
5

У меня есть веб-приложение на 3 уровня. Я хочу использовать Я использую блок catch catch на моем уровне бизнес-логики. Правильно ли использовать блок try/catch в бизнес-логике или мне нужно использовать его в моем слое пользовательского интерфейса?где поставить try/catch в архитектуре с 3 уровнями

см. Мой код для DAL.

Data Access Layer 

#region Insert in to Logbook 
public int Insert_LogBook(string Vehicle_Number, DateTime Vehicle_Booking_Date, TimeSpan Time_From, TimeSpan Time_To, int KM_Start, int KM_End, string Vehicle_Used_By, string Cost_Code, string Budget_Line, DateTime Entry_Date) 
{ 
    try 
    { 
     SqlCommand com = new SqlCommand("Insert_LogBook", con); 
     com.Parameters.Add("@Vehicle_Number", SqlDbType.NVarChar, 100).Value = Vehicle_Number; 
     com.Parameters.Add("@Vehicle_Booking_Date", SqlDbType.DateTime).Value = Vehicle_Booking_Date; 
     com.Parameters.Add("@Time_From", SqlDbType.Time).Value = Time_From; 
     com.Parameters.Add("@Time_To", SqlDbType.Time).Value = Time_To; 
     com.Parameters.Add("@KM_Start", SqlDbType.Int).Value = KM_Start; 
     com.Parameters.Add("@KM_End", SqlDbType.Int).Value = KM_End; 
     com.Parameters.Add("@Vehicle_Used_Byr", SqlDbType.VarChar, 100).Value = Vehicle_Used_By; 
     com.Parameters.Add("@Cost_Code", SqlDbType.NVarChar, 50).Value = Cost_Code; 
     com.Parameters.Add("@Budget_Line", SqlDbType.NVarChar, 50).Value = Budget_Line; 
     com.Parameters.Add("@Entry_Date", SqlDbType.DateTime).Value = Entry_Date; 
     con.Open(); 
     int res = com.ExecuteNonQuery(); 

    } 
    catch (Exception ex) 
    { 
     WebMsgBox.Show(ex.Message); 
    } 
    finally 
    { 
     con.Close(); 
     con.Dispose(); 

    } 
    return 1; 
} 
#endregion 

Так что я должен использовать его в слое bal или IN UI или мой код в порядке. потому что если я не использую try/catch в своем слое пользовательского интерфейса, он не будет перехватывать исключение (если есть) и показывает страницу с ошибкой.

ответ

3

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

  • Исключения позволяют находить ошибки в коде.
  • Они останавливают запущенную программу, чтобы предотвратить «травму» для бизнеса.
  • Они позволяют фильтровать между разумно ожидаемыми исключениями (сеть недоступна в мобильном приложении) по сравнению с непредвиденными ошибками, такими как исключение NullReferenceException.
  • Они прямо соображают, почему произошла ошибка.
  • Они позволяют каждому компоненту добавлять слой информации о контексте и состоянии, чтобы помочь отлаживать, это шаблон catch, wrap и throw.

Вы можете и должны использовать попытаться/поймать/(наконец) почти везде, но ...

используется улов только тогда, когда вы знаете, какие исключения (ы), которые могут произойти и может восстановиться их. Вы редко должны когда-либо ловить базовый тип исключения. Разрешить все другие ошибки пузыриться и быть найдены программистом/тестером/пользователем.

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

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

Вы также можете рассмотреть возможность абстрактного абзаца и подклассификации DataAccessException для более конкретных исключений, таких как SqlDataAccessException или SecurityDataAccessException.

Как вы, кажется, знаете, вы используете, наконец, когда хотите, чтобы какой-то код запускался в случае ошибки, даже если вы не поймаете и не обработаете само исключение. В ситуациях, когда вы должны всегда выпускать ресурс, try/finally становится стандартным шаблоном.

Кроме того, если возможно, поместите try/catch вокруг наиболее конкретного патча кода, в котором вы можете справиться с ошибкой, чтобы ошибки кодирования в окружающем коде разбивали приложение.

Вы можете подумать: «Как я могу поймать конкретное исключение, если я еще не знаю, какие исключения будут выбрасываться?» Вы должны увидеть их документированными в методе ExecuteNonSql, и поэтому важно документировать свой собственный API/компонент за исключения, которые он выбрасывает. Используйте XML-комментарии для этого, и если вы отправляете публичную DLL, включите генератор файлов комментариев XML.

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

На этот этап в вашей жизни программирования, я настоятельно рекомендую прочитать Принципы проектирования каркаса от Cwalina и Abrams.Это поможет вам быстро сделать правильный выбор по всем этим типам вопросов, и вы обнаружите, что использование вашего собственного кода так же радует, как и API-интерфейсы Microsoft (в основном).

Luke

Немного о сообщениях. Я использую такие вещи в сообщении об ошибке.

«Невозможно выполнить {выполнить функцию}. Произошел {тип исключения}. {Предлагайте рекомендацию по устранению или общие причины ошибки}. См. {Внутреннее исключение | дальнейшие записи в журнале}."

Например, в качестве компонента для состояния автоматического энергосбережения в приложении:

... 
catch(FileNotFoundException fnfe) 
{ 
    string m = String.Format("Cannot save changes. A FileNotFoundException occurred. Check the path '{0}' is valid, that your network is up, and any removable media is available. Please see inner exception.", path); 

    _log.Error(m, fnfe); 

    throw new StorageLifecycleException(m, fnfe); 
} 
0

Вы должны поместить свой доступ к данным и бизнес-логику в библиотеки классов. Вы не должны вызывать компоненты переднего конца из BLL или DAL. Создайте ведение журнала в своих BLL и DAL, зарегистрируйте их, используя что-то похожее на данные ошибки log4net.

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

2

Вы должны написать блок try-catch, где вы можете обработать исключение. Нет такой вещи, как «всегда помещать попытку здесь или там». Я вижу, вы с исключением, как это:

catch (Exception ex) 
{ 
    WebMsgBox.Show(ex.Message); 
} 

Это плохо из-за нескольких причин:

  1. Вы ловите родовое Exception типа. Я видел вопрос об этом несколько дней назад: https://stackoverflow.com/a/14727026/238682
  2. Вы пытаетесь обработать исключение с WebMsgBox.Show в пределах уровня доступа к данным, который разбивает границы слоя.

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

public int Insert_LogBook(string Vehicle_Number, DateTime Vehicle_Booking_Date, TimeSpan Time_From, TimeSpan Time_To, int KM_Start, int KM_End, string Vehicle_Used_By, string Cost_Code, string Budget_Line, DateTime Entry_Date) 
{ 
    using(SqlCommand com = new SqlCommand("Insert_LogBook", con)) 
    { 
     com.Parameters.Add("@Vehicle_Number", SqlDbType.NVarChar, 100).Value = Vehicle_Number; 
     com.Parameters.Add("@Vehicle_Booking_Date", SqlDbType.DateTime).Value = Vehicle_Booking_Date; 
     com.Parameters.Add("@Time_From", SqlDbType.Time).Value = Time_From; 
     com.Parameters.Add("@Time_To", SqlDbType.Time).Value = Time_To; 
     com.Parameters.Add("@KM_Start", SqlDbType.Int).Value = KM_Start; 
     com.Parameters.Add("@KM_End", SqlDbType.Int).Value = KM_End; 
     com.Parameters.Add("@Vehicle_Used_Byr", SqlDbType.VarChar, 100).Value = Vehicle_Used_By; 
     com.Parameters.Add("@Cost_Code", SqlDbType.NVarChar, 50).Value = Cost_Code; 
     com.Parameters.Add("@Budget_Line", SqlDbType.NVarChar, 50).Value = Budget_Line; 
     com.Parameters.Add("@Entry_Date", SqlDbType.DateTime).Value = Entry_Date; 
     con.Open(); 
     int res = com.ExecuteNonQuery(); 

     return 1; 
    } 

} 

public void SomeMethodWhichUsesThatInsert() 
{ 
    try 
    { 
     //call Insert_LogBook 
    } 
    catch(SomeException e) 
    { 
     //handle 
    } 

} 
4

Это зависит только от того, вы можете использовать try catch блоки в обоих слоях.

Но проблема не в том, где вы используете код обработки исключений; проблема в том, как вы используете. В примере, который вы указали, вы ловите общий код exception, вы не знаете, является ли это SqlException или каким-либо другим исключением.

В общем,

  1. ловить только исключения можно обрабатывать (в примере улове SqlException, не все исключения)

  2. дисплея удобное для пользователя сообщение (в вашем примере просто, отображающих сообщение об ошибке не имеет смысла для пользователя)

  3. журнала исключение

  4. обрабатывает исключение, где оно встречается; если это связанное с DAL исключение обрабатывает его в слое DAL, если это связанное с UI исключение обрабатывает его в слое пользовательского интерфейса.

+0

так могли бы вы разработать, используя мой код? Я не использовал в 3-м ярусе – Gaurav

+0

+1 В сообщении об ошибке. Мы все росли с грубыми сообщениями, поэтому мы думаем, что сообщения должны звучать глупо. Нет. Они должны звучать как друг, объясняющий проблему простым языком, даже предлагая возможные решения. –

 Смежные вопросы

  • Нет связанных вопросов^_^