PIPrint – A Free Direct Printing Solution for your Microsoft Dynamics 365 Business Central

…and Now for Something Completely Different…

Some of you might recall that this blog is not limited to posts about Echelon/NES meters, and know it is actually for all kind of stuff Graves and I am dabbling with. Granted, lately it’s been mostly about our Echelon/NES project – but we have not stopped dabbling with other stuff too :-).

You might know that my day job is to develop solutions in Microsoft Dynamics 365 Business Central (I’ll call it BC in this entry), and for some time I had an idea I would like to share with the community:

As some of you might know, the BC web client and Microsoft’s chosen path has made it quite an expensive challenge to do direct print (direct print is when you do a print directly to a printer – without the user having to i.e., download a PDF and then print it manually).

Microsoft do have a solution called Universal Print and BC supports it along with e-mail enabled printers. You can read more about both solutions here! The main problem – if you printer does not support e-mail printing, is that Universal Print is quite expensive.

Others also have solutions for this – and it might even be included in something more advanced like ForNAV Direct Print.

But why didn’t someone design and do a cheap, Do-It-Yourself solution?

…and – if you are on BC SaaS, but still need a simple, cheap solution to print on local and cheap printers? Or even Network printers that does not support e-mail printing?

And off cause we should try to keep it as cheap and simple as possible – and don’t rely on any special ports to be forwarded and open in firewall etc. That is simply too cumbersome for regular users to setup!


BC App – maybe a Per Tenant Extension?

Well, imagine installing an app on your BC that collects all printjobs as PDF and store them in a BC table. Then making them available through a webservice of some kind… While at it we could do a secondary webservice allowing “Print Processors” (I’ll explain what that is in a minute) to register printers with BC, so they are available for printing directly in BC.

We must do it, so we are able to install and use it for both BC OnPrem and BC SaaS, right?


So, what is this “Print Processor” thingy and what does it run on?

Well, it is something that can obtain a list of available printers and call a BC webservice to tell BC about them. It should also call a BC webservice at some interval to see if there are any print jobs (PDFs) waiting, and if so – fetch the PDFs and print them. For the last part we can simply rely on solutions other created – it cannot be that hard to print a PDF, right?

Ideally the “Print Processor” should be available on multiple platforms, it only has a few requirements:

  • Connect to the network so it can call BC webservices (Internet if BC SaaS)
  • Call webservices and handle the result
  • Connect to the local printer (network, USB etc.)
  • Print a PDF to a local printer

Ideally it could just be some kind of script? Python for Linux and other Unix like systems (some NAS servers even run Unix like systems). And maybe PowerShell for Windows while we are at it?


Really – how hard can it be to pull this off?

Well – https://github.com/DabblerDK/PIPrint

This is in NO WAY final “production” quality software, but feel free to use it on your own costs and risk and build on it.
Release it commercially, use it privately etc.
Please always keep a reference to this blog somewhere people see when they use it. And please give back any improvements to the GitHub repository and the community…

Enjoy…

Game On – or Game Over?

ALTris app logo

A few weeks ago Erik Hougaard challenged me (or I challenged myself?) in comments on one of Erik’s YouTube videos to re-implement my C5Tris game for Microsoft Dynamics C5 in AL for Microsoft Dynamics 365 Business Central (BC).

Off cause BC supports Java Script control add ins, but downloading a Java Script Tetris clone and simply calling it in a BC JavaScript control add in would not really be a challenge at all.

The true nature of the challenge must be to create a playable Tetris clone in AL, controlled by AL and only use a minimum amount of HTML and Java Script.

On top of that the game should probably be implemented with very few AL objects, to limit the footprint when installing. And why not add controls with the cursor keys and game sound effects now we are busy anyway?

Challenge accepted!

In this link you will find a ZIP-file with the source code, but if you just want to install the app in your BC, you can just download the app file here!

If you just want to see it – well here we go (disclaimer: I’m a developer, NOT a gamer!)

ALTris was developed in BC14, but as BC apps are compatible with other versions it should be installable and playable on other versions too. It probably also helps that I’m not using a bunch of calls to the standard BC base application. I didn’t find any usable – probably Microsoft didn’t think of BC as much of a games platform :-).

Feel free to use the code, look into the code, change the code, complain about the code or whatever you prefer as long as you keep my name, SIMTEQ A/S and links to my LinkedIn and SIMTEQs homepage in there.

Use this code on your own risk and costs…. and enjoy!

Updates:
* 2020-09-08: Found and fixed a few spell bugs (text only), so we are now at version 1.0.0.1 🙂

No online help in Microsoft Dynamics Business Central 2019 wave 1 (aka BC14) On-Premises

Dynanmics 365 Business Central logo

Did you also wonder where the English and Danish (and probably other languages as well) help pages went?

In Microsoft Dynamics Business Central 2019 wave 1 aka Business Central 14 (and possible newer versions) after the RTM-release in April 2019, the help simply does not work out-of-the-box anymore.

It seems Microsoft are more focused on the SaaS solution these days and the On-Premise version is suffering a bit from it.

Note: I’ve actually contacted Microsoft about these help issues, but due to the SaaS focus and the help beeing a community effort now (see https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/help/contributor-guide), they are actually NOT planning to fix this! Also they are trying to reduce the size of the install DVD.
That is an unofficial answer though, so if we all report it, they might change their minds :-). For now this is something you need to repair in your installation yourself – i.e. by following this blog post…

