2 Ways of Controlling your upgrade and install code

2 Ways of Controlling your upgrade and install code

There has been some confusion about the install- and upgrade codeunits. Questions like can I have multiple install- and upgrade codeunits? And how do I secure that they never fail? And when is the Upgrade codeunit called, is it only on version change or also on schema change?

To answer the first question: Yes, you can have as many install- and upgrade codeunits as you want. They will be executed in object number order.

Here is a short guide as how to create bulletproof codeunits for your solution.

First of all, it is important to remember that when installing an app, ONLY the install codeunit is triggered, and when upgrading the app ONLY the upgrade codeunit is triggered. Secondly, it is important that the code in the codeunits under no circumstances fail, because that would make it impossible to install the extension.

Also, be advised that publishing the code directly from Visual Studio code will trigger the Install code or the upgrade code even when there are no schema changes. If there are breaking changes in the Schema, it will fail, and it will then be possible to open Extension Management and run the upgrade from there.

To hedge my bets regarding if the install codeunit or the upgrade codeunit is triggered, I will add my code in a separate codeunit and call it from both codeunits.

From the beginning, there were only one way to control the upgrade or install process in the Business Central AL language: The NavApp system variable combined with the ModuleInfo variable.

Microsoft Introduced in BC14 the Upgrade Tag Mgt codeunit that could help do the same and that changed later on to be the Upgrade Tags codeunit.

But let’s take them one by one.

The NavApp system variable

The NavApp system variable provides the opportunity to retrieve different information from both the base application and fra the installing extension. To illuminate that, I have made a small project, including:

  • A new table to hold the information
  • A new page to list the information
  • An Install codeunit to trigger my code on install
  • An Upgrade codeunit to trigger my code on upgrade
  • A codeunit to hold my Install & Upgrade code

The table holds these fields that corresponds with the information from the ModuleInfo variable:

  • AppID        The App ID from the extension
  • Version Id    The App version from the existing extension or from the base application
  • PackageId     The Package ID from the installing package
  • Version No.    A version number to allow multiple lines per app
  • Data Version    The App version from the installing package or from the base application
  • Name         The App Name or the base application localization
  • Publisher     Publisher name

So, in order to trigger this, I will start with a fresh install triggering the following code:

As you can see, I get the ModuleInfo from the parameter and insert one line in the VersionInfo table.

Both the install codeunit and the install codeunit have the same code except for the parameter:

I use the GetCurrentModuleInfo method to get information of the base application of the receiving solution and use the GetCallerModuleInfo to get information from the incoming version.

I could also have used the GetModuleInfo command to get information from the incoming version, but then I would have to use the GetCurrentModuleInfo command first:

The result of the code varies a bit depending of if it is installing or upgrading, and it look like this first time:

So, the GetCurrentModuleInfo gives me:

  • The base application version
  • The localization, in this case
  • Implementation (triggered by the install codeunit)
  • And the publisher (Microsoft – big surprise)

The GetCallerModuleInfo gives me:

  • The App Id
  • The Package Id (which will be different every time)
  • The App Version from the incoming package
  • The Data Version from the existing app
  • The Name of the app
  • Implementation (triggered by the install codeunit)
  • The name of the publisher

For this on-premise version we upgrade the version to version 1.0.0.1. There are no schema changes and the installation is triggered from Visual Studio Code.

The result look like this:

So, I can get important information from the two commands. From the GetCurrentModuleInfo I get the base application version and the localization of the base application. From the GetCallerModuleInfo I get the App Version from the incoming package and the Data Version from the existing app.

This also means that I can create code like this:

Of course, it is possible to graduate into more simple code, this is only to show the possibilities.

Using the UpgradeTag Codeunit

The UpgradeTag codeunit was introduced with Business Central (BC13), and it can help to store information of which install- or upgrade code has already been run. In this case I have made install- and upgrade codeunits with this code:

All I do is to call the InstallUpgradeCode codeunit with one parameter.

In the InstallUpgradeCode codeunit I set all my Upgrade Tags. The name of the upgrade tags are irrelevant, the only purpose is to register that “KillRoy was her” meaning that an upgrade with this name has not been or already been run in this app.

For each upgrade codeunit I call a number of local methods:

And in every method, I create the code so it cannot fail in any way:

In here I create Number series for a number of different purposes, but if they have been installed manually, it will not fail due to this line:

Try to insert the NoSerie record, but if is cannot, then never mind

Same with the CreateResources codeunit:

BTW, this code will not run because I chose to use the OnInstallAppPerDatabase trigger and the code demands that a company is selected.

Conclusion

So, should I use the NavApp system variable or should I use the UpgradeTag codeunit?

In a “normal” upgrade situation with one app in one version, but with many installs and upgrades, I would use the UpgradeTag codeunit. Why? Because it is simple and because it still offers the opportunity to save the history of all the install – and upgrade codes for documentation purposes.

Notice: An upgrade tag once used cannot be reused or reset. Once it is set it cannot be unset, not even by uninstalling the app with the mode -clean parameter or deleting the application data on uninstalling.

If I have an App that resides with many different localizations and versions, I would probably use the NavApp system variable because it provides more detailed information about both the base application and the incoming app and it is easier to differentiate the code for each version.

But you can decide yourself

You can find my test code here on Github.

Leave a Reply

Your email address will not be published. Required fields are marked *