MS D365BC Workshop Building Apps

Download as pdf or txt
Download as pdf or txt
You are on page 1of 130

Stefano Demiliani

Microsoft Technical Workshop [email protected]


@demiliani
http://www.demiliani.com
The path in front of us…
Today

Microsoft Code
On Premise
Dynamics NAV Modifications

Tomorrow

Dynamics
365 Code
SaaS
Business Extensions
Central
Customizations
Traditional way Extensions way

CUSTOM CODE CUSTOM EXTENSIONS

ADDON EXTENSIONS

Events
NAV LOCALIZATION NAV LOCALIZATION
LAYER LAYER

NAV BASE NAV BASE


LAYER LAYER
Integration and Business Events
Business Event: we commit not to change the definition of the event in the future.
Integration Event: we are not committed to anything. In a future version, we may change the definition of
the event without any problem.

NOTE: with NAV (C/AL), always check the Event


Subscription view (Tools → Debugger → Event
Subscription) where you can find all Subscribers
attached to a published event and if parameters
mismatch occours.

AL enforce this parameter check.


Event Recorder
WHAT Event Recorder allows a developer to run a specific scenario and record which events that are
fired
WHY Developers need a way to discover the events that are available for any given scenario. Event
Recorder will record all events that are run and generate code snippets for a developer to
quickly subscribe to events

HOW
Codeunit 1: no more!
• LogInManagement
• ReportManagement
• Application System Constants
• Conf./Personalization Mgt.
• TextManagement
• AutoFormatManagement
• CaptionManagement
• GlobalTriggerManagement
• SaaS Log In Management
• Company Information
• Custom Report Layout
• ODataUtility
• Data Upgrade Mgt.
OnCheckPreconditionsPerCompany Codeunit<Data Upgrade Mgt.>.PROCEDURE<OnCheckPreconditionsPerCompany>
OnCheckPreconditionsPerDatabase Codeunit<Data Upgrade Mgt.>.PROCEDURE<OnCheckPreconditionsPerDatabase>
OnInstallAppPerCompany NOT AVAILABLE ANYMORE
OnInstallAppPerDatabase NOT AVAILABLE ANYMORE
OnUpgradePerCompany Codeunit<Data Upgrade Mgt.>.PROCEDURE<OnUpgradePerCompany>
OnUpgradePerDatabase Codeunit<Data Upgrade Mgt.>.PROCEDURE<OnUpgradePerDatabase>
OnValidateUpgradePerCompany Codeunit<Data Upgrade Mgt.>.PROCEDURE<OnValidateUpgradePerCompany>
OnValidateUpgradePerDatabase Codeunit<Data Upgrade Mgt.>.PROCEDURE<OnValidateUpgradePerDatabase>
OnAfterAutoFormatTranslate Codeunit<AutoFormatManagement>.PROCEDURE<OnAfterAutoFormatTranslate>
OnAfterCaptionClassTranslate Codeunit<CaptionManagement>.PROCEDURE<OnAfterCaptionClassTranslate>
OnAfterCompanyClose Codeunit<LogInManagement>.PROCEDURE<OnAfterCompanyClose>
OnAfterCompanyOpen Codeunit<LogInManagement>.PROCEDURE<OnAfterCompanyOpen>
OnAfterFindPrinter Codeunit<ReportManagement>.PROCEDURE<OnAfterGetPrinterName>

OnAfterGetApplicationVersion Codeunit<Application System Constants>.PROCEDURE<OnAfterGetApplicationVersion>

Codeunit<GlobalTriggerManagement>.PROCEDURE<OnAfterGetDatabaseTableTriggerSetup
OnAfterGetDatabaseTableTriggerSetup
>

OnAfterGetDefaultRoleCenter Codeunit<Conf./Personalization Mgt.>.PROCEDURE<OnAfterGetDefaultRoleCenter>


OnBeforeOnDatabaseRename Codeunit<GlobalTriggerManagement>.PROCEDURE<OnBeforeOnDatabaseRename>
OnBeforeOpenSettings Codeunit<Conf./Personalization Mgt.>.PROCEDURE<OnBeforeOpenSettings>
OnEditInExcel Codeunit<ODataUtility>.PROCEDURE<OnEditInExcel>
OnRoleCenterOpen Codeunit<Conf./Personalization Mgt.>.PROCEDURE<OnRoleCenterOpen>
OnAfterGetGlobalTableTriggerMask Codeunit<GlobalTriggerManagement>.PROCEDURE<OnAfterGetGlobalTableTriggerMask>

OnAfterGetSystemIndicator Table<Company Information>.PROCEDURE<OnAfterGetSystemIndicator>