This is actually two “errors”:

(1) If you have selected the en-US language and you try to open the help using the icon or CTRL+F1 you get this:

Server Error in '/' Application.
Runtime Error
Server Error in ‘/’ Application. – Runtime Error

…actually this is quite easily fixed. The English language is per default installed in “C:\inetpub\wwwroot\DynamicsNAV140Help\help\en”, but BC is trying to open it from “C:\inetpub\wwwroot\DynamicsNAV140Help\help\en-US”. So let us just create a link:

C:>cd C:\inetpub\wwwroot\DynamicsNAV140Help\help

C:\inetpub\wwwroot\DynamicsNAV140Help\help>mklink /d en-US en
symbolic link created for en-US <<===>> en

C:\inetpub\wwwroot\DynamicsNAV140Help\help>dir
Volume in drive C has no label.
Volume Serial Number is C6AF-373F
Directory of C:\inetpub\wwwroot\DynamicsNAV140Help\help
06/23/2020 07:03 AM
.
06/23/2020 07:03 AM ..
03/30/2020 10:53 AM da-DK
03/30/2020 10:53 AM en
06/23/2020 07:03 AM en-US [en]
01/31/2020 07:11 AM 22,060 feedback.js
03/30/2020 10:53 AM local
01/31/2020 07:11 AM 79 shortcutCold.gif
2 File(s) 22,139 bytes

…problem solved 🙂

2020-10-05 GL: Please see Jani Kivilähde’s comment below: “For fix (1), the use of SYMLINK breaks the search in Help Server. Windows Search does not traverse SYMLINKs.”. So the correct fix is – as mentioned by Jani – to rename or copy the folder.

(2) If you on the other hand have selected the da-DK (Danish) language – or presumable any other language besides en-US, you’ll get this error:

404 - File or directory not found.
404 – File or directory not found.

…and if you have a look at the server in the destination folder “C:\inetpub\wwwroot\DynamicsNAV140Help\help\da-DK”, you’ll discover why:

Slim da-DK help (missing files)
Slim da-DK help (missing files)

Actually, I’ve checked most versions of the Danish install DVD, an the .cab-file with help files are only included in full on the RTM version – NOT in all the CU versions (you’ll find the .cab-file on the DVD in the folder “Installers\DK\WebHelp\DynamicsNAV140Help\help\da-DK”). In the RTM-version the .cab-file is above 4MB in file size, while it is only 18KB on the CU versions.

So this solution is – either build your own html-files from the GitHub repository mentioned in the link I mentioned in the beginning of this post (https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/help/contributor-guide), or (preferable) download and copy the files from the RTM DVD.

Note: The latter solution is probably the preferred one, because you then get the exact help files matching your BC version. The GitHub repository might contain functionality not yet introduced in your major version.

Another note: the .cab-file or “Cabinet File” is actually a .zip-file, so you can rename it to .zip to open it in Windows or simply open it with 7-Zip or similar archiving utility. And then copy the contents to the correct language help folder.

Yet another note: In the “old days” where this worked out-of-the-box, the translated help files was typically NOT updated with each CU release. That makes sense as CUs rarely contains a lot of new functionality and it is probably quite expensive to keep the translations updated.

And a final note: I’ve not confirmed this issue for Microsoft Business Central 2019 wave 2 aka BC15 and/or 2020 wave 1 aka BC16. But as this might be caused by Microsoft prioritizing SaaS, it might be the same story in all versions after BC14. Hopefully we will be able to extract the help from the RTM versions…

As always: These fixes comes with NO warranty. Use this completely at your own risk and costs. Also it would probably be a very good idea to make a copy of the existing installation before overwriting or adding anything.

Extra hint – can you search in your help? If not, did you remember to:

  • enable Windows Search on your IIS help server (WindowsServer Manager)
  • verify that the Windows Indexing Service is running (Windows Task Manager)
  • verify the help folder is included in the indexing (Windows Control Panel)

Installing Microsoft Dynamics 365 Business Central with AzureSQL

Dynanmics 365 Business Central logo

As described here, it can be kind of a Catch-22 to try to install Microsoft Dynamics 365 Business Central if you don’t have a local SQL Server, but want to use AzureSQL.

Although I know the approach in the before mentioned Kine Info blog post works, I came across a easier solution during my struggles with this issue.

Although the installer setup.exe does not have a “Postpone Server Startup” setting in the GUI, it actually support it.

You just need to create a configuration and hit Save before actually starting the installation. You can do that when you finish filling out all the settings on the setting page (the one with port numbers, database server and database name etc.). After you saved the configuration, close the setup.exe installer.

Now open the XML file you saved, locate the “PostponeServerStartup” setting and change it’s default value of “false” to “true”:

<Parameter ID="PostponeServerStartup" Value="true"/>

Now restart setup.exe and load the configuration – and start the installation. The installer will not try to start the service tier, so it won’t fail that and roll back the installation.

We can only hope that Microsoft at some point will add this option to the setup.exe GUI :-).

2020-02-28 Update: I’ve suggested it to Microsoft. It is not a high priority issue (because of the above described workaround). For anybody interested it has been logged with internal Microsoft ID 346773.

Review: Introduction to the Modern client

Introduction to the Modern client

