Publishing apps to a Business Central Online Environment

There are 2 kinds of apps: AppSource Apps and Per Tenant Extensions (PTEs). These apps can be installed in two kinds of environments: Sandbox and Production. In Production, AppSource Apps are installed in the global scope and Per Tenant Extensions are installed in the Tenant Scope. In Sandbox environments you can also install apps to the development scope (like what VS Code does).

This blog post will describe how you can use BcContainerHelper 2.0.2 to install apps in any of those combinations.

The reason why these functions are placed in BcContainerHelper is that these functions are used in CI/CD pipelines. Some to install dependency AppSource Apps before compilation, some to publish PTEs to online production or sandbox environments after compilation, some to make the initial installation of xx PTEs to prepare for VS Code development.

This blog post will describe how to publish/install the apps, a later blog post will tie things together in a pipeline and more.

Obtaining a BcAuthContext

Please read this blog post in order to learn how to authenticate to your online Business Central environment and obtain a BcAuthContext.

In the samples below, I have read the $refreshToken from a keyvault and will use that to create an auth context and run the code to perform the scenario.

Publishing PTEs to the Tenant Scope in a Production or Sandbox Environment

The output of my sample HelloWorld PTE example can be downloaded here: https://businesscentralapps.blob.core.windows.net/githubhelloworld/latest/apps.zip.

You can publish and install the hello world sample to an environment called Sandbox in the tenant authenticated to by the refreshtoken by running this script:

$authContext = New-BcAuthContext -refreshToken $refreshToken
$environment = 'Sandbox'

$apps = "https://businesscentralapps.azureedge.net/githubhelloworld/latest/apps.zip"
Publish-PerTenantExtensionApps `
    -bcAuthContext $authContext `
    -environment $environment `
    -appFiles $apps

The .zip file will be unzipped and the apps in the .zip file will be installed in order of dependencies. You can also specify an array of app files/url or a comma separated string of app files/urls.

The output of this command could look like this:

Where the … represents a number of other apps installed in my environment.

If you run the same function again, it will fail. When using Publish-PerTenantExtensionApps you need to increase the version number in order to publish a new version of your app.

Installing AppSource Apps in the Global Scope in a Production or Sandbox environment

My sample BingMaps app also exists in an AppSource version available in US and DK. The App ID for the BingMaps App is: d22ff4b4-eff0-46cd-8d63-f28e7f646e33.

At this time, the App Management part of the Business Central Admin Center Api does not support installing AppSource Apps (it is in the backlog). It is however possible through a well known page in Business Central if you know the App ID. The URL for installing an app in a Business Central tenant is:

https://businesscentral.dynamics.com/[TenantID]/?noSignUpCheck=1&filter=%27ID%27%20IS%20%27[AppID]%27&page=2503 

where [TenantID] is your AAD Tenant ID and [AppID] is the App ID of the App you want to install. In BcContainerHelper 2.0.2 there is a function called Install-BcAppFromAppSource, which uses this page to install an app in a Business Central online environment.

The function uses a DLL called Microsoft.Dynamics.Framework.UI.Client.dll (like Run-TestsInBcContainer) to connect to the Business Central Client Services endpoint and emulate a user. This DLL is present in the Artifacts and on the DVD. Easiest way to ensure we have the right versions of his DLL and dependencies is to create a container with the same version as your online environment and connect from within that container.

The code to install the BingMaps.AppSource app in the production environment looks like this:

$authContext = New-BcAuthContext -refreshToken $refreshToken
$environment = "Production"
$appId = "d22ff4b4-eff0-46cd-8d63-f28e7f646e33"
$appName = "BingMaps.AppSource"
$env = Get-BcEnvironments -bcAuthContext $authContext |
    Where-Object { $_.Name -eq $environment }
$app = Get-BcPublishedApps -bcAuthContext $authContext -environment $environment |
    Where-Object { $_.Name -eq "Base Application" }
$artifactUrl = Get-BCArtifactUrl `
    -country $env.countryCode `
    -version $app.Version `
    -select Closest
New-BcContainer `
    -containerName proxy `
    -accept_eula `
    -artifactUrl $artifactUrl `
    -filesOnly
Install-BcAppFromAppSource `
    -containerName proxy `
    -bcAuthContext $authContext `
    -environment $environment `
    -appId $appId `
    -appName $appName `
    -allowInstallationOnProduction