OnAfterHasCustomLayout Codeunit<ReportManagement>.PROCEDURE<OnAfterHasCustomLayout>
OnAfterMakeCodeFilter NOT AVAILABLE ANYMORE
OnAfterMakeDateFilter Codeunit<TextManagement>.PROCEDURE<OnAfterMakeDateFilter>
OnAfterMakeDateText NOT AVAILABLE ANYMORE
OnAfterMakeDateTimeFilter Codeunit<TextManagement>.PROCEDURE<OnAfterMakeDateTimeFilter>
OnAfterMakeText NOT AVAILABLE ANYMORE
OnAfterMakeTextFilter Codeunit<TextManagement>.PROCEDURE<OnAfterMakeTextFilter>
OnAfterMakeTimeFilter Codeunit<TextManagement>.PROCEDURE<OnAfterMakeTimeFilter>
OnAfterMakeTimeText NOT AVAILABLE ANYMORE
OnAfterOnDatabaseDelete Codeunit<GlobalTriggerManagement>.PROCEDURE<OnAfterOnDatabaseDelete>
OnAfterOnDatabaseInsert Codeunit<GlobalTriggerManagement>.PROCEDURE<OnAfterOnDatabaseInsert>
OnAfterOnDatabaseModify Codeunit<GlobalTriggerManagement>.PROCEDURE<OnAfterOnDatabaseModify>
OnAfterOnDatabaseRename Codeunit<GlobalTriggerManagement>.PROCEDURE<OnAfterOnDatabaseRename>
OnAfterOnGlobalDelete Codeunit<GlobalTriggerManagement>.PROCEDURE<OnAfterOnGlobalDelete>
OnAfterOnGlobalInsert Codeunit<GlobalTriggerManagement>.PROCEDURE<OnAfterOnGlobalInsert>
OnAfterOnGlobalModify Codeunit<GlobalTriggerManagement>.PROCEDURE<OnAfterOnGlobalModify>
OnAfterOnGlobalRename Codeunit<GlobalTriggerManagement>.PROCEDURE<OnAfterOnGlobalRename>
OnAfterReportGetCustomRdlc Table<Custom Report Layout>.PROCEDURE<OnAfterReportGetCustomRdlc>
OnBeforeCompanyClose Codeunit<LogInManagement>.PROCEDURE<OnBeforeCompanyClose>
OnBeforeCompanyOpen Codeunit<LogInManagement>.PROCEDURE<OnBeforeCompanyOpen>
OnBeforeOnDatabaseDelete Codeunit<GlobalTriggerManagement>.PROCEDURE<OnBeforeOnDatabaseDelete>
OnBeforeOnDatabaseInsert Codeunit<GlobalTriggerManagement>.PROCEDURE<OnBeforeOnDatabaseInsert>
OnBeforeOnDatabaseModify Codeunit<GlobalTriggerManagement>.PROCEDURE<OnBeforeOnDatabaseModify>
Extensions V2
An extension is an installable feature of Microsoft Dynamics NAV functionality built in a way that does not
directly alter source resources and distributed as a preconfigured package.

1. Developed on Modern Development Environment