“Introduction to the Modern client” is a comprehensive, well written and excellent book for readers wanting an introduction to the new Modern client for Microsoft Dynamics 365 Business Central.

Peik Bech-Andersen not only introduces the Modern client and its role centers. He also walks us through the different elements of a role center and give us an easy to understand overview of the considerations, possibilities and tasks in adjusting the role center to the different requirements of a company, a department or even for an individual user.

Throughout the book Peik gives valuable hints and describes the complete life of role center and profile adjustments – starting from a developers tasks in adding parts to a role center page, via consultants and super users possibility to add or hide parts of a profile and he finishes off with the personalization options for individual users.

In the book you get information regarding best practices and unique bonus information about various subjects including notifications and utilizing/re-using the build in Business Charts – all based on Peik’s longstanding experience as a solution architect.

Peik’s full circle on the Modern client, role centers and profiles give “Introduction to the Moderns client” a very wide target audience.

I have no problems in recommending this book to readers ranging all the way from new Microsoft Dynamics 365 Business Central users (e.g. as course material), over experienced NAV users, super-users and consultants, to skilled NAV developers with the need to get familiar with the new Modern client and identifying when they need to add to the role centers and when to let the consultants handle it.

You can buy the two books at the Dynamics Book Store:

Introduction to the Modern client as PDF download
Introduction to the Modern client as paperback

The task cannot be run because the user account that is assigned to run the task has been altered

Microsoft Dynamics NAV logo

Have you tried to rename a company (from the Companies page or from PowerShell (Rename-NAVCompany cmdlet) in Microsoft Dynamics NAV 2018 and you get this error: “The task cannot be run because the user account that is assigned to run the task has been altered”, you are hit by a side effect of a new Service Tier Setting.

A quick google of the error message yields a few results – especially this one: https://forum.mibuso.com/discussion/72652/job-queue-with-task-scheduler-and-user-id… which suggest that it has something to do with the Service Tier Setting “EnableUserConsistencyValidationOnTasks”.

If we look at Microsoft description of that Service Tier Setting at https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/administration/configure-server-instance, we see this description:

Specifies whether user consistency checks are done on tasks. Setting this to true helps guard against impersonation of users in tasks. When enabled, only the user who created the task can edit the task. If a task is edited by different user account, an error similar to the following occurs: The task cannot be run because the user account that is assigned to run the task has been altered. The task has been canceled.

Default: true

Dynamically Updatable: No

…so if this protection is not important to you – you can easily work around the error by setting this key to false. If this protection is important to you, you should off cause just set it to false while renaming the company and then set it back to true again.

Have a Merry Christmas and a Happy New Year!

Cannot login to Microsoft Dynamics Business Central 2019 Spring release (BC14) RTM with LoginName authentication

Dynanmics 365 Business Central logo

Have you tried to configure a Microsoft Dynamics Business Central 2019 Spring release (BC14) RTM with LoginName authentication, just to find that it did not work?

You are right.

You won’t be able to login to the Web- or Windows-client and will get errors in your event log like these:

Server instance: BC140
Category: Runtime
ClientSessionId: 1396b6cf-5cfd-4dae-b98a-9ee3a6d3d3e1
ClientActivityId: 8665e7ca-3a27-49f3-b928-4a013317be94
ServerSessionUniqueId: 00000000-0000-0000-0000-000000000000
ServerActivityId: 5d8ecef1-6d64-4d05-9031-03a0248c9138
EventTime: 08/09/2019 10:14:40
Message (NullReferenceException): RootException: NullReferenceException

Object reference not set to an instance of an object.

ExceptionStackTrace:
   at Microsoft.Dynamics.Nav.Service.NSServiceBase.<>c__DisplayClass14_0.b__0()
   at Microsoft.Dynamics.Nav.Service.NSServiceBase.ValidateAndCreateSession(ConnectionRequest connectionRequest, Boolean requireNavUser)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)

CallerStackTrace:
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass27_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationTracer.TraceScopeCombinator(Category telemetryCategory, ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass27_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass9_0.b__0()
   at Microsoft.Dynamics.Nav.Runtime.NavPerformanceCounterSetter.UpdatePerformanceCountersWithAverageServiceOperationDuration(Stopwatch stopWatch, Action action)
   at Microsoft.Dynamics.Nav.Runtime.NavPerformanceCounterSetter.UpdatePerformanceCountersWithAverageServiceOperationAction(Action action, NavSession session)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.PerformanceCounterCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass27_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.InitClientTelemetryIdsCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass27_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.TlsClearCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, MethodBase syncMethod, Object[] inputs, Object[]& outputs)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.<>c__DisplayClass27_1.b__1(NSServiceBase serviceInstance, Object[] inputs, Object[]& outputs)
   at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
   at System.ServiceModel.Dispatcher.MessageRpc.Wrapper.Resume(Boolean& alreadyResumedNoLock)
   at System.ServiceModel.Dispatcher.ThreadBehavior.ResumeProcessing(IResumeMessageRpc resume)
   at Microsoft.Dynamics.Nav.Runtime.NavSynchronizationContext.<>c__DisplayClass1_0.b__0(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
Server instance: BC140
 Tenant ID: 
 User: xxx
 Type: System.NullReferenceException
 Message: Object reference not set to an instance of an object.
 StackTrace:
      at Microsoft.Dynamics.Nav.Service.NSServiceBase.<>c__DisplayClass14_0.b__0()
      at Microsoft.Dynamics.Nav.Service.NSServiceBase.ValidateAndCreateSession(ConnectionRequest connectionRequest, Boolean requireNavUser)
      at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)
 Source: Microsoft.Dynamics.Nav.Service
 HResult: -2147467261
 StackTrace:
      at Microsoft.Dynamics.Nav.Service.NSServiceBase.<>c__DisplayClass14_0.b__0()
      at Microsoft.Dynamics.Nav.Service.NSServiceBase.ValidateAndCreateSession(ConnectionRequest connectionRequest, Boolean requireNavUser)
      at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)
