When upgrading an extension from C/AL to AL (version 1 to version 2) we need to think about the data upgrade process.
Image may be NSFW.
Clik here to view.
In C/AL we needed to add two function to an extension Codeunit to handle the installation and upgrade. This I did with Codeunit 70009200. One function to be execute once for each install.
PROCEDURE OnNavAppUpgradePerDatabase@1(); VAR AccessControl@70009200 : Record 2000000053; BEGIN WITH AccessControl DO BEGIN SETFILTER("Role ID",'%1|%2','SUPER','SECURITY'); IF FINDSET THEN REPEAT AddUserAccess("User Security ID",PermissionSetToUserGLSourceNames); AddUserAccess("User Security ID",PermissionSetToUpdateGLSourceNames); AddUserAccess("User Security ID",PermissionSetToSetupGLSourceNames); UNTIL NEXT = 0; END; END;
And another function to be executed once for each company in the install database.
PROCEDURE OnNavAppUpgradePerCompany@2(); VAR GLSourceNameMgt@70009200 : Codeunit 70009201; BEGIN NAVAPP.RESTOREARCHIVEDATA(DATABASE::"G/L Source Name Setup"); NAVAPP.RESTOREARCHIVEDATA(DATABASE::"G/L Source Name User Setup"); NAVAPP.DELETEARCHIVEDATA(DATABASE::"G/L Source Name"); NAVAPP.DELETEARCHIVEDATA(DATABASE::"G/L Source Name Help Resource"); NAVAPP.DELETEARCHIVEDATA(DATABASE::"G/L Source Name User Access"); NAVAPP.DELETEARCHIVEDATA(DATABASE::"G/L Source Name Group Access"); GLSourceNameMgt.PopulateSourceTable; RemoveAssistedSetup; END;
For each database I add my permission sets to the installation users and for each company I restore the setup data for my extension and populate the lookup table for G/L Source Name.
The methods for install and upgrade have changed in AL for extensions version 2. Look at the AL documentation from Microsoft for details.
In version 2 I remove these two obsolete function from my application management Codeunit and need to add two new Codeunits, one for install and another for upgrade.
codeunit 70009207 "O4N GL Source Name Install" { Subtype = Install; trigger OnRun(); begin end; var PermissionSetToSetupGLSourceNames : TextConst ENU='G/L-SOURCE NAMES, S'; PermissionSetToUpdateGLSourceNames : TextConst ENU='G/L-SOURCE NAMES, E'; PermissionSetToUserGLSourceNames : TextConst ENU='G/L-SOURCE NAMES'; trigger OnInstallAppPerCompany(); var GLSourceNameMgt : Codeunit "O4N GL SN Mgt"; begin GLSourceNameMgt.PopulateSourceTable; RemoveAssistedSetup; end; trigger OnInstallAppPerDatabase(); var AccessControl : Record "Access Control"; begin with AccessControl do begin SETFILTER("Role ID",'%1|%2','SUPER','SECURITY'); if FINDSET then repeat AddUserAccess("User Security ID",PermissionSetToUserGLSourceNames); AddUserAccess("User Security ID",PermissionSetToUpdateGLSourceNames); AddUserAccess("User Security ID",PermissionSetToSetupGLSourceNames); until NEXT = 0; end; end; local procedure RemoveAssistedSetup(); var AssistedSetup : Record "Assisted Setup"; begin with AssistedSetup do begin SETRANGE("Page ID",PAGE::"O4N GL SN Setup Wizard"); if not ISEMPTY then DELETEALL; end; end; local procedure AddUserAccess(AssignToUser : Guid;PermissionSet : Code[20]); var AccessControl : Record "Access Control"; AppMgt : Codeunit "O4N GL SN App Mgt."; AppGuid : Guid; begin EVALUATE(AppGuid,AppMgt.GetAppId); with AccessControl do begin INIT; "User Security ID" := AssignToUser; "App ID" := AppGuid; Scope := Scope::Tenant; "Role ID" := PermissionSet; if not FIND then INSERT(true); end; end; }
In the code you can see that this Codeunit is of Subtype=Install. This code will be executed when installing this extension in a database.
To confirm this I can see that I have the G/L Source Names Permission Sets in the Access Control table .
Image may be NSFW.
Clik here to view.
And my G/L Source Name table also has all required entries.
Image may be NSFW.
Clik here to view.
Uninstalling the extension will not remove this data. Therefore you need to make sure that the install code is structured in a way that it will work even when reinstalling. Look at the examples from Microsoft to get a better understanding.
Back to my C/AL extension. When uninstalling that one the data is moved to archive tables.
Image may be NSFW.
Clik here to view.
Archive tables are handled with the NAVAPP.* commands. The OnNavAppUpgradePerCompany command here on top handled these archive tables when reinstalling or upgrading.
Basically, since I am keeping the same table structure I can use the same set of commands for my upgrade Codeunit.
codeunit 70009208 "O4N GL SN Upgrade" { Subtype=Upgrade; trigger OnRun() begin end; trigger OnCheckPreconditionsPerCompany() begin end; trigger OnCheckPreconditionsPerDatabase() begin end; trigger OnUpgradePerCompany() var GLSourceNameMgt : Codeunit "O4N GL SN Mgt"; archivedVersion : Text; begin archivedVersion := NAVAPP.GetArchiveVersion(); if archivedVersion = '1.0.0.1' then begin NAVAPP.RESTOREARCHIVEDATA(DATABASE::"O4N GL SN Setup"); NAVAPP.RESTOREARCHIVEDATA(DATABASE::"O4N GL SN User Setup"); NAVAPP.DELETEARCHIVEDATA(DATABASE::"O4N GL SN"); NAVAPP.DELETEARCHIVEDATA(DATABASE::"O4N GL SN Help Resource"); NAVAPP.DELETEARCHIVEDATA(DATABASE::"O4N GL SN User Access"); NAVAPP.DELETEARCHIVEDATA(DATABASE::"O4N GL SN Group Access"); GLSourceNameMgt.PopulateSourceTable; end; end; trigger OnUpgradePerDatabase() begin end; trigger OnValidateUpgradePerCompany() begin end; trigger OnValidateUpgradePerDatabase() begin end; }
So, time to test how and if this works.
I have my AL folder open in Visual Studio Code and I use the AdvaniaGIT command Build NAV Environment to get the new Docker container up and running.
Then I use Update launch.json with current branch information to update my launch.json server settings.
Image may be NSFW.
Clik here to view.
I like to use the NAV Container Helper from Microsoft to manually work with the container. I use a command from the AdvaniaGIT module to import the NAV Container Module.
Image may be NSFW.
Clik here to view.
The module uses the container name for most of the functions. The container name can be found by listing the running Docker containers or by asking for the name that match the server used in launch.json.
Image may be NSFW.
Clik here to view.
I need my C/AL extension inside the container so I executed
Copy-FileToNavContainer -containerName jolly_bhabha -localPath C:NAVManagementWorkFolderWorkspaceGITKappiNAV2017Extension1AppPackage.navx -containerPath c:run
Then I open PowerShell inside the container
Enter-NavContainer -containerName jolly_bhabha
Import the NAV Administration Module
Welcome to the NAV Container PowerShell prompt [50AA0018A87F]: PS C:run> Import-Module 'C:Program FilesMicrosoft Dynamics NAV110ServiceNavAdminTool.ps1' Welcome to the Server Admin Tool Shell! [50AA0018A87F]: PS C:run>
and I am ready to play. Install the C/AL extension
Publish-NAVApp -ServerInstance NAV -IdePath 'C:Program Files (x86)Microsoft Dynamics NAV110RoleTailored Clientfinsql.exe' -Path C:runAppPackage.navx -SkipVerification
Now I am faced with the fact that I have opened PowerShell inside the container in my AdvaniaGIT terminal. That means that my AdvaniaGIT commands will execute inside the container, but not on the host.
The simplest way to solve this is to open another instance of Visual Studio Code. From there I can start the Web Client and complete the install and configuration of my C/AL extension.
Image may be NSFW.
Clik here to view.
I complete the Assisted Setup and do a round trip to G/L Entries to make sure that I have enough data in my tables to verify that the data upgrade is working.
Image may be NSFW.
Clik here to view.
I can verify this by looking into the SQL tables for my extension. I use PowerShell to uninstall and unpublish my C/AL extension.
Uninstall-NAVApp -ServerInstance NAV -Name "G/L Source Names" Unpublish-NAVApp -ServerInstance NAV -Name "G/L Source Names"
I can verify that in my SQL database I now have four AppData archive tables.
Pressing F5 in Visual Studio Code will now publish and install the AL extension, even if I have the terminal open inside the container.
Image may be NSFW.
Clik here to view.
The extension is published but can’t be installed because I had previously installed an older version of my extension. Back in my container PowerShell I will follow the steps as described by Microsoft.
[50AA0018A87F]: PS C:run> Sync-NAVApp -ServerInstance NAV -Name "G/L Source Names" -Version 2.0.0.0 WARNING: Cannot synchronize the extension G/L Source Names because it is already synchronized. [50AA0018A87F]: PS C:run> Start-NAVAppDataUpgrade -ServerInstance NAV -Name "G/L Source Names" -Version 2.0.0.0 [50AA0018A87F]: PS C:run> Install-NAVApp -ServerInstance NAV -Tenant Default -Name "G/L Source Names" WARNING: Cannot install extension G/L Source Names by Objects4NAV 2.0.0.0 for the tenant default because it is already installed. [50AA0018A87F]: PS C:run>
My AL extension is published and I have verified in my SQL server that all the data from the C/AL extension has been moved to the AL extension tables and all the archive tables have been removed.
Back in Visual Studio Code I can now use F5 to publish and install the extension again if I need to update, debug and test my extension.
Couple of more steps left that I will do shortly. Happy coding…