2. All NAV / Dyn365BC functionalities are coded as objects
3. These objects are stored as AL code in .al files.
4. A single .al file may contain multiple objects
5. Table extension objects and Page extension objects are used for defining additive or
overriding changes to table or page objects.
6. Extensions are compiled as .app package files.
7. The .app package file can be deployed to the server / tenant
8. No DotNet variable support (built-in AL types, Azure functions)
Visual Studio Code
Open source, free, cross-platform, multi-language development tool in the Microsoft
Visual Studio family that runs on Windows, Linux, and Mac OS X.
code.visualstudio.com
• File and Folder based
• Debugger
• Git version control
• No compilers
• No designers
• Extensions (Visual Studio Code Marketplace)
AL Extension and Mac OS
• .vsix supports both Windows and Mac OS
• MacOS version must be 10.12 (Sierra) or newer
• Same functionalities as the Windows version BUT:
• Windows authentication is not supported.
• AAD authentication is using device login (http://aka.ms/DeviceLogin) to authenticate.
• RDL editing is not supported on Mac (Reports datasets, code, and requestpage can still be designed,
modified, and deployed)
• Word editing is limited. The "XML Mapping Pane" feature is not available in the MacOS version of Word so it
is not possible to add fields to the document.
Test / Demo Environments

http://aka.ms/bcsandbox
http://trials.dynamics.com (sandbox)

https://hub.docker.com/r/microsoft/bconprem
Business Central on-premise
AL Language
Visual Studio Code and the AL Language extension lets you do the following tasks:
• Create new files for your solution
• Get assistance with creating the appropriate configuration and setting files
• Use code snippets that provide templates for coding application objects
• Get compiler validation while coding
• Press F5 to publish your changes and see your code running on NAV

Extensions are compiled as .app package files.


AL Language
The following objects are available TODAY with the AL Language extension for Visual Studio Code:
• Table Object
• Table Extension Object
• Page Object
• Page Extension Object
• Codeunit Object
• Report Object
• XmlPort Object
• Query Object
• Control Add-in (Javascript)
• Profile & Page Customizations
AL: snippets
Events:
Objects: teventbus: allows to create business event
tpagecust: new customization of standard page teventint: allows to create integration event
tpageext: new extension of standard page teventsub: allows to create subscriber even
ttableext: new extension of standard table Fields and Keys:
tquery: new query tfield: new field without type (we need to put manually)
treport: new report tfieldbiginteger: Big Integer type
txmlport: new xmlport tfieldboolean: Boolean field
tpage: here we can choose either we want to get new List or new Card tfieldblob: Blob field
tcodeunit: new codeunit tfieldcode: Code field. You will need just to put length of field
Code: tfielddate: Date field
tcaseelse: case statelement with else tfielddateformula: Dateformula field
tcaseof: case statement without else tfielddatetime: Datetime field
tfor: for statement tfielddecimal: Decimal field
tforeach: foreach statement tfieldduration: Duration field
tif: if statement with begin and end. tfieldguid: GUID field
tifelse: if statement with begin and end else tfieldoption: Option field. In this case OptionMember property is
tisempty: isempty statement with begin end. automatically added
tisemptyelse: isempty statement with begin end else tfieldrecorid: RecordID field
trepeat: repeat loop with begin end tfieldtext: Text field. You will need just to put length of field
twhile: while statement tfieldtime: Time field
twith: with statement tkey: adding new key to table
Profile: Fields and Action on Pages:
tprofile: allow us to create new profile with page customizations tfieldpage: add a field to a page
taction: add an action to a page
Triggers:
ttrigger
tprocedure
AL: snippets

You can define your own snippets in VS Code:


- File → Preferences → User Snippets
- Select AL.json
Where are Extension’s fields?
• Extensions stored in NAV App Object Metadata table
• Fields are not visible in C/SIDE
• Fields are visible if you RUN the table
Dynamics 365 Business Central Extensions Range

• 50.000-99.999: per tenant/customer customizations (no appsource).


• 1.000.000-60.000.000: RSP range for partners that have an ISV solution for on premise /
D365BC. When used in Business Central these extensions are obtained as apps from appsource.microsoft.com.
• 70.000.000-74.999.999: This range is only available for extension development and only in
Business Central. These extensions are obtained as apps from appsource.microsoft.com.

Objects in Extensions are free!

You can use your CFMD object ranges


Dynamics 365 Business Central Sandbox
Environment totally isolated from a production instance where you can do development, testing, demos and
playing with the service without affecting the real production data.

https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-get-started-container-sandbox
Dynamics 365 Business Central: Sandbox
Environment totally isolated from a production instance where you can do development, testing, demos and
playing with the service without affecting the real production data.

Online Sandbox Container-based Sandbox

Dynamics 365 Cloud Service Run in Azure VM or locally

Managed by Microsoft Managed by partner

Same environment as production Container based environment

Visual Studio Code only Visual Studio Code. Supports also C/SIDE and SQL Management Studio

Production data manually uploaded using Configuration Packages Production data manually uploaded using Configuration Packages

Costs are part of the Business Central subscription Free if locally-hosted, Azure costs if hosted on Azure VM.

No Database access Database access available

Debugging available Debugging available


Dynamics 365 Business Central Sandbox
Online Sandbox:

You can reset your online sandbox environment at any time. Remember that resetting the sandbox will
completely remove and recreate it with demonstration data
Dynamics 365 Business Central Sandbox
Azure-hosted Sandbox:
What is Docker?

Leading cross platform software container environment

What is a Docker container and a Docker image?


• An image is a template with the minimum amount of OS, libraries and application
binaries needed
• A container is an instance of an image with an immutable base and it’s changes on
top
• A container is NOT a VM, you especially don’t have a GUI and nothing you can
connect to with RDP!

What is a Docker host?


• The (physical or virtual) machine where the containers are running
NAV/BC Container Image Architecture

Add Application /
Change settings Partner image or partner instance
Override scripts
+ Country database microsoft/dynamics-nav:ver[-rel]-loc
Run Install Scripts Specific
microsoft/dynamics-nav:ver[-rel]
+ parts of NAVDVD
+ Installation scripts
microsoft/dynamics-nav:generic Generic
+ SQL Express + IIS

Base image microsoft/windowsservercore / .net


D365BC on Docker (1)

Docker runs on Windows Server 2016 (or later) or Windows 10 Pro


D365BC on Docker (2)
D365BC on Docker (3)
Install Docker for Windows and select Switch to Windows Containers:
D365BC on Docker (4)
Before switching (default = Linux containers):

After switching:
D365BC on Docker (5)
From Command Prompt (running as Administrator):

docker run -e accept_eula=Y -m 4G microsoft/dynamics-nav


D365BC on Docker (6)
• docker images: returns the container list
• docker pull: docker image download (layers not in use)
• docker rmi: removes a docker image via the ID
• docker run: runs a docker image
• docker ps: shows the running container
• docker rm: removes a container ( –f if it’s running)
• docker inspect: shows the content of a container (JSON)
• docker logs: shows execution log for a container
• docker start/stop/restart <containername>
• docker commit: save the current status of a stopped container as a new container image
D365BC on Docker (7)
NavContainerHelper is a PowerShell module from the PowerShell Gallery that contains a number of
PowerShell functions, which helps running and interacting with NAV containers.
Start PowerShell ISE and run:
install-module navcontainerhelper -force

List of available commands:


Get-command –Module navcontainerhelper
Create a new NAV Container:
New-NavContainer -accept_eula -containerName "test" -auth NavUserPassword -imageName
"microsoft/bcsandbox:it" -licensefile "https://www.dropbox.com/stefano//mylicense.flf?dl=1" -Credential
$credential
Create a new NAV Container with your database backup:
$imageName = "microsoft/ bcsandbox:it"
$navcredential = New-Object System.Management.Automation.PSCredential -argumentList "admin", (ConvertTo-
SecureString -String "P@ssword1" -AsPlainText -Force)
New-NavContainer -accept_eula `
-containerName "test" `
-Auth NavUserPassword `
-imageName $imageName `
-Credential $navcredential `
-licenseFile "https://www.dropbox.com/stefano/abcdefghijkl/my.flf?dl=1" `
-additionalParameters @('--env
bakfile="https://www.dropbox.com/s/abcdefghijkl/Demo%20Database%D365BC-0%29.bak?dl=1"')
Docker based Demo Environments on Azure VMs

Full Control of the Server Azure costs


Business Central Container auto-shutdown is available
BC On Prem or BC Sandbox No Apps from AppSource
Your own solution (.fob, .bak) Not the “Real Thing”
Extensions v2
ARM templates to automate setup
http://aka.ms/getbc
Tips and tricks

• Use Windows Server if possible


• Use short and lowercase container names
• Use Windows Auth only if you are not disconnected from a domain
• Use NavContainerHelper
• Use UpdateHosts
Import your own solution (.fob)
• Create a secure Url to your .fob file
• https://blogs.msdn.microsoft.com/freddyk/2017/02/26/create-a-secure-url-
to-a-file/
• Use http://aka.ms/getbcext
• Specify the Secure Url in the Fob File Url field
Import your own extensions (.app)
• Create a secure Url to your .app files
• https://blogs.msdn.microsoft.com/freddyk/2017/02/26/create-a-secure-url-
to-a-file/
• Use http://aka.ms/getbcext
• Specify the Urls in the Include App Uris field
• Separated by comma or semicolon
Use Azure SQL database server
• Use http://aka.ms/getbcext
• Select Azure SQL in SQL Server Type
• Specify App and Tenant bacpac Uri
• Only Multitenancy
Add additional IP number to access Azure VM
• Go to https://portal.azure.com
• Locate the Resource Group
• Open the networksecuritygroup
• Select Inbound security rules
• Add your IP number
• IP number can be found on the landing page
Run a custom PowerShell script on your Demo VM
Place your PowerShell script online (github)
Obtain a Url to the script (secure or unsecure)
https://raw.githubusercontent.com/Microsoft/nav-arm-
templates/master/SetupWorkshop.ps1
Specify Script Url in Final Setup Script Url field
Reset Demo Environment
• Remove Resource Group and Create new

OR

• Connect to the Azure VM


• Open NavContainerHelper prompt
• Run Replace-NavServerContainer
• Add –alwaysPull if you want to download an updated image
• Add –imageName <imagename> if you want to use a different image
Application Areas
• Designed to simplify the user experience
• By hiding irrelevant controls from the user
• Page fields
• Page actions
• Report RequestPage options
• Enabled on Business Central online, cannot be disabled
• Mandatory for Business Central Apps on AppSource
• Controlled by Experience Tier
Setting Application Areas
• Set the ApplicationArea property on controls
• Comma separated list
• Application Area ‘All’ is always displayed
• Nothing displayed when Application Area is not set
Enabling Application Areas
Modern Development Environment for D365BC
Modern Development Environment for D365BC
Check the PublicWebBaseUrl property

NetFx40_LegacySecurityPolicy setting in the Microsoft.Dynamics.Nav.Server.exe.config file must be set to


false
You can find the file in: C:\Program Files\Microsoft Dynamics 365 Business Central\130\Service
AL Coding Guidelines
• “src” or “test” folder
• Group objects based on their functionality, like:
Naming Guidelines
• Each file name must start with the corresponding type and ID, followed by a dot for full objects or a dash for extensions.
• Full Objects: <Type><Id>.<ObjectName>.al → Tab.50100.MyTable.al
• Extensions: <Type><BaseId>-Ext<ObjectId>.<ObjectName>.al → page 50100 "MyPage" extends
"Customer Card“ → Pag21-Ext50100.MyPage.al
• It is required to use a prefix or suffix for the name property of the fields in your extension. You would then use the
Caption/CaptionML values for what to display to the user. This avoid collision of fields between extensions
• Tag must be at least 3 characters
• The object/field name must start or end with the tag
• If a conflict arises, the one who registered the tag always wins

• Example: MYPREFIXSalesPersonCode, SalesPersonCode_MYPREFIX


File structure

One object per file

For an object:
1. Properties
2. Object-specific constructs such as:
1. Table fields
2. Page layout
3. Actions
3. Global variables
1. Labels (old Text Constants)
2. Global variables
4. Methods
Referencing

Never reference per ID, only by name!

Page.RunModal(Page::"Customer Card", ...)

var
Customer: Record Customer;
Variable naming

• No Hungarian notation (Except for labels)


• PascalCasing
• Temporary variables have “Temp” prefix
• Objects must include the object name in the name

TempCustomer: temporary Record Customer;


Vendor: Record Vendor;
Method declaration
• PascalCasing
• Be as local as possible
• Separated with a blank line (automatically with the formatter)

local procedure MyProcedure(Customer: Record Customer; Int: Integer)


begin
end;

// space

local procedure MyProcedure2(Customer: Record Customer; Int: Integer)


begin
end;
VAR Handler Pattern
• OnBefore-Main Event Wrapper; Event gets raised:

• Pass Boolean to Event Publisher:


VAR Handler Pattern
• Respect Handler in Event Subscriber:

• Respect Handler in your main business function:


FunctionVisibility App.json

Internal: on-premise (target = Internal in app.json These settings affects possible features (File
External: SaaS (target = Extension in app.json) Management, DotNet, Excel Buffer)
D365BC: adding objects to Search
• You enable a page or report to be available through Search in Dynamics 365 Business Central using
the UsageCategory setting
• If the UsageCategory is set to None, or if you do not specify UsageCategory, the page or report will not show
up when you use the Search functionality
• The values for the UsageCategory property are:
• None
• Lists
• Tasks
• ReportsAndAnalysis
• Documents
• History
• Administration
AL: fields missing on Dynamics 365 Business Central
With D365BC, always add ApplicationArea

Application Area Setup table (9178)


Extensions: Code protection
DEFAULT: debugging into an extension to view the code is not allowed.

The app.json file contains a setting called showMyCode, which controls whether it is possible to debug into
the extension, when that extension is taken as a dependency

As default, in the app.json you have "showMyCode": false (hidden).

If you want to allow debugging into an extension to view the source code,
you can add the showMyCode property in the app.json file (the manifest) and set the property value to true

"showMyCode": true
AL Code Analysis
Four Code Analyzers available:
• CodeCop is an analyzer that enforces the official AL Coding Guidelines.
• PerTenantExtensionCop is an analyzer that enforces rules that must be respected by extensions meant to be
installed for individual tenants.
• AppSourceCop is an analyzer that enforces rules that must be respected by extensions meant to be published
to Microsoft AppSource.
• UiCop is an analyzer that enforces rules that must be respected by extensions targeted for Web Client
development

Possible to specify custom ruleset:


https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-rule-set-
syntax-for-code-analysis-tools
AL Code Analysis
From VS Code: File →Preferences → Settings

All code analyzers enabled

To select a specific analyzer:


AL: Enums
Option fields: great for scenarios where you want to provide a fixed, predefined list of values

But if you want to extend the list of values?

Enum: type that consists of a set of named constants


enum 50100 Level enumextension 50110 DiamondLevel extends Level
{ {
Extensible = true; value(50110; Diamond)
value(0; None) { } {
value(1; Bronze) { } Caption = 'Diamond Level’;
value(2; Silver) { } }
value(3; Gold) }
{
Caption = 'Gold Level’;
}
}

Table field: From code:


var
field(50100; Level; enum Level) {}
Level: enum Level;
case Level of
Level::Gold:

Text and TextBuilder data type
• TextBuilder based on .Net StringBuilder
• Including its functions like
• AppendLine
• Replace
• Text based on .Net String (it always was)
• New for Text functions like
• Contains
• StartsWith
• EndsWith
• Replace
• …

• Full list:
https://docs.microsoft.com/en-gb/dynamics365/business-central/dev-itpro/developer/datatypes/devenv-text-data-type
List and Dictionary data type

• Strongly type lists and dictionaries


• Based on .Net generic List and Dictionary
• Only possible with simple types (for now)
• Syntax:
• List of [Integer]
• Dictionary of [Integer,Text]
List example
AL: TextBuilder and XML Management
Dictionary Example
foreach
• Iterating over enumerable types in AL
• Current support for
• List
• XmlNodeList
• XmlAttributeCollection
• JsonArray
Dependencies

• An extension can depend on another extension


• Dependencies:
• Help structure more complex deployment scenarios
• Boost code and business logic reusability
• Increase maintenance flexibility
Referencing another Extension (1)
1) Retrieve the ID, Name, Publisher and Version of the Extension to reference
Referencing another Extension (2)
2) In app.json, create dependencies section:
Referencing another Extension (3)
3) Symbols will be downloaded and objects in the referenced extensions will
be visible on AL