Type: Microsoft.Dynamics.Nav.Client.NavClientClosingException
 Fatal: False
 ShowError: True
 Message: The server "BC140" was unable to process the request. The application will close.
 StackTrace:
      at Microsoft.Dynamics.Nav.Client.WinClient.ExceptionHandler.DoExecute(Func1 execute)      at Microsoft.Dynamics.Nav.Client.WinClient.StartWinFormsClient.RunCore() Source: Microsoft.Dynamics.Nav.Client.WinClient HResult: -2146233088 StackTrace:      at Microsoft.Dynamics.Nav.Client.WinClient.ExceptionHandler.DoExecute(Func1 execute)
      at Microsoft.Dynamics.Nav.Client.WinClient.StartWinFormsClient.RunCore()
 Type: Microsoft.Dynamics.Nav.Types.Exceptions.NavServerSessionException
 Message: The server "BC140" was unable to process the request. The application will close.
 StackTrace:
      at Microsoft.Dynamics.Nav.Client.ConnectionEstablisher.OpenConnection[TChannel](ConnectFailedEventArgs connectFailedArgs, ConnectionRequest connectionRequest, ConnectionOptions connectionOptions, SpnSetting spnSettingToTry, Boolean allowSpnSettingsSwap, UserSettings& userSettings)
      at Microsoft.Dynamics.Nav.Client.ConnectionEstablisher.OpenConnection[TChannel](ConnectionRequest connectionRequest, ConnectionOptions connectionOptions, UserSettings& userSettings)
      at Microsoft.Dynamics.Nav.Client.ServiceConnection.OpenConnection()
      at Microsoft.Dynamics.Nav.Client.ServiceConnection.Initialize()
      at Microsoft.Dynamics.Nav.Client.FormBuilder.BuilderSessionInitializer.OpenConnectionToServer()
      at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.OpenServerConnectionCore()
      at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.OpenServerConnectionWithMultipleLoginAttempts()
      at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.InitializeUISession()
      at Microsoft.Dynamics.Framework.UI.Windows.ClientSessionBase.InitCore()
      at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.InitCore()
      at Microsoft.Dynamics.Framework.UI.ClientSessionCore.Init()
      at Microsoft.Dynamics.Framework.UI.Windows.ClientSessionBase.Run()
      at Microsoft.Dynamics.Nav.Client.WinClient.NavClientErrorHandler.ExecuteAndCatchExceptions(Func`1 execute)
 Source: Microsoft.Dynamics.Nav.Client.ServiceConnection
 HResult: -2146233088
 StackTrace:
      at Microsoft.Dynamics.Nav.Client.ConnectionEstablisher.OpenConnection[TChannel](ConnectFailedEventArgs connectFailedArgs, ConnectionRequest connectionRequest, ConnectionOptions connectionOptions, SpnSetting spnSettingToTry, Boolean allowSpnSettingsSwap, UserSettings& userSettings)
      at Microsoft.Dynamics.Nav.Client.ConnectionEstablisher.OpenConnection[TChannel](ConnectionRequest connectionRequest, ConnectionOptions connectionOptions, UserSettings& userSettings)
      at Microsoft.Dynamics.Nav.Client.ServiceConnection.OpenConnection()
      at Microsoft.Dynamics.Nav.Client.ServiceConnection.Initialize()
      at Microsoft.Dynamics.Nav.Client.FormBuilder.BuilderSessionInitializer.OpenConnectionToServer()
      at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.OpenServerConnectionCore()
      at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.OpenServerConnectionWithMultipleLoginAttempts()
      at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.InitializeUISession()
      at Microsoft.Dynamics.Framework.UI.Windows.ClientSessionBase.InitCore()
      at Microsoft.Dynamics.Nav.Client.WinClient.NavWinFormsClientSession.InitCore()
      at Microsoft.Dynamics.Framework.UI.ClientSessionCore.Init()
      at Microsoft.Dynamics.Framework.UI.Windows.ClientSessionBase.Run()
      at Microsoft.Dynamics.Nav.Client.WinClient.NavClientErrorHandler.ExecuteAndCatchExceptions(Func`1 execute)
 Type: Microsoft.Dynamics.Nav.Types.Exceptions.NavServerSessionException
 Message: The server "BC140" was unable to process the request. The application will close.
 HResult: -2146233088
 Type: System.NullReferenceException
 Message: Object reference not set to an instance of an object.
 StackTrace:
      at Microsoft.Dynamics.Nav.Service.NSServiceBase.<>c__DisplayClass14_0.b__0()
      at Microsoft.Dynamics.Nav.Service.NSServiceBase.ValidateAndCreateSession(ConnectionRequest connectionRequest, Boolean requireNavUser)
      at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)
 Source: Microsoft.Dynamics.Nav.Service
 HResult: -2147467261
 StackTrace:
      at Microsoft.Dynamics.Nav.Service.NSServiceBase.<>c__DisplayClass14_0.b__0()
      at Microsoft.Dynamics.Nav.Service.NSServiceBase.ValidateAndCreateSession(ConnectionRequest connectionRequest, Boolean requireNavUser)
      at Microsoft.Dynamics.Nav.Service.ServiceOperationInvoker.CreateNewSessionCombinator(ServiceOperation innerOperation, NSServiceBase serviceInstance, Boolean requireNavUser, Object[] inputs, Object[]& outputs)

