AL Language extension for Microsoft Dynamics 365 Business Central version 16.2.1869542 (New version)

[ESP] En el siguiente enlace puedes ver leer los cambios relacionados a la versión vigente:

[ENG] En el siguiente link, you can read the changes related to the current version:


16.2

Miscellaneous


16.1

Reporting


16.0

Support for new ExtendedDataType value: Document

Allow copying nodes in the profile editor and support for hovering

In the profile editor, individual nodes can be copied and hovered to show the full text of the node. This allows for easier editing of long nodes, such as SQL queries.

Cancel publish and package commands

Publishing and packaging AL applications can now be canceled from the Visual Studio Code UI.

New Business Central Themes for Visual Studio Code

We are excited to introduce two new themes: Business Central Light and Business Central Dark. These themes prominently feature our favorite color; teal, and are included in the .vsix package. We hope you enjoy the refreshed look and feel they bring to your development experience!

ALDoc: Improvements

Namespaces can now be documented and when they are, an «Overview» entry is added in the table of contents. The overview includes objects and events from the namespace. The recommended way to document a namespace is to include a source file named after the namespace with ‘.Namespace.al’ appended just containing the documentation and the namespace declaration as the example below:

/// <summary>
/// Summary of the namespace functionality
/// </summary>
/// <remarks>
/// Some clever remarks
/// </remarks>
namespace MyCompany.MyNamespace;

The aldoc tool is updated to support the latest version of DocFx (2.78.3) when generating the docfx.json file. Existing documentation folders can be updated with the following command:

aldoc refresh -o <doc folder>

which adds a "_disableToc": false setting to the globalMetadata of the docfx.json file and refreshes the Business Central docfx templates.

Summary System Part Support

With this release, we Introduce a new system part of type Summary that can be controlled on CardDocument, and ListPlus pages. This allows developers to hide or configure the Summary factbox when it’s not needed.

Control the Summary part in page extensions using the identifier DefaultSummaryPart:

pageextension 50101 MyPageExtension extends "Customer Card"
{
    layout
    {
        modify(DefaultSummaryPart)
        {
            Visible = false;
        }
    }
}

Or, define it explicitly in new pages like this:

page 50101 MyPage
{
    layout
    {
        area(FactBoxes)
        {
            systempart(DefaultSummaryPart; Summary)
            {
                Visible = false;
            }
        }
    }
}

Note that there can only be one summary system part per page.

ALTool: New «compile» Command Support

ALTool now supports invoking alc for compiling AL packages. The syntax is:

altool compile <alc arguments>
AL compile <alc arguments>

The AL command acts as a convenient alias for ALTool when installed via the NuGet package.

To explore all available commands for ALTool (or AL alias), run the tool without any arguments. Currently supported commands include:

CommandDescription
compileCompile a package using alc.exe.
GetPackageManifestRetrieve the manifest from a .app file.
CreateSymbolPackageCreate a symbol-only package from a .app file.
GetLatestSupportedRuntimeVersionGet the latest supported AL runtime version for a platform version.
helpDisplay detailed information about a specific command.
versionDisplay version information.

This enhancement streamlines the AL development process, especially in CI/CD pipelines, by providing a more accessible and efficient way to compile AL packages.

Go To Symbol in Workspace

The Visual Studio Code feature «Go To Symbol In Workspace» (Ctrl + T) has been extended to search for a broader range of AL symbols. In addition to application objects, it now includes procedures, events, global variables, page controls, page actions, table fields, and many more.

This new way of searching can be disabled under the setting «al.extendGoToSymbolInWorkspace.enabled». In addition, you can configure the maximum amount of symbols to display with the «al.extendGoToSymbolInWorkspace.ResultLimit» setting. Use the «al.extendGoToSymbolInWorkspace.IncludeSymbolFiles» setting to specify if the search should include the dependencies symbol files.

RecordRef – Get field by name

New overloads are added to the Field and FieldExist methods, which allows searching for a field by its name.

Editable fields in page customizations

You can now make page fields defined in page customizations editable. Previously, such fields were always read-only, unlike fields declared in pages or page extensions.