• When you publish your extensions, you must do the extension that are depended on first (e.g. Parent). If you try and
publish the extension with the dependency first (e.g. Child), it will error stating that references do not exist in the
database.
• When you remove extensions, you must remove the extensions that have the dependencies first (e.g. Child)
Extensions Translations (XLIFF)
No more CaptionML!
Extensions Translations (XLIFF)
Use Caption and ToolTip:
Extensions Translations (XLIFF)

<yourapp>.g.xlf: automatically generated


<yourapp>.it-IT: manually generated
Get the translation file
Invoke package command (Ctrl+Shift+B) to
get the .xlf file
Translation file usage
• The generated translation file cannot be used as the translated file
• During every compilation, the generated translation file will be overwritten
with a new file
• Files need to be copied and modified
• You need one .xlf file per target language
• A translated file must contain:
• Target language attribute in the <file> element
• <target> element directly under the <source> element
• The <target> element must hold the translated value
• The <target> element must have an attribute state=translated
Automating translations
• Copy the generated .xlf file
• Tip: set the target language in the file name
• Use one of these tools to translate the file
• Microsoft Lifecycle Services
https://lcs.dynamics.com/

• Multilingual app toolkit 4.0 editor


https://developer.microsoft.com/en-us/windows/develop/multilingual-app-toolkit