Part of the story is that the same setup simply works with earlier versions, and that Windows-authentication also works without any glitches.

At least the fix is simple: Upgrade your platform to Cumulative Update 1 (or actually I recommend the latest while you are at it anyway 🙂 ).

Note, the error is also mentioned on forum.mibuso.com here!

Thanks goes to Christoph Bendixen and Jesper Dahl Fredriksen from team.blue aka ScanNet.dk for helping reporting and identifying this problem.

Playing around with the DynamicsNAV:// protocol handler

Dynanmics 365 Business Central logo

If you have been using the Dotnet ClickOnce technology to roll out your Dynamics NAV / 365 Business Central Windows Clients, you know it have some limitations (click here to read all about the limitations).

But if you start pulling the ClickOnce technology apart, you will find that the client files are in fact present on your harddrive, but in a obscure directory – which can be hard to locate (actually you can just start the client and go to task manager. Right click the running program and select to open the directory).

What if someone could make a small program or script that would locate all installed ClickOnce Dynamics NAV / 365 Business Central Windows Clients, present you with a list to choose from and then simply start the selected client with the appropriate parameters?

Maybe we can even register this small program or script as the protocol handler for the DynamicsNAV:// protocol?

Well, here is my first attempt of a PowerShell script I call NAVBCProtocolHandlerHelper.ps1 :-):

# Version: 2019-08-06

$SearchPath = "C:\Users\$($env:UserName)\AppData\Local\Apps\2.0\"

$WindowsClientFileName = "Microsoft.Dynamics.Nav.Client.exe"
$ClientUserSettingsFileName = "ClientUserSettings.config"

if(($args[0] -eq "?") -or ($args[0] -eq "-?") -or ($args[0] -eq "-h") -or ($args[0] -eq "-help")) {
  Write-Host "#######################################################################" -ForegroundColor Cyan
  Write-Host "# Microsoft Dynamics NAV/365 Business Central Protocol Handler Helper #" -ForegroundColor Cyan
  Write-Host "#######################################################################" -ForegroundColor Cyan
  Write-Host "#             Copyright 2019, Gert Lynge, www.dabbler.dk              #" -ForegroundColor Cyan
  Write-Host "#######################################################################" -ForegroundColor Cyan
  Write-Host "# This script is free to use, modify and distribute as long as these  #" -ForegroundColor Cyan
  Write-Host "# lines are kept intact. NO WARRANTY! Use at your own risk!           #" -ForegroundColor Cyan
  Write-Host "#######################################################################" -ForegroundColor Cyan
  Write-Host ""
  Write-Host "Examples:" -ForegroundColor Cyan
  Write-Host ""
  Write-Host "Install NAV/365BC Protocol Handler:" -ForegroundColor Cyan
  Write-Host "$($MyInvocation.MyCommand.Definition) -InstallProtocolHandler"
  Write-Host "Be warned: This will override any existing DynamicsNAV:// protocol handler" -ForegroundColor Red
  Write-Host ""
  Write-Host "Remove NAV/365BC Protocol Handler:" -ForegroundColor Cyan
  Write-Host "$($MyInvocation.MyCommand.Definition) -RemoveProtocolHandler"
  Write-Host "Be warned: This will remove any DynamicsNAV:// protocol handler installed" -ForegroundColor Red
  Write-Host ""
  Write-Host "Show list of NAV/365BC ClickOnce Windows Clients and let you select one to start:" -ForegroundColor Cyan
  Write-Host "$($MyInvocation.MyCommand.Definition)"
  Write-Host ""
  Write-Host "Show this help page:" -ForegroundColor Cyan
  Write-Host "$($MyInvocation.MyCommand.Definition) -help"
  exit
}
elseif(($args[0] -eq "InstallProtocolHandler") -or ($args[0] -eq "-InstallProtocolHandler")) {
  $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
  if(-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Throw "Installing the DynamicsNAV:// Protocol handler requires this script to be run as Administrator"
  }

  New-PSDrive -Name HKCR -PSProvider Registry -Root "HKEY_CLASSES_ROOT" -ErrorAction SilentlyContinue | Out-Null
  New-Item -Path "HKCR:\DynamicsNAV" -Force | Out-Null
  New-ItemProperty -Path "HKCR:\DynamicsNAV" -Name "(Default)" -Value "Dynamics NAV Protocol" -Force | Out-Null
  New-ItemProperty -Path "HKCR:\DynamicsNAV" -Name "URL Protocol" -Force | Out-Null

  New-Item -Path "HKCR:\DynamicsNAV\DefaultIcon" -Force | Out-Null
  New-ItemProperty -Path "HKCR:\DynamicsNAV\DefaultIcon" -Name "(Default)" | Out-Null

  New-Item -Path "HKCR:\DynamicsNAV\Shell" -Force | Out-Null
  New-ItemProperty -Path "HKCR:\DynamicsNAV\Shell" -Name "(Default)" | Out-Null

  New-Item -Path "HKCR:\DynamicsNAV\Shell\Open" -Force | Out-Null
  New-ItemProperty -Path "HKCR:\DynamicsNAV\Shell\Open" -Name "(Default)" | Out-Null

  New-Item -Path "HKCR:\DynamicsNAV\Shell\Open\Command" -Force | Out-Null
  New-ItemProperty -Path "HKCR:\DynamicsNAV\Shell\Open\Command" -Name "(Default)" -Value "PowerShell.exe -WindowStyle Hidden -File ""$($MyInvocation.MyCommand.Definition)"" ""%1""" | Out-Null

  Write-Host "Protocol Handler DynamicsNAV:// installed" -ForegroundColor Green
  exit
}
elseif(($args[0] -eq "RemoveProtocolHandler") -or ($args[0] -eq "-RemoveProtocolHandler")) {
  $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
  if(-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Throw "Removing the DynamicsNAV:// Protocol handler requires this script to be run as Administrator"
  }

  New-PSDrive -Name HKCR -PSProvider Registry -Root "HKEY_CLASSES_ROOT" -ErrorAction SilentlyContinue | Out-Null
  Remove-Item -Path "HKCR:\DYNAMICSNAV" -Recurse -Force | Out-Null

  Write-Host "Protocol Handler DynamicsNAV:// removed" -ForegroundColor Green
  exit
}


