Обработка исключений с использованием HttpModule - PullRequest
5 голосов
/ 25 сентября 2008

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

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

Мой вопрос: Разумно обернуть весь код внутри блоков try {} catch {} и затем выдать новое исключение? И если это так, то почему? В чем выгода?

Мое личное мнение таково, что было бы намного проще использовать HttpModule, подписаться на событие Error события Application и делать то, что необходимо внутри модуля. Если бы мы пошли по этой дороге, мы бы что-то пропустили? Есть ли недостатки?

Ваше мнение высоко ценится.

Ответы [ 6 ]

10 голосов
/ 25 сентября 2008

Никогда 1 catch (Exception ex). Период 2 . Невозможно справиться со всеми видами ошибок, которые вы можете поймать.

Никогда 3 перехватывает производный от исключения тип, если вы не можете обработать его или предоставить дополнительную информацию (для использования последующими обработчиками исключений). Отображение сообщения об ошибке не совпадает с обработка ошибка.

Несколько причин для этого, от макушки моей головы:

  • Ловить и отбрасывать дорого
  • В итоге вы потеряете трассировку стека
  • В вашем коде будет низкое отношение сигнал / шум

Если вы знаете, как обрабатывать специфическое исключение (и перевести приложение в состояние до появления ошибки), перехватите его. (Вот почему это называется исключение обработка .)

Чтобы обработать исключения, которые не перехвачены, прослушайте соответствующие события. При работе с WinForms вам нужно будет прослушивать System.AppDomain.CurrentDomain.UnhandledException и - если вы делаете Threading - System.Windows.Forms.Application.ThreadException. Для веб-приложений существуют аналогичные механизмы (System.Web.HttpApplication.Error).

Что касается упаковки исключений фреймворка в вашем приложении (не) определенных исключений (т. Е. throw new MyBaseException(ex);): совершенно бессмысленно и неприятный запах. 4


Редактировать

1 Никогда - это очень резкое слово, особенно когда речь идет об инженерии, как отметил @Chris в комментариях. Я признаю, что был высок по принципам, когда я впервые написал этот ответ.

2,3 См. 1 .

4 Если вы не принесете ничего нового на стол, я все равно поддерживаю это. Если вы поймали Exception ex как часть метода, который, как вы знаете, может потерпеть неудачу любым количеством способов, я считаю, что текущий метод должен отразить это в своей сигнатуре. И, как вы знаете, исключения не являются частью сигнатуры метода.

2 голосов
/ 25 сентября 2008

Если я правильно читаю вопрос, я бы сказал, что реализация try / catch, которая перехватывает исключения (вы не упоминаете - перехватывает все исключения или только конкретное?) И выдает другое исключение, как правило, плохая вещь.

Недостатки:

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

Если вы перехватываете Exception, вы рискуете замаскировать критические исключения, такие как OutOfMemory или StackOverflow, с менее критическим исключением и, таким образом, оставить процесс запущенным там, где, возможно, он должен был быть снесен.

Возможные преимущества:

В некоторых очень специфических случаях вы можете взять исключение, которое не имеет большого значения отладки (например, некоторые исключения, возвращаемые из базы данных), и заключить в исключение, которое добавляет больше контекста, например, id объекта, с которым вы имели дело .

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

Как правило, вы должны поймать исключение, только когда есть что-то реалистичное, что вы можете сделать в этом месте - то есть восстановление, откат, переход к плану B и т. Д. Если вы ничего не можете с этим поделать, просто дайте ему пройти вверх по цепочке. Вы должны ловить и выдавать новое исключение только в том случае, если в этом месте имеются конкретные и полезные данные, которые могут увеличить исходное исключение и, следовательно, помочь в отладке.

1 голос
/ 25 сентября 2008

Выезд ELMAH . Это то, о чем ты говоришь. Отлично.

Когда я создаю библиотеки, я стараюсь всегда предоставлять уменьшенное количество исключений для обработчиков. Например, подумайте о компоненте Repository, который подключается к базе данных sql. Есть ТОННЫ исключений, от клиентских исключений sql до недопустимых исключений приведения, которые теоретически могут быть выброшены. Многие из них четко задокументированы и могут быть учтены во время компиляции. Итак, я перехватываю как можно больше из них, помещаю их в один тип исключения, скажем, RepositoryException, и позволяю этому исключению свернуть стек вызовов.

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

Есть, конечно, некоторые проблемы с этим. В частности, если вызывающая сторона может обработать некоторые из этих исключений, они должны найти в RepositoryException и затем включить тип внутреннего исключения, чтобы обработать его. Это менее чисто, чем наличие единственного блока catch для одного типа исключения. Однако я не думаю, что это большая проблема.

1 голос
/ 25 сентября 2008

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

Вот интересный пост о том, как использовать HttpModule для обработки исключений: http://blogs.msdn.com/rahulso/archive/2008/07/13/how-to-use-httpmodules-to-troubleshoot-your-asp-net-application.aspx и http://blogs.msdn.com/rahulso/archive/2008/07/18/asp-net-how-to-write-error-messages-into-a-text-file-using-a-simple-httpmodule.aspx

0 голосов
/ 25 сентября 2008

Исходя из моего опыта, лови исключение, добавляй ошибку к объекту Сервер (?). Это позволит .NET делать то, что ему нужно, а затем отображать ваше исключение.

0 голосов
/ 25 сентября 2008

Похоже, что выбрасываемое исключение не должно быть реализовано как исключение.

В любом случае, я бы сказал, что поскольку это исключение BaseApplicationException является общим универсальным исключением, было бы хорошо выбросить исключения, которые являются более специфичными для контекста. Поэтому, когда вы пытаетесь извлечь сущность из базы данных, вы можете захотеть исключение EntityNotFoundException. Таким образом, при отладке вам не нужно искать внутренние исключения и трассировки стека, чтобы найти реальную проблему. Если это BAseApplicationException собирает информацию об исключении (например, отслеживание внутреннего исключения), то это не должно быть проблемой.

Я бы использовал HttpModule только тогда, когда не мог приблизиться к тому, где на самом деле происходят исключения в коде. Вы на самом деле не хотите, чтобы событие HttModule OnError представляло собой гигантский оператор switch в зависимости от информации об ошибке BaseApplicationexception.

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

...