• Virtaal
https://virtaal.translatehouse.org/
Extensions: field deletion
Launch.json: Default: schemaUpdateMode: Synchronize (no data loss every time you publish an extension)

To make schema changes (field deletion, data type change):


Extensions: schema changes
Extensions V2 do not support breaking schema changes across synchronized versions of the extension. Uninstalling
and unpublishing the 1.0 extension will not remove the schema elements coming from an extension.

In your local sandbox environment you can “clean” your environment in the following ways:
• From Visual Studio Code by using “schemaUpdateMode”: “Recreate” in launch.json
• From Powershell by executing the following command:
Sync-NavApp -Name <name of extension> -Version <Version of extension> -Tenant <Tenant name> -Mode Clean

In a production environment, once an extension is synchronized to a tenant then all the next versions
(upgrades) must have a schema that is backward compatible.
1. Mark the changed field with ObsoleteState = Pending or Removed.
2. Create a new table (or new fields or keys) with the new data type or values.
3. Create an Upgrade codeunit that moves the old data to the new data.
4. Use the new field or keys.
Extensions: schema changes
The ObsoleteState property can have these values:
• Pending: the element will be obsolete in a future release. This setting has no
effect on the current use of the table, field, or key in code.
• Obsolete or Removed: the element is not deleted from the database;
however, references to the the element in code are only allowed in upgrade
codeunits. References from other objects will result in a runtime error.
Debugging Extensions in D365BC sandbox
To enable AL debugging from VS Code we need to change the NetFx40_LegacySecurityPolicy setting in the
Microsoft.Dynamics.Nav.Server.exe.config file (in the Dynamics NAV service install directory) to
false:

