Guidelines for Partners
This article will explain the Universal Code Initiative, and its goals and will enlighten you about the most popular breaking changes regarding Cloud development.
Universal Code Initiative aims for better solutions so that code can live in any target environment. The new Business Central Universal code initiative is a modern independent software vendor (ISV) approach to ensure that all future customers can choose Dynamics 365 Business Central online while finding the right apps on Microsoft AppSource to meet their unique requirements. BC on-premises customers who aren’t licensing ‘universal code’ (cloud-optimized extensions) will be affected by gradually increasing fees from 2023 onwards (Dynamics 365 Business Central Universal code initiative | Dynamics 365 Lab).
Microsoft has introduced us to two new Modules:
- Module “Implemented code is not in extensions” – necessary for code customized base apps.
- Module “Implemented code is not cloud-optimized” – code is in extensions, but that code could only work OnPrem.
Partners that have code working only OnPrem will have to buy a license. The fee for that license is a per-user per-year fee, which increases every year. You can check fees in the following table:
Official source, slides and Q&A: Microsoft presents: UCI update and FY23 ISV Investment Program
This price is “per full user.” The more users you have, the more costly it will be to run your legacy code. If you’re a large company with, say, a 100-user license, that means, in three years, you will be paying as much as $42500 annually just to run outdated code. However, this will not affect customers who licensed BC OnPrem before April 1, 2022.
Let’s talk about requirements while creating extensions to keep code Universal:
- No code customization in the BaseApp.
- Writing code that does not require “OnPrem” scope.
When you create an Extension, you must set the “Target” in the app.json file to “Cloud” as in the example below.
That means that your code should be able to compile in both: Cloud and OnPrem development. Keep in mind there are some groups of functionalities that will not work in a Cloud environment:
- Local file operations
- Custom .Net libraries
- Direct SQL database operations
- Others
In order to rework file operations, you will have to set up BC to use external connectors and work with files in online repositories, such as Google Drive. For custom-created .Net libraries, you will have to use Cloud-approved applications which allow connecting external applications to your BC solution, such as Power Automate (which already contains more than 500 connectors). As you may probably notice, the Base Application still uses some .Net libraries, and why can we not use them in custom extensions? The answer is simple – all of the previously used functionalities containing any .Net libraries have been moved to the new objects so you can manipulate and use them in your extension, e.g. instead of DotNet Regex, which is allowed in OnPrem development and not in Cloud, you can use Codeunit Regex which is already created in Base Application.
Here are some frequently used breaking changes and their solutions while switching from OnPrem to Cloud development in Business Central 2022 Wave 1:
Table 2000000028 “Table Information”
Issue: Cannot be used for Cloud development
Possible Solution: Use AllObjWithCaption instead
Notes, Examples:
// SPLN1.00 - Start //TableRelation = "Table Information"."Table No."; TableRelation = AllObjWithCaption."Object ID" where("Object Type" = const('Table')); // SPLN1.00 - End
Table 370 “Excel Buffer”
Issue: SelectSheetsName procedure not supported in Cloud
Possible Solution: Add excel file to the input stream and call SelectSheetsNameStream instead
Notes, Examples:
// SPLN1.00 - Start //Sheetname := ExcelBufferTemp.SelectSheetsName(ServerFileName); FileMgt.BLOBImport(TempBlob, ServerFileName); TempBlob.CreateInStream(InStr); Sheetname := ExcelBufferTemp.SelectSheetsNameStream(InStr); // SPLN1.00 - End
Issue: OpenBook procedure not supported in Cloud
Possible Solution: Add excel file to the input stream and call OpenBookStream instead (needs testing)
Notes, Examples:
// SPLN1.00 - Start //ExcelBufferTemp.OpenBook(ServerFileName, Sheetname); FileMgt.BLOBImport(TempBlob, ServerFileName); TempBlob.CreateInStream(InStr); ExcelBufferTemp.OpenBookStream(InStr, Sheetname); // SPLN1.00 - End
DotNet “Interaction”
Issue: Interaction.InputBox not supported in Cloud
Possible Solution: Recreate analogy creating additional page as a dialog window with a text field. In order to replicate as similar as possible, create group and textfield, create procedures to set their captions and get value, set page type as StandardDialog.
Notes, Examples:
// SPLN1.00 - Start //ToVersion := Prompt.InputBox(MTxtNewVersionPrompt, MTxtNewVersionTitle, '', 450, 300); CopyVersion.LookupMode(true); CopyVersion.Set_VersionCaption(MTxtNewVersionPrompt); if CopyVersion.RunModal() = Action::LookupOK then begin ToVersion := CopyVersion.Get_VersionValue(); end; // SPLN1.00 - End
DotNet UTF8Encoding
Issue: Not supported in Cloud
Possible Solution: Use InStream and OutStream to read text using UTF8 encoding
Notes, Examples:
// SPLN1.00 - Start //SystemUTF8Encoder: DotNet UTF8Encoding; //SystemByteArray: DotNet Array; SystemByteArray: Codeunit DotNet_Array; InStrEncoder: InStream; OutStrEncoder: OutStream; TempBlob: Codeunit "Temp Blob"; UTF8EncodedNote: Text; // SPLN1.00 - End
DotNet Array
Issue: Not supported in Cloud
Possible Solution: Use Codeunit DotNet_Array
Notes, Examples:
// SPLN1.00 - Start //SystemUTF8Encoder := SystemUTF8Encoder.UTF8Encoding; //SystemByteArray := SystemUTF8Encoder.GetBytes(Note); TempBlob.CreateOutStream(OutStrEncoder, TextEncoding::UTF8); OutStrEncoder.WriteText(Note); TempBlob.CreateInStream(InStrEncoder, TextEncoding::UTF8); InStrEncoder.ReadText(UTF8EncodedNote); SystemByteArray.ByteArray(StrLen(UTF8EncodedNote)); for i := 0 to StrLen(UTF8EncodedNote) - 1 do begin SystemByteArray.SetByteValue(UTF8EncodedNote[i], i); end; // SPLN1.00 - End // SPLN1.00 - Start //Char1 := SystemByteArray.GetValue(i); Char1 := SystemByteArray.GetValueAsChar(i); // SPLN1.00 - End
DotNet Regex
Issue: Not supported in Cloud
Possible Solution: Use codeunit “Regex” instead
Notes, Examples:
// SPLN1.00 - Start //RegEx: DotNet Regex; //RegExOptions: DotNet RegexOptions; RegEx: Codeunit Regex; RegExOptions: Record "Regex Options"; // SPLN1.00 - End;
DotNet RegexOptions.IgnoreCase
Issue: Not supported in Cloud
Possible Solution: Use record “Regex Options” instead by setting required parameters and pass where needed
Notes, Examples:
// SPLN1.00 - Start //RegEx := RegEx.Regex(ErrorMessageAction."RegEx Pattern", RegExOptions.IgnoreCase); RegExOptions.IgnoreCase := true; RegEx.Regex(ErrorMessageAction."RegEx Pattern", RegExOptions); // SPLN1.00 - End;
In conclusion, as Business Central seems to be moving towards Cloud development, it becomes more and more important to make your code more Universal.