Collectible Errors?!

by Jul 16, 2022AL Language

Home 9 Development 9 AL Language 9 Collectible Errors?!

Collectible Errors?!

It has been already almost a year since ErrorInfo datatype & CollectibleErrors were introduced (I already have an article about basic structure: ErrorInfo data type & Collectible Errors). This article was released for the first time in September 2021 before this functionality was publicly available. Since then, there have been some changes and fixes I have already added to the original article.

Today, I want to look at some examples and see how to use collectible errors, how it differs from standard errors we have known for years, and how to use it. Later (probably in two separate articles in the upcoming weeks), I’ll show you more advanced examples of collectible errors (with the rest of the parameters) and some examples of actual usage of collectible errors and also how (and where) it is already used in the Base App.

Examples

Standard Errors

Let’s start with a basic example, with the standard error (..) procedure we all know and have used for ages. The example below is easy; calling the procedure will raise the first Error, and the whole process stops. The second Error won’t be executed (and warning AA0136 will be shown).

local procedure Error1()
begin
    Error('Test error 1');
    Error('Unreachable code.');
end;

In the example below, we get the same result with the ErrorInfo data type. In this type, we use the new Error(ErrorInfo) method (the difference is that the “old” method accepts text as a parameter, this new, overloaded method accepts ErrorInfo data type). But the result is absolutely the same – the first Error is raised once the method is called, and the second Error is unreachable.

local procedure Error2()
begin
    Error(ErrorInfo.Create('Test error 2'));
    Error(ErrorInfo.Create('Unreachable code.'));
end;

Collectible Errors

To start using collectible errors, we have to be familiar with two terms.

The procedure that should use CollectibleErrors needs to be decorated with the ErrorBehavior attribute ([ErrorBehavior(Behavior: ErrorBehavior)]). Right now, the only value available for ErrorBehavior enum is Collect. So if you want to enable collectible errors for a specific method, write [ErrorBehavior(ErrorBehavior::Collect)] before the procedure. If you do not want collectible errors (= want the standard error behavior when the error is raised once the line with Error is executed) simply do not use this parameter.

However, even with this parameter, errors will still be raised once the code executes them. So the example below is still the same even with [ErrorBehavior(ErrorBehavior::Collect)] and both Error(Text) and Error(ErrorInfo) methods work in the same way.

[ErrorBehavior(ErrorBehavior::Collect)]
local procedure Error3()
begin
    Error(ErrorInfo.Create('Test error 3'));
    Error(ErrorInfo.Create('Unreachable code.'));
end;

// OR

[ErrorBehavior(ErrorBehavior::Collect)]
local procedure Error3B()
begin
    Error('Test error 3');
    Error('Unreachable code.');
end;

So what’s the second term I said you need to be familiar with?

It’s “Collectible“! Because only errors marked as Collectible are collected in methods defined with [ErrorBehavior(ErrorBehavior::Collect)]. How to define Error as collectible? It’s easy, but there is a difference between Error(Text) and Error(ErrorInfo) methods – only the second one, Error(ErrorInfo), can be set as Collectible. It’s the second parameter in ErrorInfo.Create() method just after the text of the Error.

The example below shows how to use collectible errors properly.

[ErrorBehavior(ErrorBehavior::Collect)]
local procedure Error4()
begin
    Error(ErrorInfo.Create('Test error 4', true));
    Error(ErrorInfo.Create('Test error 5', true));
end;

And how does it look from the user’s side? It seems like a standard error – the user sees there is something wrong. The message is also pretty clear – “Multiple errors occurred during the operation, the first of which is: Test error 4. All errors can be found under ‘Detailed Information’.“. As stated, under detailed information, all errors can be found. Below is the log from the error (it’s what you get once you use the “Copy information to clipboard” link in error).

/*
Multiple errors occurred during the operation the first of which is: Test error 4. All errors can be found under 'Detailed Information'.

Test error 4
Test error 5

Internal session id: 
5296a108-3f8a-4514-ae4f-a54d9a2e1947

Application Insights session id: 
ce4a57d4-1172-470c-bcee-381882638a19

Client activity id: 
0282fb25-8950-6759-064d-01cb9db6a4ab

Timestamp: 
2022-07-15T08:31:28.2756526Z

AL call stack: 
"TKA Collectible Errors Mgt."(CodeUnit 69000).Error4 line 5 - Collectible Errors by Kepty.cz, Ing. Tomas Kapitan
"TKA Collectible Errors Mgt."(CodeUnit 69000).Try line 11 - Collectible Errors by Kepty.cz, Ing. Tomas Kapitan
"TKA Customer List"(PageExtension 69900).OnOpenPage(Trigger) line 4 - Collectible Errors by Kepty.cz, Ing. Tomas Kapitan
*/