<NetFx40_LegacySecurityPolicy enabled="false"/>

There are a number of limitations to be aware of:


• "External code" can only be debugged if the code has the ShowMyCode flag set.
• Not all AL types yet show helpful debugging.
• The debugger launches a new client instance each time you press F5. If you close the debugging session, and then start
a new session, this new session will rely on a new client instance.
• Using the debugger with the online sandbox signup and AAD authentication method is not yet supported.
Deploying Tenant Customizations to D365BC
• Object range: 50000-99999 (app.json). PerTenantExtensionCop code analyzer.
• Use Visual Studio Code and the AL extension
• Develop against a Dynamics 365 Business Central Sandbox or a Docker container
• Deploy the app directly to the production tenant through the Extension Management page (no PowerShell
needed!) If you are developing an extension as an update to a previously deployed extension, you must keep the app ID the same and increase
the version to successfully upgrade the extension to the new version.
Deploying Tenant Customizations to D365BC
Semi-Automatic Deployment
• set of Windows Power Shell cmdlets
• Only for on-premise sandbox environments

Retrieve container name:


Get-NavContainers

Publish the app:


Publish-NavContainerApp -containerName navserver -appFile C:\DEMO\TEST.app -skipVerification

Synchronize the metadata content:


Sync-NavContainerApp -containerName navserver -appName ALProject1

Install the extension:


Install-NavContainerApp -containerName navserver -appName ALProject1
Deploying Tenant Customizations to D365BC
Manual Deployment
• Most commonly used
• For all environments. Only allowed deployment methods for production tenants.
• Per tenant based (not Per Company)

Manage → Deployment Status to check deployment


Running C/SIDE and AL Side-by-Side

Use generatesymbolreference = YES as a command line argument each time you start
finsql.exe to have all compilations add a symbol reference to the NAV App Object Metadata table
(default = NO):
finsql.exe generatesymbolreference=yes

At server level, the Enable Symbol Loading at Server Startup flag must be enabled to allow any
symbol generation. If the setting is not enabled, the generatesymbolreference setting does
not have any effect.
DAY 2

Stefano Demiliani
Microsoft Technical Workshop [email protected]
@demiliani
http://www.demiliani.com
Source Control Mangement
• Why?
• AL is file based, so it is much simpler to do SCM
• There is no database anymore, only a compiled app
• Useful when working in teams (co-authoring, code reviews)
• Tie into daily builds (automated tests, continuous integration / continuous
deployment)

• VS Code has excellent, built-in support for source control, e.g.,


• Different SCM providers such as Git https://git-scm.com/ or Azure DevOps (formerly
TFS/VSO)
• Diff and merge views
• Browse history and move back to previous versions
• https://code.visualstudio.com/docs/editor/versioncontrol
GIT installation
• Install from https://git-scm.com/download/win
• Configure global git settings
• Provide username and email
GIT terminology
Source Control: Visual Studio Code & GIT
> git remote add origin
https://github.com/YourAccount/YourRepository.git
tells Git that the remote origin for the current folder (which contains the local repository) is the specified
URL
> git push -u origin master
pushes the content of the local repository into the branch called master
Source Control: Visual Studio Code & GIT
Source Control: Visual Studio Code & GIT
Source Control: Visual Studio Code & GIT
Source Control: Visual Studio Code & GIT
Source Control: Visual Studio Code & GIT
CI/CD in practice
• Use source control
• Merge changes to the master branch frequently
• Build the source code
• Deploy the .app
• Run the tests
• Track results & potentially gate
Simplest workflow
• Check-in, Check-out

