Developing Business Central Extensions (part 2) – Repository/Environment


If you haven't read part 1, you should do so before continuing here. Part 1 contains all the prerequisites you need in order to continue with this post.

Create your organization and your first project

Navigate to https://devops.azure.com and login to your DevOps account. Create your organization, which is the location in which you will create your projects. In your organization, create your first project:

In the project navigate to the Repos -> Files area, click Import and enter https://dev.azure.com/businesscentralapps/HelloWorld/_git/HelloWorld in the Clone URL field.

Inspect the content of the repository

  • app is the Hello World App folder
  • test is the Test App folder
  • scripts contains a set of scripts for build, test and CI/CD
  • settings.json defines the settings for your project and users
  • Local-Sandbox.ps1 is a script, which will create a local Sandbox environment (based on Docker)
  • AzureVM-Sandbox.ps1 is a script, which will create an AzureVM with a Sandbox environment (based on Docker and ARM templates)
  • Local-Build.ps1 is a script, which will perform a full build and test run locally
  • Initialize.ps1 is an initialization script used from the other scripts in this folder.
  • CI.yml is the CI pipeline sample

Note: The template will constantly be improved and the content of the template repository might vary.

If you want to add multiple apps to the project, the idea is to create folders for each app in the root folder.

After the import, Click the Clone button in the upper right Corner and select Clone in VS Code.

Accept the app change, select a location for the repository and sign in to your Azure DevOps account if asked to do so.

Note: If authentication fails with a NullReferenceException, it is likely because you need to install a new version of the Credential Manager as explained in Part 1.

Modify Settings.json

Open Repository and open settings.json:

  • name is the name of the project.
  • startupObjectId, startupObjectType and breakOnError are values, which will be inserted in launch.json if present.
  • navContainerHelperPath is a local path to NavContainerHelper. If not set, NavContainerHelper will be installed from the PowerShell Gallery.
  • versions describes the three different versions of Business Central you will be building against.
  • profiles describes the Azure connection and resource naming, location, sizing etc. for a specific profile. Every user will typically have their own profile and the build process will also have a profile of its own.

Please modify the default profile to match the subscription Id and the Key Vault Name from part 1 of this blog post series. If you are going to create Azure VMs for your Business Central Sandbox environment, you also need to set the Resource Group Name, the Location and the Properties you want to set in the ARM template deployment. The properties section can contain all properties known by the ARM template (described by the template parameter).

Modify App app.json

Expand the app folder, open app.json, mark <app id>, press Ctrl+Shift+P and select Insert GUID (from the Insert GUID extension we installed in VS Code in Part 1).

Copy the GUID to the clipboard, you need it for the dependency in the Test App. Close app.json.

Modify Test app.json

Expand the test folder, open app.json, replace <app id> under dependencies with the App Id GUID from the App app.json.

Replace the <test app id> with a new GUID. Close app.json.

Check in your changes

In this blog post we are primarily working on local builds and local development. For that it is not necessary to checkin your changes.

But, in the next blog post we will be looking at setting up hosted builds and our configuration needs to be in the depot for that.

Click the Source Control icon and press + on the changes line to stage all your changes.

Now enter your commit message and press Ctrl+Enter

In the bottom left side, press the synchronize symbol to push your changes to the depot.

Create your Sandbox environment

In Part 1, we installed the PowerShell extension in VS Code.

In the repository you will find two scripts for setting up sandbox environments:

  • Local-Sandbox.ps1 is a script, which will create a local Sandbox environment (based on Docker)
  • AzureVM-Sandbox.ps1 is a script, which will create an AzureVM with a Sandbox environment (based on Docker and ARM templates)

Create a local Sandbox environment

Open Local-Sandbox.ps1 and press F5.

Select the current version, login to your azure subscription if asked to do so and wait for the script to complete.

After completion of the script, you should see

Note: That all app folders in the root folder automatically gets a Local Sandbox server created pointing to the local sandbox environment.

Create an AzureVM Sandbox environment

Note: In order to create an AzureVM Sandbox environment, you need to correctly configure settings.json as described above (Resource Group Name, VM Name and Contact email for Lets Encrypt)

Note also: The Resource Group holding the Azure VM should not be used for other resources.ย Creating an AzureVM-Sandbox will remove the Resource Group if it already exists.

Open AzureVM-Sandbox.ps1 and press F5.

Note

Select the current version, login to your azure subscription if asked to do so and wait for the script to complete. This will likely take 10-15 minutes and after that you should see:

Note: The deployment is still running inside the Azure VM. The landing page should open automatically and you should see:

This content of this page will change to the landing page when the installation is complete:

Note: That all app folders in the root folder automatically gets a AzureVM Sandbox server created pointing to the AzureVM sandbox environment.

Build your app

