หมายเหตุ
การเข้าถึงหน้านี้ต้องได้รับการอนุญาต คุณสามารถลอง ลงชื่อเข้าใช้หรือเปลี่ยนไดเรกทอรีได้
การเข้าถึงหน้านี้ต้องได้รับการอนุญาต คุณสามารถลองเปลี่ยนไดเรกทอรีได้
Update an existing System Application module in BCApps by changing its implementation, exposing supported functionality through its public API, and adding tests. This article uses a historical Base64 Convert contribution to illustrate that workflow.
Prerequisites for changing a module
- Familiarity with AL development. Learn more in AL development.
- A local clone of your BCApps fork and a development environment. Follow the current BCApps local development environment guidelines.
- A GitHub issue approved for contribution in BCApps before you open a pull request. Discuss your proposed change before starting implementation to avoid work that can't be accepted. Learn more in the BCApps contribution guidelines.
Your changes must follow the module architecture guidelines. Learn more in Module architecture. Preserve the existing public API and its behavior. Run the existing tests and add tests for functionality that you change or add.
Prepare your module development environment
Use the BCApps local development workflow to create a Business Central container and configure Visual Studio Code. Its setup script generates the launch.json and settings.json files for your environment. Follow the repository's current instructions rather than copying connection or assembly paths from an older example.
Open the module and its test project. For Base64 Convert, the folders are:
src\System Application\App\Base64 Convertsrc\System Application\Test\Base64 Convert
If required symbols are missing, in Visual Studio Code, press F1 and select AL: Download Symbols.
The following historical example uses .NET interoperability. If you configure it manually, set al.assemblyProbingPaths in .vscode/settings.json to the required assembly locations. For current BCApps development, use the settings generated by the repository's setup script.
Create a contribution branch
In your local clone, run git checkout -b "<FeatureBranchName>". Replace <FeatureBranchName> with a descriptive name for your change.
Historical example of changing Base64 Convert
The following example is based on ALAppExtensions pull request 7676, which added support for text encodings other than UTF8. For a new contribution, follow the same sequence: update the implementation, expose the public API, and test the behavior.
Important
These overloads and tests already exist. Don't add them again. The example shows the historical .NET-based implementation. The implementation changed to use the native Base64Convert system codeunit. Use the latest Base64 Convert implementation when preparing a new change.
The AL snippets are fragments from existing objects, not standalone objects. They rely on declarations, .NET aliases, and test labels in the surrounding source.
Update the implementation codeunit
Start with the internal implementation codeunit. In the historical contribution, the following overloads were added to Base64ConvertImpl.Codeunit.al. The file is now under src\System Application\App\Base64 Convert\src.
procedure ToBase64(String: Text; TextEncoding: TextEncoding): Text
begin
exit(ToBase64(String, false, TextEncoding, 0));
end;
procedure ToBase64(String: Text; TextEncoding: TextEncoding; Codepage: Integer): Text
begin
exit(ToBase64(String, false, TextEncoding, Codepage));
end;
procedure ToBase64(String: Text; InsertLineBreaks: Boolean; TextEncoding: TextEncoding): Text
begin
exit(ToBase64(String, InsertLineBreaks, TextEncoding, 0));
end;
procedure ToBase64(String: Text; InsertLineBreaks: Boolean; TextEncoding: TextEncoding; Codepage: Integer): Text
var
Convert: DotNet Convert;
Encoding: DotNet Encoding;
Base64FormattingOptions: DotNet Base64FormattingOptions;
Base64String: Text;
begin
if String = '' then
exit('');
if InsertLineBreaks then
Base64FormattingOptions := Base64FormattingOptions.InsertLineBreaks
else
Base64FormattingOptions := Base64FormattingOptions.None;
case TextEncoding of
TextEncoding::UTF16:
Base64String := Convert.ToBase64String(Encoding.Unicode().GetBytes(String), Base64FormattingOptions);
TextEncoding::MSDos,
TextEncoding::Windows:
Base64String := Convert.ToBase64String(Encoding.GetEncoding(CodePage).GetBytes(String), Base64FormattingOptions);
else
Base64String := Convert.ToBase64String(Encoding.UTF8().GetBytes(String), Base64FormattingOptions);
end;
exit(Base64String);
end;
procedure FromBase64(Base64String: Text; TextEncoding: TextEncoding): Text
begin
exit(FromBase64(Base64String, TextEncoding, 1252));
end;
procedure FromBase64(Base64String: Text; TextEncoding: TextEncoding; CodePage: Integer): Text
var
Convert: DotNet Convert;
Encoding: DotNet Encoding;
OutputString: Text;
begin
if Base64String = '' then
exit('');
case TextEncoding of
TextEncoding::UTF16:
OutputString := Encoding.Unicode().GetString(Convert.FromBase64String(Base64String));
TextEncoding::MSDos,
TextEncoding::Windows:
OutputString := Encoding.GetEncoding(CodePage).GetString(Convert.FromBase64String(Base64String));
else
OutputString := Encoding.UTF8().GetString(Convert.FromBase64String(Base64String));
end;
exit(OutputString);
end;
The encoding and decoding overloads use different default code pages. When you use MSDos or Windows, specify the same code page explicitly for both operations.
The existing overloads in the implementation codeunit were updated to call the new overloads with the same default encoding:
procedure ToBase64(String: Text): Text
begin
exit(ToBase64(String, false));
end;
procedure ToBase64(String: Text; InsertLineBreaks: Boolean): Text
begin
exit(ToBase64(String, InsertLineBreaks, TextEncoding::UTF8, 0));
end;
procedure FromBase64(Base64String: Text): Text
begin
exit(FromBase64(Base64String, TextEncoding::UTF8, 0));
end;
These forwarding methods preserve the existing UTF8 defaults. When changing a module, keep existing callers in mind and use tests to check compatibility.
Expose and document the public API
Next, expose the functionality through the facade codeunit and document its public procedures. In the historical contribution, the following procedures were added to Base64Convert.Codeunit.al. The file is now under src\System Application\App\Base64 Convert\src. Each procedure calls the corresponding implementation procedure.
The containing facade declares Base64ConvertImpl as a variable of type Codeunit "Base64 Convert Impl.". Learn more in the Base64 Convert facade source.
/// <summary>
/// Converts the value of the input string to its equivalent string representation that is encoded with base-64 digits.
/// </summary>
/// <param name="String">The string to convert.</param>
/// <param name="TextEncoding">The TextEncoding for the input string.</param>
/// <returns>The string representation, in base-64, of the input string.</returns>
procedure ToBase64(String: Text; TextEncoding: TextEncoding): Text
begin
exit(Base64ConvertImpl.ToBase64(String, TextEncoding));
end;
/// <summary>
/// Converts the value of the input string to its equivalent string representation that is encoded with base-64 digits.
/// </summary>
/// <param name="String">The string to convert.</param>
/// <param name="TextEncoding">The TextEncoding for the input string.</param>
/// <param name="Codepage">The Codepage if TextEncoding is MsDos or Windows.</param>
/// <returns>The string representation, in base-64, of the input string.</returns>
procedure ToBase64(String: Text; TextEncoding: TextEncoding; Codepage: Integer): Text
begin
exit(Base64ConvertImpl.ToBase64(String, TextEncoding, Codepage));
end;
/// <summary>
/// Converts the specified string, which encodes binary data as base-64 digits, to an equivalent regular string.
/// </summary>
/// <param name="Base64String">The string to convert.</param>
/// <param name="TextEncoding">The text encoding used to decode the converted bytes.</param>
/// <returns>Regular string that is equivalent to the input base-64 string.</returns>
/// <error>The length of Base64String, ignoring white-space characters, is not zero or a multiple of 4.</error>
/// <error>The format of Base64String is invalid. Base64String contains a non-base-64 character, more than two padding characters,
/// or a non-white space-character among the padding characters.</error>
procedure FromBase64(Base64String: Text; TextEncoding: TextEncoding): Text
begin
exit(Base64ConvertImpl.FromBase64(Base64String, TextEncoding));
end;
/// <summary>
/// Converts the specified string, which encodes binary data as base-64 digits, to an equivalent regular string.
/// </summary>
/// <param name="Base64String">The string to convert.</param>
/// <param name="TextEncoding">The text encoding used to decode the converted bytes.</param>
/// <param name="Codepage">The Codepage if TextEncoding is MsDos or Windows.</param>
/// <returns>Regular string that is equivalent to the input base-64 string.</returns>
/// <error>The length of Base64String, ignoring white-space characters, is not zero or a multiple of 4.</error>
/// <error>The format of Base64String is invalid. Base64String contains a non-base-64 character, more than two padding characters,
/// or a non-white space-character among the padding characters.</error>
procedure FromBase64(Base64String: Text; TextEncoding: TextEncoding; Codepage: Integer): Text
begin
exit(Base64ConvertImpl.FromBase64(Base64String, TextEncoding, Codepage));
end;
Add tests for the changed behavior
Run the existing tests to check compatibility, and then add and run tests for the new behavior. The historical contribution included the following UTF16 tests in Base64ConvertTest.Codeunit.al. The file is now under src\System Application\Test\Base64 Convert\src.
The containing test codeunit supplies the Base64Convert and Assert variables, sample text, expected Base64 value, and error labels. Learn more in the Base64 Convert test source.
[Test]
procedure StringToBase64UTF16Test()
var
ConvertedText: Text;
begin
// [SCENARIO] A string variable is converted to base-64 string, binary representation is kept in UTF16
// [WHEN] The string is converted
ConvertedText := Base64Convert.ToBase64(SampleUTF16Txt, TextEncoding::UTF16);
// [THEN] The converted value is correct
Assert.AreEqual(Base64SampleUTF16Txt, ConvertedText, ConvertionToBase64UTF16Err);
end;
[Test]
procedure FromBase64UTF16StringTest()
var
ConvertedText: Text;
begin
// [SCENARIO] A base-64 string with UTF16 encoding is converted to a regular string
// [WHEN] The base-64 string is converted
ConvertedText := Base64Convert.FromBase64(Base64SampleUTF16Txt, TextEncoding::UTF16);
// [THEN] The converted value is correct
Assert.AreEqual(SampleUTF16Txt, ConvertedText, ConvertionFromBase64UTF16Err);
end;
Submit your module changes
Build the changed app and its test app, and run the relevant tests before submitting your changes. Follow the BCApps local development guidelines for your environment.
- Run
git statusand review your changes. - Stage each intended file with
git add "<ChangedFile>". Replace<ChangedFile>with its path. - Commit your changes with
git commit -m "<CommitMessage>". Replace<CommitMessage>with a summary of the change. - Push your branch with
git push --set-upstream origin "<FeatureBranchName>". Theoriginremote must point to your fork. - Open a pull request from your branch to the BCApps repository. Select the appropriate target branch and link it to your approved issue by including
Fixes #<IssueNumber>in the description.
Follow the repository's contribution checks and review process. Complete the Contributor License Agreement steps if the pull request bot requests them.
Related information
BCApps contribution guidelines
BCApps local development environment guidelines
Module architecture
Create a new module