• + Daily builds
• + Discard changes
• + History
• - No guarantee that the branch is stable

• Still a giant leap forward compared to NAV / CSIDE


Feature branches workflow
• Branch out
• Pull Requests
• Code reviews
• Tests

• + Stable master branch


• + Feature work in teams
• - Hard to hotfix existing release
Microsoft recommended workflow

• Cherry Pick hot fixes

• + x months cycles
• + hotfix existing releases
Installing Extensions: custom operations
• You can perform actions on data when installing an extension (populating tables, checks etc.).
• Install logic in written in an install codeunit. This is a codeunit that has the SubType property is set
to Install.
• You can have more than one install codeunit. Execution order is not guaranteed.
Installing Extensions: custom operations
Install codeunit syntax:
Uninstalling Extensions
Uninstalling an extension will not remove the data. Data are moved on archived tables :

Archive tables are handled with the NAVAPP.* commands

trigger OnUpgradePerCompany()
var
archivedVersion : Text;
begin
archivedVersion := NAVAPP.GetArchiveVersion();
if archivedVersion = '1.0.0.1' then begin
NAVAPP.RESTOREARCHIVEDATA(DATABASE::"My Table 1");
NAVAPP.DELETEARCHIVEDATA(DATABASE::"My Table 2");
end;
end;
Upgrading Extensions
• If there are no data changes between the versions of your extension, then you do not need to write
upgrade code.
• Upgrade logic must be written in an upgrade codeunit, which is a codeunit whose SubType property is
set to Upgrade.
• Syntax:
Upgrading Extensions

• PerCompany triggers are run once for each company in the database, where each trigger is
executed within its own system session for the company.
• PerDatabase triggers are run once in the entire upgrade process, in a single system session that
does not open any company.
Upgrading Extensions
Each extension version has a set of properties that contain information about the extension. These
properties are encapsulated in a ModuleInfo data type:

Start-NAVAppDataUpgrade -ServerInstance DynamicsNAV -Name MyExtension -Version 2.0.0.0


Upgrading Extensions
It’s possible to check dependencies before updating:
Reporting with AL
• Reports must be created as extensions (VSCode)
• Dataset defined in AL
• Modify the layout via Report Builder
Converting NAV reports to AL (1)
The procedure of converting NAV reports to Extensions goes as follows:
• Export NAV report(s) to a new syntax
• Convert it to AL code using txt2al tool
• Move it to Visual Studio Code environment
• Refactor the code and publish as the extension.
Converting NAV reports to AL (2)
Export the report to new syntax:

finsql.exe Command=ExportToNewSyntax, File=”C:\Stefano\Extensions\CAL\export.txt”, Database=”Demo


Database NAV (11-0)”, ServerName=.\NAVDEMO, Filter=Type=report;ID=50100
Converting NAV reports to AL (3)
Convert the report to AL code:

txt2al –source=”C:\Stefano\Extensions\CAL” –target=”C:\Stefano\Extensions\AL” –rename


Converting NAV reports to AL (4)
Open converted report in Visual Studio Code:

In VSCODE open the report and specify RDLC Layout property value to the path of your RDLC layout
DotNet with Dynamics 365 Business Central
Available in Preview only for On-Premise deployment
DotNet with Dynamics 365 Business Central
Declare a dotnet package:

dotnet
{
assembly(YOURASSEMBLY)
{
type(YOURDOTNETTYPE; ALIAS) {}
}
}
Isolated Storage
Data storage that provides isolation between extensions, so that you can keep keys/values in one
extension from being accessed from other extensions.
Isolated Storage
The DataScope Option Type identifies the scope of stored data in the isolated storage.
DataScope is an optional parameter and if it is not passed the value would be Module.

Member Description
Module Indicates that the record is available in the scope of the app(extension) context.
Company Indicates that the record is available in the scope of the company within the app context.
User Indicates that the record is available for a user within the app context.
CompanyAndUser Indicates that the record is available for a user and specific company within the app context.
API: new way for integration
Dynamics 365 Business Central exposes REST API for integration with other services.

Dynamics 365 Business Central: there are two different ways to connect to and authenticate against the APIs:
• Use Azure Active Directory (AAD) based authentication against the common API
endpoint: https://api.businesscentral.dynamics.com/v1.0/api/beta
• Use basic authentication with username and password (a so-called web service access key) against the
common API endpoint that includes the user domain, for
example https://api.businesscentral.dynamics.com/v1.0/cronus.com/api/beta.
Production: you must use Azure Active Directory (AAD)/OAuth v2 authentication and the common
endpoint https://api.businesscentral.dynamics.com/v1.0/api/beta.

To set up basic authentication:


1. Log into your tenant and in the Search field, enter Users
2. On the Users page, in the Web Service Access Key field, generate a key.
3. Copy the generated key and use it as the password for the username.
API: new way for integration
Dynamics NAV:

In Dynamics NAV, search for API Setup and then choose the related link.
On the API Setup page, choose the Integrate APIs button. This will start a process of populating all the integration tables
with records for all APIs.

All standard APIs are pages in range 5470 - 5528 with page type = API. Use them as templates to create your
own APIs.

http://ServerName:Port/NAVInstance/api/beta/ GET - read records