In VS Code, close the folder.

Select File -> Add folder to workspace select the app folder in the repository and add this to the workspace.

Do the same with the test folder and save the Workspace in the Root folder.

Open your app project in the workspace (not under myfirstapp), click HelloWorld.al

Click the Download Symbols, select appropriate server if you have created both environments (Local Sandbox if running Local, AzureVM Sandbox if running Azure VM). Enter the credentials you stored in the keyvault and you should see:

Press F5 and you should see:

What's next

Now we are done setting up our repository, we have build the app and successfully tested it.

In the next Blog Post we will setup build agents and create build pipelines to build the app in Azure DevOps.

 

Enjoy

Freddy Kristiansen
Technical Evangelist

Comments (18)

  1. Hi Freddy, fantastic that you created this blog series. I am trying to execute all steps you described.
    I am at the point that I need to create the sandbox environments. The local sandbox creation on my Windows 10 laptop doesn’t finish because the container that is created gets corrupted after about 2 minutes of starting.

    Before I could use the Azure sandbox creation script I had to fill in the ‘template URI’ and the ‘contact email for letsencrypt’. I didn’t know what to fill in at the template URI. I suppose it must be the one I could find in your screenprints above. Maybe you could mention it in the paragraph ‘Create an AzureVM Sandbox environment’.

    1. FreddyDK says:

      Actually, the template URI is optional and it defaults to the value in the screenshot, but I will edit the blog post and mention this.

  2. Additional information to my previous post:

    Select Version (current, nextminor, nextmajor) (default current):
    NavContainerHelper 0.4.1.2 is installed
    Determine latest NavContainerHelper version
    NavContainerHelper 0.4.1.2 is the latest version
    Create helloworld-dev from microsoft/bcsandbox:us
    Host is Windows 10 10.0.17763.0 – ltsc2019
    Using image microsoft/bcsandbox:us
    Removing container helloworld-dev
    Removing helloworld-dev from hosts
    Removing C:\ProgramData\NavContainerHelper\Extensions\helloworld-dev
    Creating Nav container helloworld-dev
    NAV Version: 13.0.24630.25789-US
    Generic Tag: 0.0.7.1
    Container OS Version: 10.0.14393.2551 (ltsc2016)
    Host OS Version: 10.0.17763.0 (ltsc2019)
    A better Container OS exists for your host (ltsc2019)
    generic-ltsc2019: Pulling from microsoft/dynamics-nav
    Digest: sha256:60298c15aeb3e54a809b70d4c47d74a96ee06dca62cbe1f67ee92a30bf6865ba
    Status: Image is up to date for microsoft/dynamics-nav:generic-ltsc2019
    Creating container helloworld-dev from image microsoft/dynamics-nav:generic-ltsc2019
    e6135948da45704fda967eb2b14c907f80a3160c4c41db1a9afb70a21f3eceda
    Waiting for container helloworld-dev to be ready
    Installing Business Central
    Downloading Url Rewrite
    Exception calling “DownloadFile” with “2” argument(s): “The remote name could not be resolved: ‘download.microsoft.com'”
    at InstallPrerequisite, C:\Run\HelperFunctions.ps1: line 575
    at , C:\Run\navinstall.ps1: line 26
    at , C:\Run\start.ps1: line 108
    at , : line 1Error
    Installing Business Central
    Downloading Url Rewrite
    Exception calling “DownloadFile” with “2” argument(s): “The remote name could not be resolved: ‘download.microsoft.com'”
    at InstallPrerequisite, C:\Run\HelperFunctions.ps1: line 575
    at , C:\Run\navinstall.ps1: line 26
    at , C:\Run\start.ps1: line 108
    at , : line 1
    Initialization of container helloworld-dev failed
    At C:\Program Files\WindowsPowerShell\Modules\navcontainerhelper\0.4.1.2\ContainerHandling\Wait-NavContainerReady.ps1:45 char:17
    + … throw “Initialization of container $containerName failed” …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (Initialization …orld-dev failed:String) [], RuntimeException
    + FullyQualifiedErrorId : Initialization of container helloworld-dev failed

    1. FreddyDK says:

      It looks like there is no internet connectivity from inside the container – it cannot do a DNS lookup.
      I am not sure that the container will work if no internet connectivity exists.
      I will investigate if there is a better way of making this work.

  3. Freddy, I kept on searching for the cause and found it although I cannot explain why. If I leave out the option ‘-useBestContainerOS ` when creating the local sandbox, it works okay.

    1. FreddyDK says:

      Yeah, if you leave out the useBest, the container doesn’t have to download pre-requisites.
      I will investigate whether there is a better way of doing this – thanks for reporting this.

      1. I said it works when I leave out the UseBestContainerOS but it doesn’t. I don’t get the previous error anymore and the script continues but runs into another problem.

        First thing I notice are these two output lines:
        WARNING: DNS resolution not working from within the container.
        WARNING: Container starts with TimeZone = West-Europa (standaardtijd), which is not recognized in the list of TimeZones.

        But the script continues:
        Using NavUserPassword Authentication
        Starting Local SQL Server
        Starting Internet Information Server
        Creating Self Signed Certificate
        Self Signed Certificate Thumbprint 7B0DF8793F2996E39DFDB4475AF8418CBA7B0E3D
        Modifying Service Tier Config File with Instance Specific Settings
        Starting Service Tier
        Creating DotNetCore Web Server Instance
        Enabling Financials User Experience
        Creating http download site
        Creating Windows user admin
        Setting SA Password and enabling SA
        Creating admin as SQL User and add to sysadmin

        From the previous output line the script seemed to fail and after that the container goes into the unhealthy state. After several minutes an error was shown that the container couldn’t initialize.

        I realized that my project-name in DevOps maybe was too long and the path where I stored my local cloned repo was also quite long. After shortening both I was able to create the local sandbox (after leaving out the UseBestContainerOS).

        Hopefully this was helpful.

  4. Hi Freddy

    To running DeployTo-AzureVM.ps1 will kill all your setup for key vault service, if settings.json share same resourceGroup with azure key vault. Please look that place in your code.
    https://dev.azure.com/businesscentralapps/_git/HelloWorld?path=%2Fscripts%2FDeployTo-AzureVM.ps1&version=GBmaster&line=34&lineStyle=plain&lineEnd=36&lineStartColumn=1&lineEndColumn=104

    So i managed to use same Resource Group ๐Ÿ˜‰

    Br,
    Indrek

    1. FreddyDK says:

      That is correct – I will add that information to the blog post.
      I hope you didn’t have a lot of other stuff in that resource group?

      1. Luckily, I grated special resource group to follow your blogs. Trust is not blind ๐Ÿ˜Š You know the old joke. Developers never made backup, but they cry ๐Ÿ˜Š
        I would recommend to add resourceGroupRemovalPolicy to setting.json with following values: force, ask, merge
        Force โ€“ like it works now
        Ask โ€“ give the warring to the terminal. With possibility to cancel, continue (same as force), to give new value for resource group. It should be default value because otherwise developers will cry ๐Ÿ˜Š
        Merge โ€“ Create new resource group, if same resource group already exist, then add new resources inside existing resource group without deleting anything. It is the user responsibility to maintain that resource group overwhelming with portal
        Last one support ideas to Create multiple VM -in same RG. Think about running VM -s for bcsandbox:W1 and bcsandbox:us side by side to test or demo drive.

        Also I would recommend to create additional branch based on master for https://dev.azure.com/businesscentralapps/HelloWorld/_git/HelloWorld. Called Community Feedback, I hope name telling more why that. We can easily comment your code or will give feedback via some MD files. I feel the commenting blogs is not good way to handle that.

  5. Hi Freddy,
    How can I create pull requests for your Azure DevOps repository?

    1. FreddyDK says:

      Will check up on that and get back.

  6. Good to know: you need to update to Windows version 1809, otherwise some errors will occur: first an error about ProcessIsolation. Windows 1803 only supports hyperv. I changed this to hyperv in the CreateContainer.ps1 but got another error about Select INTO (SQL) scripts. So finally I updated to 1809 and all problems went away.

    1. By the way, great post and looking forward for more!

    2. FreddyDK says:

      NavContainerHelper should automatically determine process vs. hyperv isolation, but maybe I didn’t change this in CreateContainer.
      Will check.
      Thanks for the feedback.

  7. Hi Freddy, following your great blogs and giving this one a try. I’ve moved to 1809 to get over those issues, but things now seem to be failing when trying to ‘create admin as SQL User and add to sysadmin’. I’m in VS Code running as admin (although same result in PS ISE).
    If I simply run the “New-NavContainer -accept_eula -containerName “helloworld-dev” -auth NavUserPassword -imageName “microsoft/bcsandbox:us-ltsc2019” I can reproduce the error.

    Initialization of container helloworld-dev failed
    At C:\Program Files\WindowsPowerShell\Modules\navcontainerhelper\0.5.0.2\ContainerHandling\Wait-NavContainerReady.ps1:45 char:17
    + … throw “Initialization of container $containerName failed” …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (Initialization …orld-dev failed:String) [], RuntimeException
    + FullyQualifiedErrorId : Initialization of container helloworld-dev failed

    Any ideas?
    Thanks
    Ryan

    1. FreddyDK says:

      Sorry, didn’t see the info before now – did you resolve the issue? else please file an issue at http://www.github.com/microsoft/navcontainerhelper/issues, thanks

Skip to main content