How to generate Azure Containers Instances loaded with Business Central in minutes

Standard

To start writing extensions for Business Central we have a few choices: installing locally one of the release candidates that comes in the same format as any other Dynamics NAV DVD packages, creating a locally hosted docker sandbox, or in Azure as a container instance.

As the process of getting your container takes just a few minutes, I prefer to do my extensions testing and development in an Azure container.

To generate my Azure container with Business Central I started by installing Azure CLI for Windows. You can also use chocolatey to install Azure CLI on your local machine.

In Visual Studio Code click on Terminal and in a powershell session start your Azure work by logging in your Azure account with

az login

1.Azure Login

If logged in already and want to check account logged info:

az_account_show

Next, we need to create a resource group, which is a logical container in Azure, something like an organization unit in Active Directory or a folder for Windows files.

The command is “az group create” and takes two parameters: group name and location:

create group

Once the resource group is created we can create the azure container instance loaded with the latest Business Central using the following Azure command:

az container create

containerIn the image above,

  • the group in which the container will be created follows “-g” (group) option: “svrg”
  • the name of the container follows the “-n” (name) option: “d365bc-az-cont-us-cont”
  • the image loaded on this container is stored here: “Microsoft/bcsandbox:latest”
  • the OS is Windows
  • We can only enter 5 ports: 80,7046, 7048, 7049, 8080

For a complete list of parameters for “az container create”, check this.

To check the logs, find the credentials to log in recorded by Azure for the previous command run “Az container logs” like below:

logs

As you have seen above, the admin credentials are displayed and the new Azure Business Central instance appears ready for connections. Lets check by browsing on the link for the web client:

Ctrl + Click on the web client link in the picture above opens the Business Central web client:

webclient

To see the newly container page in Azure navigate to the resource group and then to your container:

az_container_page

After entering the credentials from the logs we are in:

inbc

Good! We’ve got a Business Central instance in Azure running in a container and we’re ready to code and test extensions!

To get into this container in Visual Studio Code generate with AL:Go command a new AL project and change in launch.json the value for server token to the container dns name created above:

vscode to azure

In the next blog I’ll go through the steps of deploying an Azure container loaded with a Business Central image using deployment templates with parameters.

If you liked this article bookmark my blog or follow me for more stuff about NAV and Business Central.

Advertisements

Invoking Azure Functions to replace DOT NET calls in C/AL or AL

Standard

Recently Microsoft announced that dotnet can still be used with installations on premise of Dynamics 365 Business Central.

However, if our extension is to make it in the cloud the code leveraging dot net needs to be replaced with http api calls.

In this example I will show how a legacy C/AL code using dot net can be replaced with a call to an Azure function to achieve the original goal of validating a posting code.

Premise

  • Either Table 18 was modified and additional code was added in “Post Code” Validate trigger with Regex class entities to perform validation on post codes.
  • Or, the additional validation is executed when the Post Code Validate in standard is finished and a subscriber to Post Code Validate exists in our extension and is triggered, but still contains dot net code(RegularExpressions class entitites) as we’re only dealing with on-premise (target=internal in app.json)

Objective

I want the additional validation to be executed when the standard validation is finished and the additional validation to not contain dotnet calls.

Design

  1. In a new AL project add a new codeunit:

add_al_codeunit

2. The codeunit itself contains an event subscriber to Table18.Validate.PostCode.

(Use “teventsub” snippet to get the quick scaffolding of the event subscriber)

codeunit_content

When the subscriber is triggered we are executing an Azure Function call: azfnvalidate-us-ca-zipcode. We’re retrieving a json object whose content is : {“PCValid” : true} or {“PCValid” : false}.

3. Write the Azure Function with Visual Studio Code

Pre-requisites:

  • Azure subscription
  • install C# extension
  • Azure Function Core Tools extension
  • install .net core (use npm or chocolatey)
  • Azure CLI Tools

VSCodeExtensions

A good guide to get you started with Azure Functions is here.

Once you have the default “Hello World” Azure Function created, replace your Run function with:

azFn

Publishing the function in Azure should generate a record in your chosen storage:AzureFninPortal

Testing

  1. Once published we can quickly spin a test for the new Azure Function in a web browser window:

web_browser_test

2. Removing the “W” in the previous test, triggers the Azure Function to return above json.

web_browser_invalid_postcode

3. Let’s test now the validation in Business Central:

ezgif-3-34f9ae149c11

Therefore, to replace a set of dotnet calls we need a worker placed somewhere else other than in AL or C/AL and a caller of that worker services placed in the extension. In my example use a codeunit (caller) in the extension range with a subscriber event defined that calls an Azure function(worker).

What other methods are you employing to achieve similar results ?

If you liked this article bookmark my blog or follow me for more stuff about NAV and Business Central.

Dynamics 365 Business Central : Extending Role Center headline with web service data, lists and dictionaries

Standard

So much to read, so little time … the speed at which Microsoft adds new Business Central and AL features is overwhelming 🙂

In this blog I’ll demonstrate how I was able to display weather temperature for 3 cities in Business Central role center headline.