pagecustomization MyPageCust customizes MyPage
{
    layout
    {
        addfirst(Content)
        {
            field(MyPageCustField; Rec.MyTableField) { Editable = true; }
        }
    }
}
  • Never – still excludes a table’s fields from the in-client designer.
  • AsReadOnly – allows use in page customizations, but only as read-only.
  • AsReadWrite – allows fields to be made editable in page customizations.

The default value ToBeClassified and the obsolete value Always both behave like AsReadOnly.

Semantic Highlighting Improvements

Code made inactive using #if/#else/#endif directives is now shown in the same color. This improves readability when using Conditional directives. There is a known issue with brackets (parentheses, begin/end, curly braces, etc.) if bracket pair colorization is active. Unless "editor.bracketPairColorization.enabled": false, brackets will still have colors when code is inactive.

XML documentation comments now support Semantic Highlighting if the selected theme supports it. Try the Visual Studio 2019 Dark & Light themes.

Obsolete symbols now also support Semantic Highlighting.

Reporting

  • Allow empty dataitems when emitting Excel layouts with multiple datasheets (error if no data items contains columns which would result in a workbook with no data sheets).
  • Add new layout information fields in the aggregated metadata sheet for the Excel layout template (object caption, local date. and UTC timezone offset).
  • Updated report Word layout XML, enabling layouts to be compatible with the new data picker in the Word add-in; and it now includes the ‘Obsolete State’ attribute for Report Column and DataItem elements.

ALDoc Improvements

  • New option (–includeinternals) to include internal symbols in the generated documentation.
  • Fixed navigational links to other reference symbols
  • Reference to other objects contains object type.
  • New fallbacks in case of missing symbol documentation
    • Promote AboutText property to page or report summary
    • Promote Tooltip property to table fields summary
  • New ALDoc option (–targetpackageslist) accepts space-separated values to support target package names containing commas (unlike –targetpackages). For example, --targetpackageslist "TechCore,Inc" "Fintech Corp" "Global Solutions, Ltd"

TestType Property in AL tests

We have introduced a new TestType property in test codeunits, which allows engineers to specify the primary purpose and scope of the test.

The property can be used to group tests for execution and reporting in CI/CD pipelines.

RequiredTestIsolation Property in AL tests

We have introduced a new RequiredTestIsolation property in test codeunits, which allows engineers to set the required TestIsolation for the test codeunit to run in. If the selected TestRunner does not satisfy the test codeunit’s RequiredTestIsolation property, then the tests might fail.

The property can be used to group tests for execution and reporting in CI/CD pipelines.

If a test codeunit has RequiredTestIsolation = None, then it can run by a TestRunner with any TestIsolation.

If a test codeunit has RequiredTestIsolation = Codeunit, then it requires a TestRunner with Codeunit TestIsolation.

If a test codeunit has RequiredTestIsolation = Function, then it requires a TestRunner with Function TestIsolation.

If a test codeunit has RequiredTestIsolation = Disabled, then it requires a TestRunner with Disabled TestIsolation.

AppSourceCop

PerTenantExtensionCop

GitHub Issues

Miscellaneous


15.3

GitHub Issues

AppSourceCop

Miscellaneous


15.2

Implicit conversion between Record and RecordRef

We have introduced support for implicit conversion between Record and RecordRef instances, allowing direct assignment between these types.

codeunit 10 RecordAndRecordRefConversion
{

    procedure RecordToRecordRef()
    var
        Customer: Record Customer;
        RecRef: RecordRef;
    begin
        RecRef := Customer;      // Similar to RecRef.GetTable(Customer);
        ProcessRecord(Customer); // Argument conversion
    end;

    procedure RecordRefToRecord()
    var
        Customer: Record Customer;
        RecRef: RecordRef;
    begin
        Customer := RecRef;      // Similar to RecRef.SetTable(Customer); This will cause an error if the table is different
        ProcessCustomer(RecRef); // Argument conversion.
    end;

    procedure ProcessCustomer(r: record Customer)
    begin
        Message('Process Customer');
    end;

    procedure ProcessRecord(rr: RecordRef)
    var
        Customer: record Customer;
    begin
        case rr.Number of
            Database::Customer:
                Message('Process Customer');
            else
                Error('Unable to process record');
        end;
    end;
}

AppSourceCop

Miscellaneous

Updated the maximum allowed CSV length to 2048 to resolve import errors in the Bank Reconciliation Journal via Data Exchange Definition.


15.1

