Ответ 1
Вот как мы подходим к проблеме:
Все вызовы с уровня UI/codebehind на другие уровни используют try-catch, где мы всегда получаем пользовательское исключение. Все действия, выполняемые лежащими в основе слоями, имеют свой собственный try-catch, который регистрирует, переносит и генерирует настраиваемое исключение. Пользовательский интерфейс затем может полагаться на это и искать обработанные исключения с дружественными сообщениями об ошибках.
Codebehind:
protected void btnSubmit_Click(object sender, EventArgs e)
{
//do something when a button is clicked...
try
{
MyBL.TakeAction()
}
catch(MyApplicationCustomException ex)
{
//display something to the user, etc.
ltlErrorPane.Text = ex.Message;
//or redirect if desired
if(ex.ErrorType == MyCustomErrorsType.Transactional)
{
Response.Redirect("~/Errors/Transaction.aspx");
}
}
}
BL:
На бизнес-уровне любые операции, которые могут не использовать try-catch, которые регистрируют и обертывают проблему, прежде чем бросать ее в пользовательский интерфейс.
public class MyBL
{
public static void TakeAction()
{
try
{
//do something
}
catch(SpecificDotNetException ex)
{
//log, wrap and throw
MyExceptionManagement.LogException(ex)
throw new MyApplicationCustomException(ex, "Some friendly error message", MyCustomErrorsType.Transactional);
}
finally
{
//clean up...
}
}
}
Обработчик исключений:
Фактический обработчик исключений имеет несколько способов ведения журнала, включая журнал событий, журнал файлов и последний email, если все остальное не работает. Мы выбираем простой возврат false, если регистратор не может выполнять какие-либо ожидаемые действия. ИМО это личный выбор. Мы полагаем, что вероятность того, что три метода не удастся подряд (журнал событий не удался, попробуйте файл журнала, не удается, попробуйте электронную почту, не удается) очень маловероятен. В этом случае мы решили разрешить приложению продолжать. Другой вариант - разрешить полностью сбой приложения.
public static class MyExceptionManagement
{
public static bool LogException(Exception ex)
{
try
{
//try logging to a log source by priority,
//if it fails with all sources, return false as a last resort
//we choose not to let logging issues interfere with user experience
//if logging worked
return true;
}
catch(Exception ex)
{
//in most cases, using try-catch as a true-false is bad practice
//but when logging an exception causes an exception itself, we do
//use this as a well-considered choice.
return false;
}
}
}
Наконец, как отказоустойчивый, мы реализуем глобальный обработчик событий Application_Error
(в Global.asax
). Это последнее средство для случаев, когда мы неправильно пытались что-то поймать. Обычно мы регистрируем и перенаправляем на страницу с дружественной ошибкой. Если вышеупомянутая пользовательская обработка ошибок выполнена успешно, очень мало ошибок приведет к глобальному обработчику.
Надеюсь, это поможет немного. Это одно из возможных решений. Он работал очень хорошо для нас в течение нескольких лет в некоторых более крупных приложениях.