ezgif-3-ef3a02f8f885

First, there are 9 headline role center pages in Business Central, with ID from 1440..1448.

headline pages

I will extend the headline role center for the page 1440 : “Headline RC Business Manager”, by adding three fields, one for each city and its temperature.

To record the three cities and their temperatures I am using here a list and a dictionary data structure.

Fields_And_DataStructures

This is followed by a querying of a weather web service and recording of the 3 cities and their temperatures in a dictionary:

Query Web Service

Commented is the response from the web service.

I need data stored in the following tokens:

  • $main.temp
  • $sys.country
  • name

For more info on how to parse web service response take a look at Mr. Kauffman blog.

json

I use a free web service for weather openweathermap. You need to create an account and you will get a free APPID when you complete the registration. You can only query the web service once every 10 minutes for the same location.

Finally, to load cities and their temperatures in your headline use the code below:

CityTemp

The complete pageextension object is included here.

That’s it … thanks for reading!

Original post here.

NAV 2017 – Delivering custom code as extension

Standard

We can still deliver our custom code as a fob in NAV 2017 as most VARs will continue to do so in the foreseeable future, however it seems to me that ISVs will embrace faster the new method. While in my first blog on extensions I was focused on explaining the basics of the technical side of creating an extension, in this blog I will delve into delivering a functional requirement as an extension.

I will go through an exercise of adding a new field: “Created By” Code 20 (a valid user from User table)  to Sales documents.

If you’re planning to follow this exercise please review “Setting up your working space” from my previous blog.

I will make this new field available on:

  • Table 36 “Sales Header”
  • Table 112 “Sales Invoice Header”
  • Table 114 “Sales Cr. Memo Header”
  • Page 43 “Sales Invoices”
  • Page 44 “Sales Credit Memo”
  • Page 132 “Posted Sales Invoices”
  • Page 134 “Posted Sales Credit Memo”.

The field will be passed on and made visible on

  • Page 20 “G/L Entries” and
  • Page 25 “Cust. Ledger Entries”

when we drill down on different tables exposed via Navigate action on the posted document.

At this moment, delta files for reports (standard report modifications) cannot be part of an extension. Please visit Extension Packages Capability Support Matrix for updates on this topic.

Therefore my attempt to modify the report 1306 to add the new field in the layout and report failed:

ext21

Delivering modifications to reports must be done in a different way. One alternative is to add a new action on the Posted Sales Invoice and point to a copy of report 1306 (modified to include our field). Therefore our custom code won’t be extension-only based.

This link contains a fob with all the modifications done to a Demo Database 2017 CU9.

The steps to create and publish the extension are very similar to the steps in my previous blog located here.

Let’s test the changes by pointing our Service tier to the target database and publish there the new extension.

First let’s install the extension, by opening page 2500 “Extension Management”:

ext22

Let’s open Sales Invoice page and create a new invoice. The “Created By” field should be in the first FastTab and auto-populated with the logged in user:

ext23

After posting the invoice we notice that the new field is part of the “Posted Sales Invoice” as well:

ext24

Next we want to check the existence of this new field in page “General Ledger Entries” and page “Cust. Ledger Entries”. In the “Posted Sales Invoice” page, in the Actions tab, click on Navigate, and check the 2 pages:

Ext25

ext26

At the core of this simple exercise is the codeunit 50000 in which I subscribed in a few instances to standard events like OnAfterInsertEvent:

 ext28

Thank you for reading, sharing, commenting, liking, following 🙂

 

How To : 5 Easy Steps to generate your First NAV Extension

Standard

Thank you for landing here.

It’s quite common nowadays to hear NAV people talking about Dynamics 365, AppStore, extensions, new AL language and the Visual Studio Code.

So extension is a concept that sooner or later NAV developers need to grasp.

In this blog I will create one simple extension. I have seen a few demos on the web, but I had  a few issues following them. I will highlight these issues as I go.

I encourage everyone to visit msdn page on this topic.

1. Setting up your working space

On my development machine I installed NAV 2017 CU 9. I will be working with 3 databases which initially will be restored from your NAV DVD, from the folder below:

SQLDemoDatabase\CommonAppData\Microsoft\Microsoft Dynamics NAV\100\Database
  • restore via SQL Server Management Studio the Demo database as Demo Database NAV (10-0) (we won’t touch this – it will be our ORIGINAL DB)
  • restore via SQL Server Management Studio the Demo database as TestExtension (we will make modifications on this database – it will be our MODIFIED DB)
  • restore via SQL Server Management Studio the Demo database as ApplyExtension (we will install our extension here – it will be our TARGET DB)
  • create a NAV service(I named mine TestExtension) pointing to the database you will be working with in the development environment, in our case is TestExtension
  • created 3 folders on your local drive: ORIGINAL, MODIFIED, DELTA

2. Create extension content

I added field 50000 “Planet No.” – Integer on table 14 Location.

I added this new field to Page 15, “Location List”.

I created a new codeunit, 50000, TestExtension, with 2 empty and local functions:

Extension1

And these are the 3 objects:

Ext2

3. Populate local folders: ORIGINAL,MODIFIED and DELTA:

a. Populate ORIGINAL:

Point Service tier towards Demo Database NAV (10-0) and from Dev. environment export all objects (or just Table 14 and Page 15 if you want a faster text file processing) as Original.txt. As this file contains a concatenation of all objects we will need to split the big file into smaller ones (one per object). In the ORIGINAL folder create a Split folder. From the Dynamics NAV 2017 Administration Shell run:

Split-NAVApplicationObjectFile -Source .\original\*.txt -Destination .\original\split\

And this is the end-result:

ext3

b. Populate MODIFIED

Point Service tier towards TestExtension and from Dev. environment export all objects (or just Table 14 and Page 15 if you want a faster text file processing) as Modified.txt.
For the same reason as in the previous step split big Modified file:

 Split-NAVApplicationObjectFile -Source .\Modified\*.txt -Destination .\Modified\split\

c. Populate DELTA

To create Delta files run:

Compare-NAVApplicationObject -OriginalPath .\ORIGINAL\SPLIT\ -ModifiedPath .\MODIFIED\Split\ -DeltaPath .\DELTA\
Processed 4965 objects:
 Inserted 1 objects
 Deleted 0 objects
 Changed 2 objects
 Identical 4963 objects
 Failed 0 objects

Have a look at the composition of a Delta file:

ext4

4. Create NAVX file (extension file)

From the Microsoft Dynamics NAV 2017 Administration Shell run:

 New-NAVAppManifest -Name "FirstExtension" -Publisher "SVIRLAN.com" -Version "1.0.0.0" | New-NAVAppPackage -Path FirstExtension.navx -SourcePath .\DELTA

5. Publish extension

To publish the new extension in the ApplyExtension database, point your service tier towards the ApplyExtension database and from the Microsoft Dynamics NAV 2017 Administration Shell run:

 Publish-NAVApp -Path .\FirstExtension.navx -ServerInstance TestExtension -SkipVerification

Open page 2500 “Extension Management” and click Install on our new extension:

ext5

You can Un-install the extension(via action on Page 2500) and you can Un-publish it via “Un-Publish” powershell command.

Facts:

Let’s have a look at what we’ve got by applying our extension to the ApplyExtension database:

The Locations page contains the new field:ext6

But when looking at the objects we dont see the codeunit 50000, the new fields nor the changes in the Version List:

ext8

ext9

Moreover, trying to add the field 50000 in the Location table prompts this system error:

ext7

This makes sense!

The code in table14 and Page 15 remained as delivered by Microsoft, and the extension fields are somehow managed internally via system objects like tables 2000000150 – 2000000163.

Issues encountered:

1. First error I encountered was: “The package contains changes to the database schema that are not handled in upgrade code.”

I needed a codeunit to subscribe to standard published events:
That’s the reason I have codeunit 50000 and the 2 functions:
OnNavAppUpgradePerDatabase()
OnNavAppUpgradePerCompany()

PS C:\docs\blogs\Extensions> New-NAVAppManifest -Name "Proseware SmartStuff" -Publisher "Proseware, Inc." -Version "1.5.0.12" | New-NAVAppPackage
 -Path MyExtension.navx -SourcePath DELTA
 New-NAVAppPackage : The package contains changes to the database schema that are not handled in upgrade code.
 At line:1 char:100
 + ... 1.5.0.12" | New-NAVAppPackage -Path MyExtension.navx -SourcePath DELT ...
 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 + CategoryInfo : InvalidArgument: (Microsoft.Dynam...ewNavAppPackage:NewNavAppPackage) [New-NAVAppPackage], InvalidOperationExcepti
 on
 + FullyQualifiedErrorId : Microsoft.Dynamics.Nav.Apps.Tools.NewNavAppPackage

2. Second issue happened when running the Publish-NAVApp command: “Access is denied. You need to be a member of the local Administrators group on the server to run this cmdlet.”

Need to run powershell as Admin:

PS C:\docs\blogs\Extensions> Publish-NAVApp -Path .\FirstExtension.navx -ServerInstance TestExtension -SkipVerification
 Publish-NAVApp : Access is denied. You need to be a member of the local Administrators group on the server to run this cmdlet.
 At line:1 char:1
 + Publish-NAVApp -Path .\FirstExtension.navx -ServerInstance TestExtens ...
 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 + CategoryInfo : NotSpecified: (:) [Publish-NAVApp], NavCommandException
 + FullyQualifiedErrorId : MicrosoftDynamicsNavServer$TestExtension,Microsoft.Dynamics.Nav.Apps.Management.Cmdlets.PublishNavApp

3. In case any of the powershell cmdlets is not recognized in your environment run:

PS C:\docs\blogs\Extensions> Import-Module “C:\Program Files (x86)\Microsoft Dynamics NAV\100\RoleTailored Client\Micro
soft.Dynamics.Nav.Model.Tools.psd1” –force

Thank you for reading, sharing, commenting, liking, following 🙂