Catching exceptions


<< Prev   Next >>

Scope: managed applications, mobile applications, and ordinary applications.

1. Generally, you should not catch exceptions. Specifically, do not catch exceptions just to display the error messages. Unhandled exceptions are displayed as error messages. Their details are also recorded to the event log and sent to the error reporting service.

2. However, there are cases exceptions should be caught. For example, when you want to complement an error message with some details to make it more meaningful and clear to the user. It is recommended that you also log the error details to help the system administrator with troubleshooting.

The detailed description is added to the event log and the brief description is displayed to the user.

3. Improper exception catching.

Scope: managed applications, ordinary applications.

3.1. For applications where interactive operations call business logic on the server side:

&AtServer
 Procedure ExecuteOperation()
 // Code that throws an exception.
 ....
 EndProcedure

Incorrect: conceal the details about the issue from the user and system administrator.

// On the client side.
 Try
 ExecuteOperation();
 Except
 ShowMessageBox(,NStr("en = 'Operation failed.'"));
 EndTry;

Correct: log the detailed description of the exception and display the brief description to the user.

&AtServer
 Procedure ExecuteOperation()
 Try
 // Code that throws an exception.
 ....
 Except
 // Add the exception details to the event log.
 WriteLogEvent(NStr("en = 'Executing operation.'"),
 EventLogLevel.Error,,,
 ErrorProcessing.DetailErrorDescription(ErrorInfo()));
 Raise;
 EndTry;
 EndProcedure

Client side:

Try
 ExecuteOperation();
 Except
 MessageText = BriefErrorDescription(ErrorInfo());
 ShowMessageBox(,NStr("en = 'Operation failed. Reason:'") + Chars.LF + MessageText);
 EndTry;

Avoid using the ErrorDescription function as it does not provide relevant information for developers, such as the stack trace in the error text.

3.2. Do not analyze the text of exceptions to interpret the error data. The text of exception might vary depending on its location. If standard features—such as typed exceptions—are not available, display the details "as is." For better user experience, complement it with a list of possible reasons.
Example:

Try
 DownloadFile(...);
 Except
 MessageText = BriefErrorDescription(ErrorInfo());
 MessageText = NStr("en = 'Cannot load the file:'") + Chars.LF + MessageText + Chars.LF + NStr("en = 'Possible reasons:
 • No Internet connection
 • Web site issues
 • Firewall or antivirus blocks outgoing traffic
 • Wrong proxy parameters'");
 ShowMessageBox(,MessageText);
 EndTry;

If analysis of exception types is critical for the proper operation of business logic, use error codes instead of exception types. Do not use numeric error codes:

ErrorCode = DownloadFile(...);
 If ErrorCode = 12345 Then
...
 ElsIf ...

Use alphabetic human-readable codes, such as "Successfully", "NoSpace", and "Canceled":

ImportResult = DownloadFile(...);
 If ImportResult = "Successfully" Then
...
 ElsIf ...

Error code strings are not localizable.

This requirement does not apply to the cases when error codes are not available, such as web services and external systems, and operation results are transferred to the caller in the form of exceptions.

3.3. For applications where all business logic is implemented on the client side:

&AtClient
 Procedure CreateFileOnDisk()
 // Code that throws an exception.
 ....
 EndProcedure

Correct: make a server call to log the exception.

Try
 // Client code that throws an exception.
 CreateFileOnDisk();
 Except
 MessageText = BriefErrorDescription(ErrorInfo());
 ShowMessageBox(,NStr("en = 'Operation failed. Reason:'") + Chars.LF + MessageText);
 WriteFileHandlingError(ErrorProcessing.DetailErrorDescription(ErrorInfo()));
 EndTry;

&AtServerNoContext
 Procedure RegisterFileHandleError(...)
 WriteLogEvent(NStr("en = 'Executing operation.'"),
 EventLogLevel.Error,,,
 DetailErrorDescription);
 EndProcedure

3.4. Details about any exception caught must be provided to the system administrator. Incorrect:

Try
 // Code that throws an exception.
 ....
 Except // Catch exceptions.
 EndTry;

This code does not provide any details about the issues, which makes troubleshooting more complicated.
Correct:

Try
 // Code that throws an exception.
 ....
 Except
 // Explain why exceptions are non-displayed to the user.
 // ....
 // Log the exception details for the system administrator.
 WriteLogEvent(NStr("en = 'Executing operation.'"),
 EventLogLevel.Error,,,
 ErrorProcessing.DetailErrorDescription(ErrorInfo()));
 EndTry;

See also: Temporary files and directories in Accessing file system programmatically.

3.5. 3. In object events like OnWrite, BeforeWrite, BeforeDelete, Posting, FillCheckProcessing, and others, do not throw exceptions to raise warning messages to be handled by users. Instead, set the Cancel parameter to True and display a message to the user. This ensures that the user sees all the failure reasons at once, rather than one by one.

However, if the user cannot handle the warning during the ongoing operation, or the error situation is exceptional and renders other checks producing warnings meaningless, an exception must be thrown.

Procedure BeforeWrite(Cancel)
If Not RegisterChangesOnExchangePlanNodes() Then
Raise NStr("en = 'Failed to register changes on exchange plan nodes. Contact the administrator.'");
EndIf;
...
EndProcedure

For more information, see items 1.1 and 1.3 in User notifications.

3.6. Do not use exceptions to validate object's attributes, methods, templates, and so on. This makes error traceability and "Stop on error" debugging more complicated.
 Instead, adopt one of the following practices:

  • Use metadata management tools that allow you to explicitly check objects for attributes, methods, templates, and so on.
  • For embedded libraries, specify the order of integration in the overridable modules. See Overridable and non-overridable library objects.
  • Reconsider the behavior of methods that catch the exceptions. For example, you can add parameters that determine whether a method or object property will be called.

Incorrect:

Try
 ContextEDIServer.GetTemplate("ExchangeAddIn");
 AddInPath = ContextEDIServer.ObjectPath + ".Template.ExchangeAddIn";
 Except
 EndTry;

Correct:

ExchangeAddInTemplate = ContextEDIServer.Metadata().Templates.Find("ExchangeAddIn");
 If ExchangeAddInTemplate <> Undefined Then
 TemplatePath = ExchangeAddIn.FullName()
EndIf;

3.7. For handling exceptions in transactions, see Transaction guidelines.

3.8. Do not use exceptions to convert a value to a type. Instead, use TypeDescription.

Incorrect:

Try
 PermissionDaysCount = Number(Value);
 Except
 PermissionDaysCount = 0; // Default value
 EndTry;

Correct:

TypeDetails = New TypeDescription("Number");
 PermissionDaysCount = TypeDetails.AdjustValue(Value);

See also:

<< Prev   Next >>

Icon/Social/001 Icon/Social/006 Icon/Social/005 Icon/Social/004 Icon/Social/002