$WindowsClients = New-Object System.Data.DataTable
$WindowsClients.Columns.Add("Product","System.String") | Out-Null
$WindowsClients.Columns.Add("Server","System.String") | Out-Null
$WindowsClients.Columns.Add("Port","System.String") | Out-Null
$WindowsClients.Columns.Add("Instance","System.String") | Out-Null
$WindowsClients.Columns.Add("Tenant","System.String") | Out-Null
$WindowsClients.Columns.Add("Authentication","System.String") | Out-Null
$WindowsClients.Columns.Add("Version","System.Version") | Out-Null
$WindowsClients.Columns.Add("Path","System.String") | Out-Null

foreach($File in Get-ChildItem -Path "$SearchPath$WindowsClientFileName" -Recurse | Select-Object FullName) {
  $Path = (Split-Path -Path $File.FullName -Parent)

  if(Test-Path "$Path\$ClientUserSettingsFileName" -PathType Leaf) {
    [xml]$XmlDocument = Get-Content -Path "$Path\$ClientUserSettingsFileName"
    $ChildNodes = $XmlDocument.configuration.appSettings.ChildNodes

    $WindowsClient = $WindowsClients.NewRow()
    $WindowsClient.Path = $Path
    $WindowsClient.Version = [System.Version][System.Diagnostics.FileVersionInfo]::GetVersionInfo($File.FullName).FileVersion
    $WindowsClient.Server = ($ChildNodes | Where-Object {($_.key -eq "Server")}).value
    $WindowsClient.Port = ($ChildNodes | Where-Object {($_.key -eq "ClientServicesPort")}).value
    $WindowsClient.Instance = ($ChildNodes | Where-Object {($_.key -eq "ServerInstance")}).value
    $WindowsClient.Tenant = ($ChildNodes | Where-Object {($_.key -eq "TenantId")}).value
    $WindowsClient.Authentication = ($ChildNodes | Where-Object {($_.key -eq "ClientServicesCredentialType")}).value
    $WindowsClient.Product = ($ChildNodes | Where-Object {($_.key -eq "ProductName")}).value
    $WindowsClients.Rows.Add($WindowsClient)
  }
}
$WindowsClients = $WindowsClients | Group-Object -Property Server,ClientServicesPort,ServerInstance,TenantId | `
                  foreach { $_.Group | Sort-Object @{Expression="Version";Descending="$True"} | Select-Object -First 1 }

$Picked = $WindowsClients | Out-GridView -PassThru -Title "Select which Microsoft Dynamics NAV/365 Business Central ClickOnce Windows Client to run"

if(-not $Picked) {
  exit
}

$Command = "$($Picked.Path)\$WindowsClientFileName"
if($args[0]) {
  & "$Command" "-protocolhandler" $args[0]
}
else {
  & "$Command"
}

Please run NAVBCProtocolHandlerHelper.ps1 from a powershell CLI with the -help parameter and read the possibilities. It has five ways of running:

  1. Show the help:
    NAVBCProtocolHandlerHelper.ps1 -help
  2. Install itself as the DynamicsNAV:// protocol handler (OVERWRITING the existing one):
    NAVBCProtocolHandlerHelper.ps1 -InstallProtocolHandler
  3. Remove ANY DynamicsNAV:// protocol handler (also ones the script did not install itself):
    NAVBCProtocolHandlerHelper.ps1 -RemoveProtocolHandler
  4. Show list of installed ClickOnce Windows Clients for Dynamics NAV/365 Business Central and lets you choose one. The chosen one is started:
    NAVBCProtocolHandlerHelper.ps1
  5. Started through the DynamicsNAV:// protocol.
    A list of installed ClickOnce Windows Clients for Dynamics NAV/365 Business Central will be shown. When you chose one, it is started and the URL is passed as a parameter to it (just like if it was called directly from the protocol handler):
    DynamicsNAV://<your parameters>

This is still work in progress and can be improved in many ways. Feel free to send me your comments and wishes.

You can use and modify this free of charge as long as you keep the blocks shown in the help intact.
This is completely without any warranty of any kind – so use at your own risk!
Parameters and functionalities are subject to changes as this is work in progress.

Option value != OptionML value

Dynanmics 365 Business Central logo

Do you need some way of getting the Option value instead of the OptionML value from an Option field?

It is not so straight forward as one should think, but with this simple function the work is done for you:

PROCEDURE GetOptionValue@1000000002(TableId@1000000001 : Integer;FieldId@1000000000 : Integer;Value@1000000002 : Integer) : Text;
VAR
  TableRef@1000000003 : RecordRef;
  FieldRef@1000000004 : FieldRef;
BEGIN
  //Example:
  //  MESSAGE(KMCTools.GetOptionValue(DATABASE::"Sales Line",SalesLine.FIELDNO(Type),SalesLine.Type::Item));
  TableRef.OPEN(TableId);
  FieldRef := TableRef.FIELD(FieldId);
  EXIT(SELECTSTR(Value+1,FieldRef.OPTIONSTRING));
END;

Free of charge – but use on your own risk…

Microsoft Dynamics 365 Business Central WebClient with no Role Center

Dynanmics 365 Business Central logo

Is your Microsoft Dynamics 365 Business Central Windows Client working, but your Web Client gets stuck with this picture just after log in?

WebClient - no Role Center
WebClient – stuck with no Role Center just after login.

…and do you see events like these in the Windows eventviewser on the Server? (sorry – I know it is in Danish: “fejl” translates to “error” and “undtagelse” means “exception”)

Der opstod fejl under forsøg på adgang til webstedet 
Type: Microsoft.Dynamics.Nav.Types.NavCancelCredentialPromptException
Message: Der blev udløst en undtagelse af typen 'Microsoft.Dynamics.Nav.Types.NavCancelCredentialPromptException'.
StackTrace:
   ved Microsoft.Dynamics.Nav.Client.ConnectionEstablisher.PromptForCredentials() i S:\Depot\Platform-Core\platform\client\Shared\Prod.Client.ServiceConnection\ConnectionEstablisher.cs:linje 1041
   ved Microsoft.Dynamics.Nav.Client.ConnectionEstablisher.OpenConnection[TChannel](ConnectionRequest connectionRequest, ConnectionOptions connectionOptions, UserSettings& userSettings) i S:\Depot\Platform-Core\platform\client\Shared\Prod.Client.ServiceConnection\ConnectionEstablisher.cs:linje 196
   ved Microsoft.Dynamics.Nav.Client.ServiceConnection.OpenConnection() i S:\Depot\Platform-Core\platform\client\Shared\Prod.Client.ServiceConnection\ServiceConnection.cs:linje 892
   ved Microsoft.Dynamics.Nav.Client.ServiceConnection.Initialize() i S:\Depot\Platform-Core\platform\client\Shared\Prod.Client.ServiceConnection\ServiceConnection.cs:linje 561
   ved Microsoft.Dynamics.Nav.Client.FormBuilder.BuilderSessionInitializer.OpenConnectionToServer() i S:\Depot\Platform-Core\platform\client\Shared\Prod.Client.Builder\BuilderSession\BuilderSessionInitializer.cs:linje 265
   ved Microsoft.Dynamics.Nav.Client.FormBuilder.BuilderSessionInitializer.InitializeCore() i S:\Depot\Platform-Core\platform\client\Shared\Prod.Client.Builder\BuilderSession\BuilderSessionInitializer.cs:linje 92
   ved Microsoft.Dynamics.Nav.Client.FormBuilder.BuilderSessionInitializer.Initialize() i S:\Depot\Platform-Core\platform\client\Shared\Prod.Client.Builder\BuilderSession\BuilderSessionInitializer.cs:linje 76
   ved Microsoft.Dynamics.Framework.UI.UISession.Initialize() i S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\Session\UiSession.cs:linje 1094
   ved Microsoft.Dynamics.Nav.Client.Web.NavWebUISessionInitializer.InitializeCore(UISession session) i S:\Depot\Platform-Core\platform\client\web\Prod.Client.WebCommon\Session\NavWebUISessionInitializer.cs:linje 94
   ved Microsoft.Dynamics.Nav.WebClient.NavWebClientUISessionInitializer.InitializeCore(UISession session) i S:\Depot\Platform-Core\platform\client\web\Prod.Client.WebClient\Session\NavWebClientUISessionInitializer.cs:linje 65
   ved Microsoft.Dynamics.Nav.Client.Web.NavWebUISessionInitializer.Initialize(UISession session) i S:\Depot\Platform-Core\platform\client\web\Prod.Client.WebCommon\Session\NavWebUISessionInitializer.cs:linje 77
   ved Microsoft.Dynamics.Framework.UI.Client.OpenFormExecutionStrategy.TryInitializeUiSession(UISession session) i S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\Client\Interactions\ExecutionStrategies\OpenFormExecutionStrategy.cs:linje 67
   ved Microsoft.Dynamics.Framework.UI.Web.WebOpenFormExecutionStrategy.TryInitializeUiSession(UISession session) i S:\Depot\Platform-Core\platform\client\web\Prod.Client.Web\Interactions\ExecutionStrategies\WebOpenFormExecutionStrategy.cs:linje 61
   ved Microsoft.Dynamics.Framework.UI.Client.OpenFormExecutionStrategy.Execute() i S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\Client\Interactions\ExecutionStrategies\OpenFormExecutionStrategy.cs:linje 41
   ved Microsoft.Dynamics.Framework.UI.InteractionManager.<>c__DisplayClass8_2.b__4() i S:\Depot\Platform-Core\platform\client\Shared\Prod.ClientFwk\Interactions\InteractionManager.cs:linje 125
Source: Microsoft.Dynamics.Nav.Client.ServiceConnection
Error accessing Website 
Unhandled error occurred on a browser or device client:
{
  "clientInfo": {
    "platform": "Win32",
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362",
    "browserLanguage": "da-DK"
  },
  "message": "Unable to get property 'getElementsByClassName' of undefined or null reference",
  "pageUrl": "https://xxxxxxxxxx/yyyyyyyyyy/?runinframe=1",
  "originalError": {},
  "location": {
    "name": "https://xxxxxxxxxx/yyyyyyyyyy/js/framework.js?h=69F05AE1092A2D30721123840E70FB027600B5F7A4BA9069BAE99A1E20C9168D&_v=1.0.0",
    "url": "https://xxxxxxxxxx/yyyyyyyyyy/js/framework.js?h=69F05AE1092A2D30721123840E70FB027600B5F7A4BA9069BAE99A1E20C9168D&_v=1.0.0",
    "lineNumber": 4562,
    "columnNumber": 58
  },
  "detailedMessage": "   at DN.LogicalFormAdapter.prototype.$105 (https://xxxxxxxxxx/yyyyyyyyyy/js/framework.js?h=69F05AE1092A2D30721123840E70FB027600B5F7A4BA9069BAE99A1E20C9168D&_v=1.0.0:5188:1958)\r\n   at DN.LogicalFormAdapter.prototype.initializeNativeControl (https://xxxxxxxxxx/yyyyyyyyyy/js/framework.js?h=69F05AE1092A2D30721123840E70FB027600B5F7A4BA9069BAE99A1E20C9168D&_v=1.0.0:5152:101)\r\n   at DN.LogicalControlAdapter.prototype.$27 (https://xxxxxxxxxx/yyyyyyyyyy/js/framework.js?h=69F05AE1092A2D30721123840E70FB027600B5F7A4BA9069BAE99A1E20C9168D&_v=1.0.0:4839:1117)\r\n   at DN.LogicalControlAdapter.prototype.createContent (https://xxxxxxxxxx/yyyyyyyyyy/js/framework.js?h=69F05AE1092A2D30721123840E70FB027600B5F7A4BA9069BAE99A1E20C9168D&_v=1.0.0:4833:6623)\r\n   at DN.LogicalControlAdapter.prototype.buildCore (https://xxxxxxxxxx/yyyyyyyyyy/js/framework.js?h=69F05AE1092A2D30721123840E70FB027600B5F7A4BA9069BAE99A1E20C9168D&_v=1.0.0:4834:399)\r\n   at Type.prototype.callBaseMethod (https://xxxxxxxxxx/yyyyyyyyyy/js/mscorlib.js?h=D3729A20D7B95888CE98A4A7D3E48A9F0C340D80C5F72A67326464A956360F0E&_v=1.0.0:1:23528)\r\n   at DN.LogicalFormAdapter.prototype.buildCore (https://xxxxxxxxxx/yyyyyyyyyy/js/framework.js?h=69F05AE1092A2D30721123840E70FB027600B5F7A4BA9069BAE99A1E20C9168D&_v=1.0.0:5160:156)\r\n   at DN.LogicalControlAdapter.prototype.build (https://xxxxxxxxxx/yyyyyyyyyy/js/framework.js?h=69F05AE1092A2D30721123840E70FB027600B5F7A4BA9069BAE99A1E20C9168D&_v=1.0.0:4833:6709)\r\n   at DN.LogicalControlAdapter.prototype.buildChildAdapter (https://xxxxxxxxxx/yyyyyyyyyy/js/framework.js?h=69F05AE1092A2D30721123840E70FB027600B5F7A4BA9069BAE99A1E20C9168D&_v=1.0.0:4834:1581)\r\n",
  "requireUserToSignOut": false,
  "silent": true
}

Well – congratulations. You probably hit the same rabbit hole I just wasted 2 hours on.

Please go through you Role Center PageParts and check if you by mistake filled the InstructionalTextML property with something. I don’t want you to check the Role Center page, but check the individual PageParts pages. It is a global parameter on them.

If you did – remove it and this problem is magically gone :-)…

Note: This issue HAS off cause been reported to Microsoft (it got case ID 119071922000172 ). They have confirmed that it also seems to be present on Microsoft Dynamics 365 Business Central 2019 spring release.

I’ve discovered it in 2018 fall release CU7 (running single tenant and NavUserPassword authentication – not that I think that is part of the cause). I’ll expect it to be also present in at least 2018 fall release CU9 and 2019 spring release CU1.

Microsoft confirms they are looking into fixing it and a fix will be released in a future CU.