What’s New in “ErrorInfo datatype” for Microsoft Dynamics Business Central for Developers

Usage:

  • This blog shows to use error messages in different ways possible.
  • If you’re developing App for AppSource and want to give more detailed error message plus advanced capabilities to solve the error by end-users on their own.

Use Cases with examples:

1. ErrorInfo.Create (not a data type but as a direct function)-

  • When used with Error() do not make any difference and will show below error.
pageextension 50100 CustomerListExt extends "Customer List"
{
    trigger OnOpenPage();
    begin
        Error('App published: Hello world');
        //OR
        Error(ErrorInfo.Create('App published: Hello world'));
    end;
}
  • Output:

2. ErrorInfo (as a data type with MessageType as Client)-

  • Purpose: To show the specific error message same as above use case and sends to telemetry.
  • Code:
pageextension 50100 CustomerListExt extends "Customer List"
{
    trigger OnOpenPage();
    begin
        // Error(InitialMsg);
        // Error(ErrorInfo.Create(InitialMsg));
        InitializeClientError();
    end;

    local procedure InitializeClientError()
    var
        InitializeErrorInfo: ErrorInfo;
    begin
        InitializeErrorInfo.DataClassification(DataClassification::SystemMetadata);
        InitializeErrorInfo.ErrorType(ErrorType::Client);
        InitializeErrorInfo.Verbosity(Verbosity::Error);
        InitializeErrorInfo.Message(InitialMsg);
        Error(InitializeErrorInfo);
    end;

    var
        InitialMsg: Label 'App published: Hello world';
}
  • Output: Same as case # 1.

3. ErrorInfo (as a data type with MessageType as Internal)-

  • Purpose: To show some generic error message same as above use case and sends to telemetry. Mainly for developers track this error message.
  • Code:
pageextension 50100 CustomerListExt extends "Customer List"
{
    trigger OnOpenPage();
    begin
        InitializeInternalError();
    end;

    local procedure InitializeInternalError()
    var
        InitializeErrorInfo: ErrorInfo;
    begin
        InitializeErrorInfo.DataClassification(DataClassification::SystemMetadata);
        InitializeErrorInfo.ErrorType(ErrorType::Internal);
        InitializeErrorInfo.Verbosity(Verbosity::Error);
        InitializeErrorInfo.Message(InitialMsg);
        Error(InitializeErrorInfo);
    end;

    var
        InitialMsg: Label 'App published: Hello world';
}
  • Output:

4. ErrorInfo (with Title)-

  • Purpose: To show some error message with a title.
  • Code:
pageextension 50100 CustomerListExt extends "Customer List"
{
    trigger OnOpenPage();
    begin
        InitializeClientError();
    end;

    local procedure InitializeClientError()
    var
        InitializeErrorInfo: ErrorInfo;
        ErrorTitleLbl: Label 'Initializing error.';
    begin
        InitializeErrorInfo.DataClassification(DataClassification::SystemMetadata);
        InitializeErrorInfo.ErrorType(ErrorType::Client);
        InitializeErrorInfo.Verbosity(Verbosity::Error);
        InitializeErrorInfo.Message(InitialMsg);
        InitializeErrorInfo.Title(ErrorTitleLbl);
        Error(InitializeErrorInfo);
    end;

    var
        InitialMsg: Label 'App published: Hello world';
}
  • Output:

5. ErrorInfo (with Action)-

  • Purpose: To show some error message with a action and title.
  • Code:
    • Add InitializeErrorInfo.AddAction(UpdateLbl, Codeunit::”Update MNK”, ‘UpdateOnCustomer’);
local procedure InitializeClientError()
    var
        InitializeErrorInfo: ErrorInfo;
        ErrorTitleLbl: Label 'Initializing error.';
        UpdateLbl: Label 'Make Update';
    begin
        InitializeErrorInfo.DataClassification(DataClassification::SystemMetadata);
        InitializeErrorInfo.ErrorType(ErrorType::Client);
        InitializeErrorInfo.Verbosity(Verbosity::Error);
        InitializeErrorInfo.Message(InitialMsg);
        InitializeErrorInfo.Title(ErrorTitleLbl);
        InitializeErrorInfo.AddAction(UpdateLbl, Codeunit::"Update MNK", 'UpdateOnCustomer');
        Error(InitializeErrorInfo);
    end;
codeunit 50100 "Update MNK"
{
    trigger OnRun()
    begin
    end;

    procedure UpdateOnCustomer(ErrorInfo: ErrorInfo)
    var
        SomeProcessesLbl: Label 'Some process or data updates here.';
    begin
        Message(SomeProcessesLbl);
    end;
}
  • Output:

6. ErrorInfo (with Navigation)-

  • Purpose: To show some error message with a navigation, action and title.
  • Code:
    • Add InitializeErrorInfo.AddAction(UpdateLbl, Codeunit::”Update MNK”, ‘UpdateOnCustomer’);
local procedure InitializeClientError()
    var
        InitializeErrorInfo: ErrorInfo;
        ErrorTitleLbl: Label 'Initializing error.';
        UpdateLbl: Label 'Make Update';
        ActualUpdateLbl: Label 'Make Actual Update';
        NavigateToCardLbl: Label 'Open Card';
    begin
        InitializeErrorInfo.DataClassification(DataClassification::SystemMetadata);
        InitializeErrorInfo.ErrorType(ErrorType::Client);
        InitializeErrorInfo.Verbosity(Verbosity::Error);
        InitializeErrorInfo.Message(InitialMsg);
        InitializeErrorInfo.Title(ErrorTitleLbl);

        //Add actions using another codeunit
        InitializeErrorInfo.AddAction(ActualUpdateLbl, Codeunit::"Update MNK", 'ActualUpdateCustomer');

        //Add navigation action using another codeunit
        Rec.FindFirst();
        InitializeErrorInfo.PageNo(Page::"Customer Card");
        InitializeErrorInfo.FieldNo(Rec.FieldNo(Blocked));
        InitializeErrorInfo.RecordId(Rec.RecordId);
        InitializeErrorInfo.AddNavigationAction(NavigateToCardLbl);
        Error(InitializeErrorInfo);
    end;
