Do you expect that?

For previous months I was involved in developing a new app for Business Central. That's what I love most. You have white (actually black) canvas, take the brush and begin to create. 

The end-user had to start using the application as quickly as possible. So I've populated all setup data during the installation process: app setup, no-series, templates and so on. 

Everything worked as expected until I've installed 2-nd version of my app on production tenant. I've noticed that after 1-st installation user changed some setup configuration and 2-nd version returned everything to default.

That was not expected, cos everything was tested on a sandbox and worked fine. 

So I decided to dive into that. 

Start of blog series 

I've decided to check what is going on when you

  • First-time install
  • Upgrade 
  • Re-install
  • Uninstall and Install
  • Unpublish and Install

an app on 3 different environments

Today I will describe the First-time install process.

But before some prehistory, to show you the evolution of the installation process. 

Old classic customizations "installation" approach

Even 2-3 years ago development process looked more or less like in the next picture:

 

Figure 1. Install customizations on Production

We just developed something very useful in the development database, exported changes as a .fob or .txt, and imported them into the production database. Some developers changed the code in Production directly… ufff… NEVER do that.

Extensions 1.0 installation approach

Then we've got Extensions 1.0, where the process became a little more difficult:

Figure 2. Install Extensions 1.0 on Production

First, we needed to create 2 databases: original from NAV DVD, and development. Then we developed something very useful in the development database. After exporting all objects from each database, run through PowerShell scripts to get Deltas and generated .navx file from these deltas. At the end, we published .navx file on Production database using PowerShell command.

All this is very well described in the official documentation and in various blogs, so I will go further. 

Note! If you have NAV2016 or NAV2017 - this is how you should make changes

Extensions 2.0 installation approach

With Extensions 2.0 we’ve got Visual Studio Code as a new development platform. So, we don’t develop inside the database, we develop outside.

The process could be illustrated on next picture

 

Figure 3. Install Extensions 2.0 on Production

The process seems much easier than in Extensions 1.0 approach.

First, you create a project in VSCode with AL extension pre-installed. Then you download symbols of your destination platform (NAV2018 or Business Central). Then you develop something very useful in .al files. After packaging your solution in a .app file you publish it in Production Database. Packaging and publishing run in one click.

I’m sure you know everything this very well. 

But the Devil is in details.

  • What’s going on during the Installation process?
  • How correctly add some new features to the already Installed app?

And, what is more, important how to install an app to an Online Business Central Production Tenant? 

So, let’s start with the first question.

What’s going on during the Installation process?

Generally, the publishing process should look like that.

Figure 4. Publish Extensions 2.0 on Production

But this depends on:

So, let’s create a simple app and try to publish it differently on different databases.

Simple app to test the installation process

To check what is going on we will create a table with auto increment primary key and a list page for it. And during the installation process will fill this table with some messages.

table 50101 "AIR Check install process"
{
    DataPerCompany = false;

    fields
    {
        field(1; "Primary Key"; Integer)
        {
            AutoIncrement = true;
        }
        field(2; "Trigger"; Text[250])
        { }
        field(3; "Version Installing"; Text[250])
        { }
        field(4; "Company Name"; Text[250])
        { }
        field(5; "Version Installed"; Text[250])
        { }

    }

    keys
    {
        key(PK; "Primary Key")
        {
            Clustered = true;
        }
    }

    procedure InsertRecord(MessageFromTrigger: Text)
    var
    begin
        Init();
        "Trigger" := MessageFromTrigger;
        "Company Name" := CompanyName();
        InsertVersionNo();
        Insert();
    end;

    local procedure InsertVersionNo()
    var
        AppInfo: ModuleInfo;
    begin
        NavApp.GetCurrentModuleInfo(AppInfo);
        "Version Installing" := Format(AppInfo.AppVersion());
        "Version Installed" := Format(AppInfo.DataVersion());
    end; 

Notice, that I’ve added property DataPerCompany = False. This will allow us to record triggers related to database, also.

Upgrade and Install Codeunits

First, we will create Upgrade Codeunit. And on each trigger will fill our table.

codeunit 50101 "AIR Upgrade codeunit"
{
    Subtype = Upgrade;

    trigger OnCheckPreconditionsPerDatabase()
    begin
        //if you will add insert any code that insert data to a table, 
        //where DataPerCompany = True, you will receive an error during publish process
        AddMessageToOurTable('OnCheckPreconditionsPerDatabase');
    end;

    trigger OnCheckPreconditionsPerCompany()
    begin
        AddMessageToOurTable('OnCheckPreconditionsPerCompany');
    end;

    trigger OnUpgradePerDatabase()
    begin
        AddMessageToOurTable('OnUpgradePerDatabase');
    end;

    trigger OnUpgradePerCompany()
    begin
        AddMessageToOurTable('OnUpgradePerCompany');
    end;

    trigger OnValidateUpgradePerDatabase()
    begin
        AddMessageToOurTable('OnValidateUpgradePerDatabase');
    end;

    trigger OnValidateUpgradePerCompany()
    begin
        AddMessageToOurTable('OnValidateUpgradePerCompany');
    end;

    local procedure AddMessageToOurTable(MessageFromTrigger: Text)
    var
        CheckInstallProcess: Record "AIR Check install process";
    begin
        CheckInstallProcess.InsertRecord(MessageFromTrigger);
    end;
}

Note! If you will input any code in *PerDatabase triggers, that insert data to a table, where DataPerCompany = True, you will receive an error during publish process. 

Second, we will create Install Codeunit.

codeunit 50102 "AIR Install codeunit"
{
    Subtype = Install;

    trigger OnInstallAppPerDatabase()
    begin
        AddMessageToOurTable('OnInstallAppPerDatabase');
    end;

    trigger OnInstallAppPerCompany()
    begin
        AddMessageToOurTable('OnInstallAppPerCompany');
    end;

    local procedure AddMessageToOurTable(MessageFromTrigger: Text)
    var
        CheckInstallProcess: Record "AIR Check install process";
    begin
        CheckInstallProcess.InsertRecord(MessageFromTrigger);
    end;
}

Let’s publish this app in different ways.

SCENARIO 1. INSTALL APP FOR THE FIRST TIME

Container Sandbox

VSCode > AL:Publish without debugging (Ctrl+F5)



PSScript> Publish-NavContainerApp -containerName $containername `
    -appFile $appfilename `
    -install `
    -skipVerification `
    -sync `
    -tenant $tenant

Online Sandbox

VSCode > AL:Publish without debugging (Ctrl+F5)

Online Business Central Production Tenant

>Web client > Extensions Page >Upload .app file

The first-time app install. Summary

  • Upgrade codeunit was not triggered at all. That’s because we publish our app for the first time.
  • Install codeunit was triggered.

The result of this scenario can be displayed in the next picture

Figure 5. Install app for the first time

What's next

Next blog will be about the upgrade process. Stay tuned.