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

С# (не ASP/MVC/WinForms) - Ловить все исключения в классе

Некоторая справочная информация

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

К сожалению, система не обрабатывает необработанные исключения, пузырящиеся из .NET кода, если это вообще не так; система выходит из строя без объяснения причин. Это раздражает, потому что мы часто хотим обрабатывать исключения в проприетарной системе, а не в .Net-коде. Решение, предлагаемое поставщиком системы, состоит в том, чтобы переупаковать исключение в специальный объект, который обрабатывает система.

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

Вопрос

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

Очевидно, что интерфейс между .Net-dll, содержащим классы и запатентованный язык, полностью находится вне нашего контроля.

Изменить

Я попробовал метод currentDomain.UnhandledException, предложенный @VMAtm, к сожалению, безрезультатно. Обработчик событий не срабатывал, и родительская система завладела исключением, а затем, как обычно, стала плохо себя вести. Это снова привело меня в Google, и я нашел этот абзац здесь:

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

Джонатан Келджо, исключения CLR PM

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

Ох, ошибка, которую я получаю в родительской системе, - это Exception has been thrown by the target of an invocation., насколько я знаю сообщение из внешнего исключения. Net. Если можно что-либо прочитать из этого, я не знаю.

Я поеду в Castle Dynamic Proxy, предложенный также @jlew, но это выглядело намного сложнее, чем две строки AppDomain, и немного испугало меня:)

Решение

Если у вас такая же проблема, как и у меня, вы должны попробовать метод currentDomain.UnhandledException, предложенный @VMAtm во-первых, потому что из-за того, что моя родительская система была особенно анальной, она не работала.

Я работал, используя настройку Castle DynamicProxy. Это было очень легко настроить. Мой тестовый пример был фасадным классом, инкапсулирующим класс XmlAttribute. Первое, что мне нужно было сделать, это написать класс прокси:

public class AttribInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        try
        {
            invocation.Proceed();
        }
        catch (Exception e)
        {
            // Custom exception repackaging here
        }
    }
}

Затем мне пришлось указать фасадному объекту на самом деле использовать прокси. Я сохранил свое старое backend-поле, но добавил c'tor следующее:

public class CapXmlAttribute : CapPmlNetObject
{
    private XmlAttributeBackend _xmlAttribute;

    public CapXmlAttribute()
    {
        var generator = new ProxyGenerator();
        _xmlAttribute = (XmlAttributeBackend) generator.CreateClassProxy(
            typeof (XmlAttributeBackend), new AttribInterceptor());
    }
}

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

DynamicProxy действительно не так хорошо документирован, но я многое узнал из учебник Krzysztof Koźmic и код Гамильтона Verissimo.

4b9b3361

Ответ 1

Я бы посмотрел на использование чего-то вроде Замок динамического прокси.
Это позволит вам перехватывать вызовы метода класса, что даст вам центральное место для размещения обработчика исключений "весь-весь". (Тем не менее, мне непонятно, как на самом деле создаются ваши классы, что может сделать этот подход проблематичным)

Ответ 2

Как я понял ответ, вам нужно поймать и реконструировать необработанное исключение, верно? Вы можете добавить обработчик для AppDomain.UnhandledException Event:

  AppDomain currentDomain = AppDomain.CurrentDomain;
  currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);

  static void MyHandler(object sender, UnhandledExceptionEventArgs args)
  {
        Exception e = (Exception) args.ExceptionObject;
        // handle exception here, you can easily package exceptions there.
  }

Update:

Я обнаружил другое событие в классе AppDomain, Событие AppDomain.FirstChanceException:

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

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

Ответ 3

В дополнение к сообщению VMAtm вы также можете установить обработчик событий для ThreadExceptions