The last thing I want to cover in this article is the TestFields() method. Even this method can be used as Collectible. You are definitely familiar with the method Record.TestField(Field, [Value]) where [Value] is the value the field should have. If omitted, the method tests that the Field is not blank.

The error from this method (as the example below) can not be collected, so the error in the example is unreachable!

[ErrorBehavior(ErrorBehavior::Collect)]
local procedure Error5()
var
    Customer: Record Customer;
begin
    Customer.FindFirst();
    Customer.TestField(Name, '');

    if Customer.Name <> '' then
        Error(ErrorInfo.Create('Unreachable code.', true));
end;

To be able to collect TestFields() errors, we need to use the new method Record.TestField(Field, Value, ErrorInfo) or Record.TestField(Field, ErrorInfo). These two methods accept as the last parameter instance of ErrorInfo and use the setting from this ErrorInfo. That means, if ErrorInfo is set as Collectible, the TestField() itself is set as Collectible.

To create a new collectible instance of ErrorInfo, we can set it manually (MyErrorInfo.Collectible := true) or use ErrorInfo.Create() method (WITHOUT ANY PARAMETER!) which returns an empty ErrorInfo object that is set as Collectible.

One thing to remember – ErrorInfo.Create() is by default set as Collectible, however, ErrorInfo.Create(‘My own error’) is by default set as NonCollectible and you need to specify second parameter ErrorInfo.Create(‘My own error’, true) to create ErrorInfo as collectible!


[ErrorBehavior(ErrorBehavior::Collect)]   
local procedure Error6()
var
    Customer: Record Customer;
begin
    Customer.FindFirst();
    Customer.TestField(Name, '', ErrorInfo.Create());

    if Customer.Name <> '' then
        Error(ErrorInfo.Create('This error will be raised all times when TestField error will be raised.', true));
end;

Recent Articles from the category

Connect to Azure Function in BC 2022 wave 2 (v21)

Connect to Azure Function in BC 2022 wave 2 (v21)

The new version of the Microsoft Dynamics 365 Business Central brought a new system module "Azure Functions" that makes integration with Azure Functions much easier and straightforward. The typical scenario, why to use Azure Functions together with Business Central,...

read more
Collectible Errors?! Is it already in use?

Collectible Errors?! Is it already in use?

Collectible Errors?! Is it already in use? This is the second part of my new article series about Collectible Errors. Let's check out the first part here: Collectible Errors?! | Microsoft Dynamics 365 - Ing. Tomáš Kapitán (kepty.cz) or you might be interested in my...

read more
Substituting standard reports

Substituting standard reports

Report objects cannot be extended in versions previous to the Business Central 2021 release wave 1 version when ReportExtensions object was introduced. Since then, many of changes we need to do in reports can be done without creating a new copy of object. On the other...

read more
Isolated events

Isolated events

With Business Central 2022 wave 1, a new setting for event publishers was introduced. Until this version, any error in any event subscriber caused interruption to the current running process and stopped the whole activity. In some cases (such as log-in), this is...

read more
Custom Filter Tokens

Custom Filter Tokens

As a user of the Business Central you have some constants you can use to filter or insert values. These constants contain useful values for data manipulation such as t / today for date field - return current dateq / quarter for date field filters - return range of the...

read more
1D & 2D Barcodes in Business Central 19.1

1D & 2D Barcodes in Business Central 19.1

Business Central (cloud-only!) includes one-dimensional (1D) barcode fonts since Microsoft Dynamics 365 Business Central 2020 wave 2 (17.0) was released in October 2020. It is a great improvement to how developers can handle requirements from their clients to print...

read more
How to let users choose field(s) properly

How to let users choose field(s) properly

When some complex functionality is developed, it is sometimes necessary to let users choose a specific field. This can be required for field permissions, mapping imported values or any similar process. Earlier, the usual way was to create a link on the Field table...

read more

Sign Up for News

Certifications

Highest certification
Microsoft Data Management and
also in D365 Business Central

Microsoft Certified: Dynamics 365 Business Central Functional Consultant Associate

See other certifications here