POST - insert record
PATCH - modify record
DELETE - delete record
API: new way for integration
Production Tenant
Business Central offers out-of-the box API endpoints to the base APIs. Like:

The list of all APIs https://api.businesscentral.dynamics.com/v1.0/<your domain>/api/beta


The list of companies https://api.businesscentral.dynamics.com/v1.0/<your domain>/api/beta/companies

The list of items https://api.businesscentral.dynamics.com/v1.0/<your domain>/api/beta/


companies(<companyId>)/items
API: new way for integration
Sandbox Tenant
You can access APIs in asandbox environment with the following URLs:

The list of all APIs https://api.businesscentral.dynamics.com/v1.0/<sandbox tenant id>/sandbox/api/beta

The list of companies https://api.businesscentral.dynamics.com/v1.0/<sandbox tenant


id>/sandbox/api/beta/companies

The list of items https://api.businesscentral.dynamics.com/v1.0/<sandbox tenant


id>/sandbox/api/beta/companies(<companyId>)/items
Available APIs (48)
Company Finance Sales Purchasing Reports
company accounts customers irs1099Codes (US only) agedAccountsPayable

companyInformation dimensions customerPayments purchaseInvoices agedAccountsReceivable

countriesRegions dimensionLines customerPaymentJournals purchaseInvoiceLines balanceSheet

currencies dimensionValues salesInvoices vendors cashFlowStatement

employees generalLedgerEntries salesInvoiceLines incomeStatement

items journals salesOrders retainedEarningsStatement

itemCategories journalLines salesOrderLines customerSales

paymentMethods salesQuotes vendorPurchases

paymentTerms salesQuoteLines trialBalance

shipmentMethods salesCreditMemos

taxAreas salesCreditMemoLines

taxGroups

unitsOfMeasure

picture, defaultDimension, attachments, pdfDocument


Filtering
• Follows Microsoft REST API guidelines
• salesinvoices/?$filter=status eq ‘Open’
Deep Insert
Enables creating a tree of related entities in one request

{
"invoiceDate": "2016-07-26",
"dueDate": "2016-08-26",
"customerId": "653053b1-d580-4102-845f-00df29a77e1e",
"salesInvoiceLines" : [
{"itemId":"5b0b9c1c-312d-4809-96b2-056690a11057", "quantity": 4},
{"itemId":"ad7220e5-8149-4cf0-a1e6-07d2bbbf414c", "quantity": 1}
]
}
Custom API endpoints

Production Sandbox

https://api.businesscentral.dynamics.com/v1.0/ https://api.businesscentral.dynamics.com/v1.0/
The list of all custom APIs <your domain>/api/<ApiPublisher> <sandbox tenant id>/sandbox/api/<ApiPublisher>
/<ApiGroup>/<ApiVersion> /<ApiGroup>/<ApiVersion>

https://api.businesscentral.dynamics.com/v1.0/ https://api.businesscentral.dynamics.com/v1.0/
The list of companies <your domain>/api/<ApiPublisher> <sandbox tenant id>/sandbox/api/<ApiPublisher>
/<ApiGroup>/<ApiVersion>/companies /<ApiGroup>/<ApiVersion>/companies

https://api.businesscentral.dynamics.com/v1.0/ https://api.businesscentral.dynamics.com/v1.0/
<your domain>/api/<ApiPublisher> <sandbox tenant id>/sandbox/api/<ApiPublisher>
The list of your entities
/<ApiGroup>/<ApiVersion>/companies /<ApiGroup>/<ApiVersion>/companies
(<companyId>)/<entitySetNames> (<companyId>)/<entitySetNames>
Custom API: rules

• Fields should be named in the APIs supported format


• Add Insert(true) for OnInsertRecord Trigger in the page. When you insert an entity through API endpoint,
Business Central don’t run OnInsert trigger on the table. And you remember – we assign the ID for the new
record there.
• Add business logic to the page OnModifyRecord trigger. Remember that an external user can change values
through API, even the value of the primary key field.
• Add Delete(true) for OnDeleteRecord page trigger.
SOAP Web Services
NAV: user credential passed on request
Dynamics 365 Business Central:
• Generate Web Service Key from User Card
• Pass username and web service key
Serverless business processes
Azure Functions is a serverless compute service that enables you to run code on-demand without having to
explicitly provision or manage infrastructure:
• Use the language you want
• Pay per use (low cost)
• Develop via the Azure Portal or other development tools (VS)
• Function runtime is open source
• Integrated security
• Templates for different scenarios (HTTPtrigger, TimerTrigger, Webhooks, BlobTrigger, QueueTrigger, …)
• Code-first

Recommended way to execute .NET code in D365BC SaaS environment


Business Central Connectors
Connector used to enable data flow, triggers and
actions between Business Central and PowerApps Microsoft Flow
& Microsoft Flow

Actions support all API endpoints

Supported APIs for triggers


Customers Journals
Vendors Purchase Invoices
Items Sales Orders
G/L Accounts Sales Quotes
Sales Credit Memo Sales Invoices

Azure AD Authentication
Support Read/Write of Business Central data

Designer first
Pre-built templates
Ready-made actions
Designed via browser or mobile app
To master all these topics…

You might also like