codeunit 50100 "Update MNK"
{
    trigger OnRun()
    begin

    end;

    procedure ActualUpdateCustomer(ErrorInfo: ErrorInfo)
    var
        Customer: Record Customer;
    begin
        Customer.FindFirst();
        if Customer.Blocked = Customer.Blocked::" " then
            Customer.validate(Blocked, Customer.Blocked::All)
        else
            Customer.validate(Blocked, Customer.Blocked::" ");
        Customer.Modify();
    end;
}
  • Output:

Important Notes:

  • You cannot have two actions at the same time.
  • Any actions you put should have reference to global function of that Codeunit.
  • Try other functions like DetailedMessage for Telemetry.
References:

New Feature to “Add Item tracking lines from Item Journal lines” on Microsoft Dynamics Business Central (aka from v22.0)

Scenario:

  • It was hard to insert item tracking lines for item journals as they are saved in different table. Plus going to each journal lines and then inserting a lot/serial is a huge manual task.

Before Enabling:

  • The user needs to click on Item Tracking Lines and then enter Lot/Serial for that item (which needs to be done for all items if list is huge):

Solution:

  • On journal batches, enable the setup as shown in below snapshot.

After Enabling:

  • Four fields (highlighted below) would be shown on Item Journals Line (you must have seen them in Item Reclassification Journals).
  • Entering the data or uploading the data here allows to create a Item Tracking Lines in background.
  • This helps in uploading opening inventories in easier manner for items with lots / serials.
  • Same feature is available on Warehouse physical journal. Give it a try!!

Reference:

How-To “Hide the Page Inspection or Zoom for users” in Microsoft Dynamics Business Central

Scenario:

  • Users by default are allowed to access the data of Microsoft Dynamics Business Central (BC) which they can view the table or check the values which we some installations may not need.

Before Changes:

  • Users can access the said details either by pressing the [Ctrl] + [Alt] + [F1] on their keyboard or by going to ‘Help and Support’ -> ‘Inspect Pages and Data’
  • The screen looks something like shown below:

Solution:

  • Create a new Permission Set in BC as shown below:1
TypeObject TypeObject IDObject Name
ExcludeSystem1350Run Table
ExcludeSystem5330Tools, Zoom
Permissions under new Permission Set create.
  • Assign the permissions to the users and ask them to re-login in BC.

After Changes:

  • Now ask users to re-login to BC and they will not see the data under Page Inspection. The screen would look like below:

References:

  1. Define Granular Permissions – Business Central | Microsoft Learn ↩︎

Microsoft Dynamics Business Central (On-Premise) – DocFx – simple help generator

Scenario:

This blog is to give small idea, hint or knowledge on how you can use DocFx for generating a simple static documentation portal.

Just to give the idea, this same tool is used by Microsoft for maintaining ‘https://docs.microsoft.com‘ hosted on GitHub. I will be showing, and hosting pages created using DocFx on App server instead of using WordPress / Github page or other provider for hosting the help manual.

Pre-requisites:

  • Markdown language
  • YAML/JSON understanding
  • DocFx (from Github) – The same can be installed using Nuget or Chocalatey package (which is NOT shown on this post)
Read more: Microsoft Dynamics Business Central (On-Premise) – DocFx – simple help generator

Why use DocFx:

  • Cross-platform support. (Also runs on MacOS and Linux, hence easy to deploy using Pipelines)
  • Custom or multiple themes supported.
  • Easy to coordinate and maintain on repos.
  • Seamless integration with your source code (for examples, any APIs published). You can allow to view source code on an API.

Getting Started with Templates:

  • After you download docfx.zip from provided reference link (below), extract it to a local folder.
  • You can create a first project by typing below commands on PowerShell (make sure that you on folder where docfx.exe exists):
    • docfx init -q
  • Alternatively, if you wanted to host or create project folder at /inetpub/wwwroot/<folder> you can type same above command as follows:
    • docfx init -o “/inetpub/wwwroot/<folder>” -q
  • On running this command, DocFx creates a basic default template folder with api, apidoc and articles folders plus contents.

Getting Started with Building website:

  • Run below command on PowerShell to check default template:
    • docfx.exe "/inetpub/wwwroot/<folder>/docfx.json" --serve -p <port_number>
  • After a without error run, the pages are created and can be checked on localhost as shown below (this will only run until serve command is running):

Getting Started with updating contents on website:

  • Now as you are confident on using DocFx and building website, try updating/adding new .md files and then run DocFx build command.
  • Make sure you give correct ‘image’ or media path for them to be included on website.
  • If you have more media folders on DocFx, add them in Docfx.json file as well:

Tips:

  • You should be good to track your folders with pages (hence use repos to make sure you don’t lose or add anything wrong).
  • For adding a search bar, add “ExtractSearchIndex” in “globalMetadataFiles” in docfx.json
Before changeAfter change
“postProcessors”: []“postProcessors”: [“ExtractSearchIndex”]
  • DO NOT change docfx.json without a proper knowledge.
  • Use help command or access ‘http://dotnet.github.io/‘ for more details and walkthroughs.

References:

Let me know on how useful this tutorial was and I will extend to show BC APIs functionality on DocFX.