Search
Write a publication
Pull to refresh
476.16
OTUS
Развиваем технологии, обучая их создателей

Обработка исключений в 1С

Reading time6 min
Views2.3K

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

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

А может не надо

В целом, 1С рекомендует не перехватывать исключения. Например, зачастую разработчики перехватывают исключения для того, чтобы отобразить сообщение об ошибке. Это позволяет понять на каком шаге работы алгоритма произошел сбой.

Однако платформа 1С автоматически выводит сообщение об ошибке для каждого не перехваченного исключения и вы и так получите сообщение о том, по какой причине сработало исключение.

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

Хорошей рекомендацией является обязательная запись сообщений об ошибках в журнал событий. В результате это сообщение не потеряется и у вас будет точное время, когда произошла данная ошибка. А для пользователей можно отображать краткое описание для пользователей.

Рассматриваем примеры

В первом примере бизнес‑логика сервера вызывается клиентом во время интерактивного взаимодействия с пользователем:

//на клиенте
Procedure PerformAction()
    // Код, вызывающий ошибку

    ...

EndProcedure

В этом блоке с кодом нам необходимо добавить обработчик исключения. Логичным было бы использовать следующую конструкцию:

// на клиенте

Try

    PerformAction();

Except

    DoMessageBox("Cannot perform the action.");

EndTry;

Однако, ограничиваться выводом сообщения только на клиенте не стоит, так как этого явно недостаточно для последующей отладки. Более правильным будет следующий вариант:

//на сервере

Procedure PerformAction()

Try

  // Код, вызывающий ошибку
         ...

Except

    // Запись события в журнал

  WriteLogEvent(NStr("en = 'Performing action'"),
    EventLogLevel.Error, , ,
    DetailErrorDescription(ErrorInfo()));
  Raise;

EndTry;

EndProcedure

И на клиенте:

Try

PerformAction();

Except

  MessageText = BriefErrorDescription(ErrorInfo());
  DoMessageBox(NStr("en = 'Cannot perform the action. Reason:'" + Chars.LF + MessageText);

EndTry;

Теперь рассмотрим другой пример. У клиента реализована какая‑то логика при сохранении файла на диск:

//На клиенте

Procedure CreateFileOnDisk()

    // Код, вызывающий ошибку

    ...

EndProcedure

Здесь рекомендуется сделать дополнительный вызов сервера для регистрации неудачного выполнения операции в журнале событий:

//на клиенте

Try

    // Код, вызывающий ошибку
    CreateFileOnDisk();

Except

    MessageText = BriefErrorDescription(ErrorInfo());
    DoMessageBox(NStr("en = 'Cannot perform the action. Reason:'") + Chars.LF + MessageText);
    WriteFileOperationError(DetailErrorDescription(ErrorInfo()));

EndTry;

 
//на сервере

Procedure WriteFileOperationError(...)

    WriteLogEvent(NStr("en = 'Performing action'"),

        EventLogLevel.Error, , ,
        DetailErrorDescription(ErrorInfo()));

EndProcedure

Вообще, хорошей практикой должно стать правило не перехватывать исключения без его фиксации в журнале событий:

Try

    // Код, вызывающий ошибку
    ...

Except

    // Перехват исключения

EndTry;

Как правило, такие конструкции создают проблемы, которые невозможно обнаружить. Правильным был бы следующий вариант написания кода:

Try

    // Код, вызывающий ошибку

    ...

Except

    // Комментарий, объясняющий, почему исключение было поймано без уведомления конечных пользователей.

    // ... 

    // Запись в журнал событий.

    WriteLogEvent(NStr("en = 'Performing action'"),

        EventLogLevel.Error, , ,
        DetailErrorDescription(ErrorInfo()));

EndTry;

Еще одна рекомендация по работе с исключениями: не используйте исключения для проверки доступности атрибутов объектов, методов, шаблонов и так далее. Это может привести к ошибкам, которые трудно обнаружить, а также усложнит отладку в режиме «Остановка при ошибках», используемом в 1С:EDT.

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

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

Давайте рассмотрим неправильный вариант реализации:

Try

    ContextERPServer.GetTemplate("ExchangeComponent");

    Path = ContextERPServer.PathToObject + ".Template.ExchangeComponent");

Except

EndTry;

Более правильным вариантом реализации будет следующий:

ExchangeComponentTemplate = ContextERPServer.Metadata().Templates.Find("ExchangeComponent");

 If ExchangeComponentTemplate <> Undefined Then

    PathToTemplate = ExchangeComponent.FullName();

EndIf;

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

Далее поговорим о транзакциях. Внутри транзакций рекомендуется использовать следующий формат обработки исключений:

BeginTransaction();

Try

    Query = New Query("...");

    Selection = Query.Execute().Select();

    While Selection.Next() Do

        ...

    EndDo;

    CommitTransaction();

Except

    RollbackTransaction();

    WriteLogEvent(NStr("en = 'Performing action'"),
        EventLogLevel.Error, , ,
        DetailErrorDescription(ErrorInfo()));
    Raise;

EndTry;

Поскольку исключение не приводит к немедленному откату транзакции, а запрещает ее фиксацию, каждый из вызовов BeginTransaction должен иметь соответствующий вызов CommitTransaction или RollbackTransaction.

Заключение

В этой статье мы рассмотрели несколько рекомендаций по работе с исключениями в 1С. Основным является то, что если вы используете исключение, то обязательно фиксируйте его срабатывание в журнале событий. И в некоторых случаях иногда бывает лучше вообще не использовать исключения.


Если вы работаете с 1С и стремитесь системно подходить к проектированию и сопровождению решений, приглашаем вас на серию открытых уроков курса «Архитектор 1С». Это возможность ознакомиться с подходами, инструментами и практиками, которые применяются в современной архитектуре систем на базе 1С.

30 июля в 19:00«Как документировать сервисы 1С по OpenAPI (Swagger)?». На этом уроке разберём, как описывать интерфейсы ваших сервисов в удобном и читаемом формате.

13 августа в 19:00 — «Yaxunit как инструмент автоматизированной валидации API по схеме OpenAPI». Участники узнают, как использовать Yaxunit для проверки соответствия сервисов заявленным спецификациям.

19 августа в 19:00 — разбор темы «Проектирование архитектуры систем предприятия в интеграциях с 1С», где будет представлен подход к построению архитектуры с учётом взаимодействия 1С с внешними системами.

Также доступно вступительное тестирование, позволяющее проверить понимание тем и оценить уровень ваших навыков.

Tags:
Hubs:
+2
Comments12

Articles

Information

Website
otus.ru
Registered
Founded
Employees
101–200 employees
Location
Россия
Representative
OTUS