Подтвердить что ты не робот

Дублирование кода в блоке 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 выше?

4b9b3361

Ответ 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 уже объяснил концепцию этого в своем ответе.