Handling Errors by Using Try Functions
Try functions in C/AL enable you to handle errors that occur in the application during code execution. For example, with try functions, you can provide more user-friendly error messages to the end user than those thrown by the system.
Behavior and Usage
The main purpose of try functions is to catch errors/exceptions that are thrown by Dynamics NAV or exceptions that are thrown during .NET Framework interoperability operations. Try functions catch errors similar to a conditional Codeunit.Run function call, except try function calls do not require that write transactions are committed to the database, and changes to the database that are made with a try function are not rolled back.
Database write transactions in try functions
Because changes made to the database by a try function are not rolled back, you should not include database write transactions within a try function. By default, the Microsoft Dynamics NAV Server configuration prevents you from doing this. If a try function contains a database write transaction, a runtime error occurs.
Note
This behavior is different from the behavior in Microsoft Dynamics NAV 2016, which did not include this restriction by default. Therefore, you might encounter errors if you have application code that was written for Microsoft Dynamics NAV 2016 and you run the code in Microsoft Dynamics NAV 2017.
In practice, this means that you should not include the following function calls inside a try function scope:
Data Type | Function |
---|---|
Record and RecordRef | - INSERT - MODIFY - MODIFYALL - RENAME - DELETE - DELETEALL - >ADDLINK - DELETELINK - DELETELINKS |
Database | - COMMIT |
If you want to change this behavior, you can set the DisableWriteInsideTryFunctions setting in the CustomSettings.config file of the server instance to false. However, we recommend that you design your code to suit the default behavior instead.
Handling errors with a return value
A function that is designated as a try function has a Boolean return value (true or false), and has the construction OK:= MyTryFunction
. A try function cannot have a user-defined return value.
If a try function call does not use the return value, the try function operates like an ordinary function and errors are exposed as usual.
If a try function call uses the return value in an
OK:=
statement or a conditional statement such asIF-THEN
, errors are caught. The try function returnstrue
if no error occurs;false
is an error occurs.
Note
The return value is not accessible within the try function itself.
Getting details about errors
You can use the GETLASTERRORTEXT Function to obtain errors that are generated by Dynamics NAV. To get details of exceptions that are generated by .NET Framework objects, you can use the GETLASTERROROBJECT Function to inspect the Expection.InnerException property.
Tip
The CRONUS International Ltd. demonstration database includes codeunit 1291 DotNet Exception Handler that includes several global functions for handling exceptions similar to a try-catch capability in C#. You can use this codeunit together with try functions to handle exceptions and maximize the reuse of code.
Creating a Try Function
To create a try function, add a function in C/AL code of an object (such as a codeunit) as usual, and then set the TryFunction Property property to Yes. A try function has the following restrictions:
In test and upgrade codeunits, you can only use a try function on a normal function type, as defined by the FunctionType Property (Test Codeunits) or FunctionType Property (Upgrade Codeunits).
Example 1
The following simple example illustrates how the try function works. First, create a codeunit that has a local function MyTryFunction
. Add the following code on the OnRun
trigger and MyTryFunction
function.
OnRun()
MyTryFunction;
MESSAGE('Everthing went well.');
LOCAL MyTryFunction()
ERROR('An error occurred during the operation.');
When you run this codeunit, the execution of the OnRun
trigger, the calling function, stops and the error message An error occurred during the operation.
is thrown in the client.
Now, set the TryFunction property of the MyTryFunction
function to Yes. Then, add code to the OnRun
trigger to handle the return value of the try function:
OnRun()
IF MyTryFunction THEN
MESSAGE('Everying went well.')
ELSE
MESSAGE('Something went wrong.');
LOCAL [TryFunction] MyTryFunction()
ERROR('An error occurred during the operation.');
When you run the codeunit, instead of stopping the execution of the OnRun
trigger when the error occurs, the error is caught and the message Something went wrong.
is returned.
Example 2
The following example illustrates how to use a try function with .NET interoperabilty. The example uses the System.Decimal.Divide method to divide two decimals.
First, create a codeunit that has a local function MyTryFunction
, and add the following text constants and variables:
Text constant name | ConstValue |
---|---|
Text000 | %1 divided by %2 equals %3. |
Text001 | You cannot divide by %1. |
Variable name | DataType | Subtype |
---|---|---|
divide | DotNet | System.Decimal.'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' |
d1 | Decimal | |
d2 | Decimal | |
result | Decimal |
Then, add the following code on the OnRun
trigger and MyTryFunction
function.
OnRun()
IF MyTryFunction THEN
MESSAGE(Text000, d1, d2, result)
ELSE
MESSAGE(Text001, d2);
LOCAL MyTryFunction()
d1 := 3;
d2 := 0;
result := divide.Divide(d1,d2);
When you run this codeunit, an error occurs because you are not allowed to divide by 0
. The message You cannot divide by 0.
is displayed in the client.