Pass SecretText to control-addins

It is now possible to pass a value of type SecretText to control add-in procedures. This permits the integration of credentials with JavaScript-based authentication solutions.

New method to add SecretText values to JSON objects – WriteWithSecretsTo

A new method was added to the JsonObject type, which allows developers to add SecretText values. To use it, the AL developer first creates a JSON object with placeholder values for their secret values. Then they provide paths to the values in the JPath format as well as the values themselves. Finally, the method produces a new SecretText value with the credentials replaced.

procedure CreateSecretBody(ApiKey: SecretText, SecretSalt: SecretText) : SecretText
var
    JsonBody: JsonObject;
    Secrets: Dictionary of [Text, SecretText];
    Result: SecretText;
begin
    // Create a debuggable body
    JsonBody.Add('type', 'Some type');
    JsonBody.Add('api_key', 'placeholder');
    JsonBody.Add('salt', 'placeholder');

    // Prepare the replacements
    Secrets.Add('$.api_key', ApiKey);
    Secrets.Add('$.salt', SecretSalt);

    // Produce the secret body
    JsonBody.WriteWithSecretsTo(Secrets, Result);
    exit(Result);
end

AppSourceCop

GitHub Issues

Miscellaneous

Fixed an issue where an error during publishing would be hidden, causing it to look as if the publishing operation had stalled.


15.0

Implicit conversion between Record and RecordRef

We have introduced support for implicit conversion between Record and RecordRef instances, allowing direct assignment between these types.

codeunit 10 RecordAndRecordRefConversion
{

    procedure RecordToRecordRef()
    var
        Customer: Record Customer;
        RecRef: RecordRef;
    begin
        RecRef := Customer;      // Similar to RecRef.GetTable(Customer);
        ProcessRecord(Customer); // Argument conversion
    end;

    procedure RecordRefToRecord()
    var
        Customer: Record Customer;
        RecRef: RecordRef;
    begin
        Customer := RecRef;      // Similar to RecRef.SetTable(Customer); This will cause an error if the table is different
        ProcessCustomer(RecRef); // Argument conversion.
    end;

    procedure ProcessCustomer(r: record Customer)
    begin
        Message('Process Customer');
    end;

    procedure ProcessRecord(rr: RecordRef)
    var
        Customer: record Customer;
    begin
        case rr.Number of
            Database::Customer:
                Message('Process Customer');
            else
                Error('Unable to process record');
        end;
    end;
}

Mocking HTTP calls in AL tests

We have introduced a new handler type HttpClientHandler to allow mocking the response of HTTP requests in test codeunits. This feature allows for more controlled and easier testing of modules that interact with external services. The feature is limited to OnPrem instances only.

HttpClientHandler

When an HttpClientHandler is added to a test method, every HTTP request that occurs during the execution of that test will be intercepted and routed to the handler. The handler method signature is as follows: it receives a TestHttpRequestMessage that contains information about the HTTP request, as well as a TestHttpResponseMessage that contains the mocked HTTP response values that should be updated by the handler. The Boolean return value indicates whether to fall through and issue the original HTTP request (true) or to use the mocked response (false).

TestHttpRequestPolicy Property

We have also introduced a new property on test codeunits called TestHttpRequestPolicy. This property determines how outbound HTTP requests are treated during test execution and has the following possible values:

  • BlockOutboundRequests: Any HTTP request issued during the test execution that is not caught and handled by an HTTP client handler will raise an exception.
  • AllowOutboundFromHandler: All HTTP requests issued during the test execution are required to be caught by an HTTP client handler. The handler is allowed to explicitly fall through to issue the original request to the external endpoint.
  • AllowAllOutboundRequests: All outbound HTTP requests issued during the test execution are allowed.

Example code

codeunit 10 MyCodeunit
{
    procedure MethodWithHttpRequest()
    var
        Client: HttpClient;
        Response: HttpResponseMessage;
    begin
        Client.Get('http://example.com/', Response);
    end;
}