Remove-BcContainer `
    -containerName proxy

Note that you need to add -allowInstallationOnProduction to Install-BcAppFromAppSource in order to Install on a production environment, else the function will fail. This is to make sure that you don’t install any apps in the wrong environment by accident.

Once the admin center supports this, I will refactor the Install-BcAppFromAppSource function and you won’t need to create the container anymore, meaning that a lot of the code above can be deleted. The output of the function today could look like this:

As you can see, majority of the output is creating a filesOnly container, which is much faster than creating a “real” container. More about what a filesOnly container can be used for in a later blog post.

If the app is already installed, this function will return. This function cannot be used to upgrade an app. The primary reason for this function is to be able to install dependencies in an online environment for your development or to install the Test Runner in a pipeline in order to run automated testing on an online environment.

I will modify this blog post when the container is no longer needed.

Publishing apps to the Development scope in a Sandbox environment

Both AppSource apps and PTEs can be published to the Development scope in a Sandbox environment. This is what VS Code does when you press F5 and obviously you cannot publish to the development scope in a Production environment.

Publishing Apps to the development scope in a container is done using a function called Publish-BcContainerApp. This function is used extensively in pipelines, so I decided to add two parameters to this function (BcAuthContext and environment) and with these parameters, allow the function to publish to an online Business Central sandbox environment. If publishing to an online environment, you do not need to specify a container.

$authContext = New-BcAuthContext -refreshToken $refreshToken
$environment = "Sandbox"

$apps = "https://businesscentralapps.azureedge.net/githubhelloworld/latest/apps.zip"
Publish-BcContainerApp `
    -bcAuthContext $authcontext `
    -environment $environment `
    -appFile $apps

This should provide an output like this:

The function downloads the .zip file, unpacks, sort by dependencies, publishes one by one.

If you run the exact same function again, it will fail. You cannot publish the same app twice. If you recompile, it will succeed. You do not need to update the version number, it just needs to be a different package id (a new compilation)

One way you can use this function is when you setup a new sandbox environment and you have a series of PTEs to publish in order to start developing. You can publish the lot using this function and VS Code is ready for RAD afterwards.

Enjoy

Freddy Kristiansen
Technical Evangelist

12 thoughts on “Publishing apps to a Business Central Online Environment

  1. Pingback: Publishing apps to a Business Central Online Environment | Pardaan.com

  2. Hi,
    Once again thank you for all those improvements in BcContainerHelper.
    Being able now to install within Development Scope is really helpful to manage App Source published extensions.
    We’re now still facing a small issue while deploying to sandboxes. As specified a package cannot be deployed twice and that’s fine, but it seems this is not only true by Sandbox but rather for all sanboxes within same tenant?

    Within a same Tenant including 2 Sandboxes ex. Dev and Master, Pipeline can successfully deploy first one on master, but fails while deploying same package (same version id in our context as number created by build pipeline) on Dev Sandbox. We did not find a way to deploy same version/package on 2 different sandbox.
    Is there any workaround except creating a different builds and in our actual context meaning different versions ?

    Like

  3. Hi,

    Are we able to publish to the development scope with Client_Credentials flow?

    We have tried with the script below:

    $bcAuthContext = New-BcAuthContext `
    -clientID $myClientId `
    -clientSecret $myClientSecret
    Publish-BcContainerApp `
    -bcAuthContext $bcAuthContext `
    -environment “Sandbox” `
    -appFile ‘C:\Default publisher_publication_1.0.0.0.app’`
    -Verbose

    And we get the following error:

    COMMENTS : GET https://api.businesscentral.dynamics.com/admin/v2.3/applications/BusinessCentral/environments with 0-byte payload
    The remote server returned an error : (403) Forbidden. (ms-correlation-x = c17982d4-9fc0-4a16-90df-878b9c0557c7)
    At char C:\Program Files\WindowsPowerShell\Modules\BcContainerHelper\2.0.4\BcSaaS\Get-BcEnvironments.ps1:29 : 9
    + throw (GetExtenedErrorMessage $_.Exception)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (The remote server…f-878b9c0557c7):String) [], RuntimeException
    + FullyQualifiedErrorId : The remote server returned an error : (403) Forbidden. (ms-correlation-x = c17982d4-9fc0-4a16-90df-878b9c0557c7)

    The application has the following permissions: Automation.ReadWrite.All + app_access

    Is there more to do?

    Liked by 1 person

  4. Pingback: Running tests in Business Central Online Sandbox environments | Freddys blog

  5. Hi Freddy, I’ve a general question regarding publishing apps to a docker container – not to an online sandbox.
    I just saw in this post that Publish-BCContainerApp should publish the apps in dev scope, But in our case it’s always publishing to global scope. Do you have any idea why that happens to us? Is there a setting we’re missing that allows us to publish to dev scope?

    Like

  6. Publishing apps to the Development scope in a Sandbox environment

    What would happen if I publish a future AppSource App in a Sandbox & the Development Scope & afterwards I install the the same app from AppSource?

    Like

    • Exactly the same as if you publish the app from VS Code and then afterwards install the same app from AppSource.
      My guess is that you can only install from appsource if that version number is higher and the upgrade works.
      Note that apps published to development scope are not guaranteed to survive a BC upgrade.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s