Дублирование кода в блоке try catch
Есть ли лучший способ поймать исключения? Кажется, я дублирую много кода. В основном в каждом контроллере у меня есть оператор catch, который делает это:
try
{
Do something that might throw exceptions.
}
catch (exception ex)
{
Open database connection
Save exception details.
If connection cannot be made to the database save exception in a text file.
}
У меня есть 4 контроллера и около 5-6 методов действий в каждом контроллере, в котором много дублирования кода. Как я могу обрезать количество строк в выводе try catch выше?
Ответы
Ответ 1
Здесь вы можете использовать методы расширения.
Создайте метод расширения в новом классе.
public static class ExtensionMethods
{
public static void Log(this Exception obj)
{
// log your Exception here.
}
}
И используйте его как:
try
{
}
catch (Exception obj)
{
obj.Log();
}
Ответ 2
Вам не нужно класть блоки try/catch для каждого метода. Это утомительно и болезненно! Вместо этого вы можете использовать событие Application_Error Global.asax для регистрации исключений. Код ниже представляет собой примерную реализацию, которая может использоваться для обнаружения исключений, которые происходят в вашем веб-приложении.
protected void Application_Error(object sender, EventArgs e)
{
var error = Server.GetLastError();
if (!string.IsNullOrWhiteSpace(error.Message))
{
//do whatever you want if exception occurs
Context.ClearError();
}
}
Я также хотел бы подчеркнуть, что "Обработанное исключение" , особенно пытающееся поместить блоки try/catch для большинства методов, является одним из "Топ-3 тихих убийц производительности для IIS/ASP.NET apps" , как описано в этом блоге http://mvolo.com/fix-the-3-high-cpu-performance-problems-for-iis-aspnet-apps/
Ответ 3
То, что вы пытаетесь сделать, называется сквозной проблемой. Вы пытаетесь зарегистрировать любую ошибку, которая происходит в любом месте вашего кода.
В ASP.NET MVC сквозные проблемы могут быть достигнуты с помощью Filters. Фильтры - это атрибуты, которые можно применять глобально, к контроллеру или к методу. Они запускаются до того, как выполняется метод действия или после него.
У вас есть несколько типов фильтров:
- Фильтры авторизации, они запускаются, чтобы проверить, разрешен ли пользователю доступ к ресурсу.
- Фильтры действий, выполняемые до и после выполнения действия.
- Фильтры результатов, они могут быть использованы для изменения результата действия (например, добавление некоторого дополнительного HTMl к выходу)
- Фильтры исключений запускаются всякий раз, когда генерируется исключение.
В вашем случае вы ищете фильтры исключений. Эти фильтры запускаются только тогда, когда в методе действий происходит исключение. Вы можете применить фильтр глобально, чтобы он автоматически запускался для всех исключений в любом контроллере. Вы также можете использовать его специально для определенных контроллеров или методов.
Здесь, в документации MSDN, вы можете найти, как реализовать свои собственные фильтры.
Ответ 4
Лично, поскольку мне очень не нравятся блоки try
/catch
, я использую класс static
try
, который содержит методы, которые переносят действия в многоразовые блоки try
/catch
. Пример:
public static class Try {
bool TryAction(Action pAction) {
try {
pAction();
return true;
} catch (Exception exception) {
PostException(exception);
return false;
}
}
bool TryQuietly(Action pAction) {
try {
pAction();
return true;
} catch (Exception exception) {
PostExceptionQuietly(exception);
return false;
}
}
bool TrySilently(Action pAction) {
try {
pAction();
return true;
} catch { return false; }
}
// etc... (lots of possibilities depending on your needs)
}
Ответ 5
Я использовал специальный класс в своих приложениях, который называется ExceptionHandler, в статическом классе у меня есть некоторые методы для обработки исключений приложений. Это дает мне возможность централизовать обработку исключений.
public static class ExceptionHandler
{
public static void Handle(Exception ex, bool rethrow = false) {...}
....
}
В этом методе вы можете зарегистрировать исключение, переустановить его, заменить его другим видом исключения и т.д.
Я использую его в try/catch, подобном этому
try
{
//Do something that might throw exceptions.
}
catch (exception ex)
{
ExceptionHandler.Handle(ex);
}
Как справедливо заявил в своем ответе Wouter de Kort, это сквозная проблема, поэтому я поместил класс в свой Application Layer и использовал его как Service. Если вы определили класс как интерфейс, вы могли бы иметь разные реализации в разных сценариях.
Ответ 6
Также вы можете использовать шаблон Singleton:
sealed class Logger
{
public static readonly Logger Instance = new Logger();
some overloaded methods to log difference type of objects like exceptions
public void Log(Exception ex) {}
...
}
И
Try
{
}
Catch(Exception ex)
{
Logger.Instance.Log(ex);
}
Edit
Некоторым людям не нравится Синглтон для разумных оснований. Вместо Singleton мы можем использовать некоторые DI:
class Controller
{
private ILogger logger;
public Controller(ILogger logger)
{
this.logger = logger;
}
}
И используйте некоторую библиотеку DI, которая введет один экземпляр ILogger в ваши контроллеры.
Ответ 7
Мне нравятся ответы, предлагающие общие решения, однако я хотел бы указать еще один, который работает для MVC.
Если у вас есть общая база контроллеров (в любом случае вы должны это сделать, это ИМО с лучшей практикой). Вы можете просто переопределить метод OnException:
public class MyControllerBase : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
DoSomeSmartStuffWithException(filterContext.Exception);
base.OnException(filterContext);
}
}
Затем просто наследуйте обычные контроллеры от вашей общей базы вместо Controller
public class MyNormalController : MyControllerBase
{
...
Если вам это нравится, вы можете проверить класс Controller для других удобных виртуальных методов, у него много.
Ответ 8
В ASP.NET MVC вы можете реализовать свой собственный HandleErrorAttribute
, чтобы поймать все исключения, которые происходят во всех контроллерах:
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
var ex = filterContext.Exception;
// Open database connection
// Save exception details.
// If connection cannot be made to the database save exception in a text file.
}
}
Затем зарегистрируйте этот фильтр:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomHandleErrorAttribute());
}
}
И, конечно, вызовите метод регистрации при запуске приложения:
public class MvcApplication : HttpApplication
{
protected override void OnApplicationStarted()
{
// ...
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
// ...
}
}
Wouter de Kort уже объяснил концепцию этого в своем ответе.