codeunit 11 MyCodeunitTests
{
    Subtype = Test;
    TestHttpRequestPolicy = AllowOutboundFromHandler;

    [Test]
    [HandlerFunctions('HttpClientHandler')]
    procedure TestUnauthorizedResponseHandled()
    var
        MyCodeunit: Codeunit "MyCodeunit";
    begin
        MyCodeunit.MethodWithHttpRequest();
    end;

    [HttpClientHandler]
    procedure HttpClientHandler(request: TestHttpRequestMessage; var response: TestHttpResponseMessage): Boolean
    begin
        // Mock a '401 Unauthorized' response for the 'GET http://example.com/' request
        if (request.RequestType = HttpRequestType::Get) and (request.Path = 'http://example.com/') then begin
            response.HttpStatusCode := 401;
            response.ReasonPhrase := 'Unauthorized';
            exit(false); // Use the mocked response
        end;

        // Fall through and issue the original request in case of other requests
        exit(true);
    end;
}

Searchable downloaded symbols and using them as context in Copilot Chat

Objects from downloaded symbol packages can now be added as context when using the Github Copilot Chat extension (prerelease version 0.24.2024121201) and Visual Studio Code Insiders (version 1.97 and later). It will also be possible to search and navigate to objects coming from downloaded symbol packages via the ‘Open Symbol by Name’ functionality (Ctrl + T). Additionally, the performance of searching workspace symbols has been improved to support the now larger amount of available symbols.

UserControlHost PageType

We have introduced a new PageType UserControlHost. This page type can be used to only render a single usercontrol in the client. With the UserControlHost page type, the layout is optimized by the client to maximize the available space for the usercontrol.

This new page can only have a single control of type usercontrol within the layout Content area.

Actions cannot be specified on this page, and limited properties and triggers are available for it. It is also not extensible.

Multiline strings

AL now has support for multiline string literals. A multiline string must be prefixed with @.

var
    t: Text;
begin
    t := @'This is
a
multiline
string
';
end;

Continue statement

From runtime version 15, it is possible to use the continue keyword in loops to continue to the next iteration.

Preview support in File

Two new methods to open and view a file on the client.

[Ok :=] File.ViewFromStream(Stream: InStream, FileName: String [, AllowDownloadAndPrint: Boolean]);
[Ok :=] File.View(FilePath: String [, AllowDownloadAndPrint: Boolean]);

New methods access properties and array elements

We have improved the API for accessing JSON data with a new set of methods that will avoid always to read data through a JsonToken.

For JsonObject instances we have added:

value := GetBoolean(Key: Text [; DefaultIfNotFound: Boolean])
value := GetByte(Key: Text [; DefaultIfNotFound: Boolean])
value := GetChar(Key: Text [; DefaultIfNotFound: Boolean])
value := GetInteger(Key: Text [; DefaultIfNotFound: Boolean])
value := GetBigInteger(Key: Text [; DefaultIfNotFound: Boolean])
value := GetDecimal(Key: Text [; DefaultIfNotFound: Boolean])
value := GetOption(Key: Text [; DefaultIfNotFound: Boolean])
value := GetDateTime(Key: Text [; DefaultIfNotFound: Boolean])
value := GetDate(Key: Text [; DefaultIfNotFound: Boolean])
value := GetTime(Key: Text [; DefaultIfNotFound: Boolean])
value := GetDuration(Key: Text [; DefaultIfNotFound: Boolean])
value := GetText(Key: Text [; DefaultIfNotFound: Boolean])
value := GetArray(Key: Text [; DefaultIfNotFound: Boolean])
value := GetObject(Key: Text [; DefaultIfNotFound: Boolean])

For JsonArray instances we have added:

value := GetBoolean(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetByte(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetChar(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetInteger(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetBigInteger(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetDecimal(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetOption(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetDateTime(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetDate(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetTime(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetDuration(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetText(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetArray(Index: Integer [; DefaultIfNotFound: Boolean])
value := GetObject(Index: Integer [; DefaultIfNtFound: Boolean])    

New Command in VSCode to start a new project from a template

We have added a new command AL.NewProject. From this it is possible to start a new project from a template.

New IncStr method overload

A new overload of the IncStr method was added to support an arbitrary positive increment. This allows for incrementing number series or other similar series by more than one position in one go.

New VS Code actions from the Web Client

Two new actions have been added to the Extension Management page. One to generate launch configurations in your local AL project to match the environment, and another to select installed extensions and download them as dependencies.

Github Issues

AppSourceCop

PerTenantExtensionCop rules

Reporting

HttpClient

Miscellaneous


Más información / More information:

Deja un comentario