Well, it has been quite a while since my last post and I’m sorry for that. Lots of things have gone on in the past few months and it has caused me to re-evaluate some of my priorities. As such, I’ll be switching some things up in my life and putting focus in other areas of my life.
Things are not dire by any means, I’m just going to be spending my “non-work time” focusing on my family rather than worrying about things like blog writing, code samples, etc. Heck, I’ve even taken a huge step back from social media, which for me was not easy 🙂
I’ve been very fortunate in the past few years to have some great experiences; becoming a Microsoft MVP and publishing a book just to name a couple. Thanks to everyone for the support and opportunities, but now it’s time to do a bit of a reset. Family first.
I’m definitely not leaving the Business Central community, and I’m not saying I won’t blog again, but I’m just not going to be putting any pressure on myself to do it. If it happens it happens, if not then so be it. If you follow me on LinkedIn you know that I’m leaving my current job after what will be a few months shy of 17 years. Scary stuff, but I’ve already got something lined up and I’m super excited to move on to my next role and to stay on-board the Business Central train.
Maybe I didn’t look hard enough, but I went looking at the Microsoft Docs online help for Business Central for a project I’m working on, and I could not find any information on this. I did find it listed in the AL Language Extension changelog, so figured I’d throw up a quick post to get this out there in case you don’t read the changelog. 🙂
With the Business CentralFall 2018 release, it’s now possible to override base reports with your AL extension. Not just printed reports, but processing reports too!
You can do that by creating a subscriber to the OnAfterSubstituteReport event in the ReportManagement codeunit (I thought we wanted to get rid of management codeunits 😉 !?) It’s a very straightforward bit of code and it looks like this:
codeunit 50100 "Replace Reports"
[EventSubscriber(ObjectType::Codeunit, Codeunit::ReportManagement, 'OnAfterSubstituteReport', '', false, false)]
local procedure OnAfterSubstituteReport(ReportId: Integer; var NewReportId: Integer)
if ReportId = Report::"Customer Listing" then
NewReportId := Report::"My New Customer Listing";
As you can see, very simple logic that just replaces the report that is being executed by the system.
The above logic can be enhanced to check to see if the report has already been substituted by another extension. You can do that just by comparing the ReportId and NewReportId parameters before making your change. If those parameters do not match, and NewReportId is not -1, then the report has already been replaced by another extension, and you’re of course then going to have to figure out how you handle that.
Remember when you are replacing base reports, if the report is called in code, make sure you use a compatible report, or you’ll get run time errors.
Oh, one more piece of good news here………the event above that we subscribed to is called every time a user clicks on a report action on a page, and also when any of the following commands are executed in code for a report object:
A little bit ago I posted this article on indirect app dependencies. Based on what I was seeing, it appeared as though if your app has a dependency, and the dependent app has its own dependencies, you have to put all of the dependencies in your app, making things very difficult to manage.
Shortly after my post, fellow MVP Erik Ernst published an article stating that this is not the way it works, and he published a sample project on GitHub to try it out.
Things got a bit weird here, as I grabbed his sample project and tried it for myself using his instructions. I got the same results as I first saw, and not what Erik said he saw.
After some back and forth and some research into this, it turns out that this was a change in behaviour with the particular AL Language extension that I was using.
I was using the VSIX from the Business Central insider registry. When I retested Erik’s instructions using the latest official Business Central release (Fall 2018 Update 3) everything worked as he stated.
This is great news. I wasn’t going crazy! However, it was still a question if this was a bug or a new ‘feature’.
After logging to Microsoft, it was confirmed to be a bug in the insider version of the VSIX.
This means that you do NOT need to define any indirect dependencies in your app if you are not referencing any entities or functions from the app.
So….I’m working through a new build process for our ISV solution. Why? Because we’re finally breaking it down into many extensions!! More on that another day…..
We’ve created a ‘library’ app which will house all of our common functionality. Each of our functional apps will have a dependency on the library app. Further to this, each of our functional apps will have its own test app. The test app of course has a dependency on the app that it is testing.
So……you create your test app, add a dependency to the app you are testing and compile…..NOPE…..failure. 😦
In the above example, what needs to be done is the dependency to Library also needs to be added to Test App 1.
Does this make sense? Maybe. This forces an assumption that because App 1 has direct access to the functions and entities within Library that Test App 1 also needs that access. In my example above, this direct access to Library was not something that we needed.
From the symbol perspective it perhaps makes a bit more sense. Adding the dependency forces the system to download the symbols for the dependent apps. If you just add the dependency for App 1‘ above, those symbols could be considered “incomplete” without also having the symbols for its dependencies, in this case Library.
I really (!!!) wish that we didn’t have to specify the extra dependencies. It would be nice if the compiler was able to figure out all of the downstream dependencies. An indirect dependency so to speak!?
The above scenario is fairly simple, but imagine this one:
ISV ‘AA’ creates a ‘app b’ that has a dependency on ‘app a’.
ISV ‘BB’ creates ‘app c’ that extends ‘app b’. 2 dependencies needed here (a, b).
ISV ‘BB’ sells ‘app c’ to a customer who then extends it even more with ‘app d’. This new app requires 3 dependencies (a, b, c).
…..look at all the apps now that have to be updated when ISV ‘AA’ releases a new version of ‘app b’? In an agile saas world, rapid small incremental releases are a reality. Is this also going to be magnified once Microsoft breaks down the main application into smaller (and perhaps dependent) apps?
Oh…in case you don’t know or don’t remember how to add dependencies to your app? It’s done in the app.json file in each app. See below for an example of what the app.json would look like in the ‘test app 1’ from the above example….
So how did I find this? As I mentioned, I’m working on a new build pipeline for our apps. My goal is that the pipeline will dynamically handle the dependencies so that it will update all of the versions in the app.json without the developer having to worry about that. After all, the build numbers are being generated from Azure DevOps so the developer is not going to know what the build numbers of the dependent apps will be. This little dependency hiccup caused a little bit of a wrench in my original plans.
More to come on the build pipeline later……..but spoiler alert…..it is working!!
Microsoft announced today that the April 2019 release notes for Dynamics 365 and the Power Platform are now available for download. These notes cover all products within these platforms, but for readers of this blog, you’re likely most interested in what’s coming for Business Central.
A few highlights of new end-user functionality for Business Central are:
Base application as an app (!!)
Yes, one of the things I’m looking forward to most is that we’re getting the base application moved from CAL objects to 2 AL extensions – system and application. Yes, the end of C/Side is coming.
Add multiple items to a sales or purchase order at once.
Name and description fields on master/document/journal records increased from 50 to 100 characters.
Watch out for this one in your ISV solutions as you may need to increase your field sizes to match!
New Physical Inventory Order and Physical Inventory Recording interfaces to enhance physical inventory functionality.
Set an expiration date for your sales quotes.
Merge duplicate customer and vendor records (!!).
Configurable reports for warehouse documents.
Save your filtered list views (!!).
Document focus mode – expend the item section on documents to see more data for faster entry.
More keyboard shortcuts – show/hide fact box, add item, previous/next navigation, etc.
Adjust field importance via personalization.
Page inspection – See all data elements of the current page record…….think the old ‘page zoom’ but even better!
The April 2019 release also includes improvements for developers working with AL extensions, such as:
Optimizing the experience of using VS Code with large projects.
new Outline View to show the symbol tree in teh current editor.
The in-client designer no longer makes dependencies on all apps, only the ones that have been used in the designer.
Attach to an existing client session for debugging.
Code Actions – have VS Code suggest ways to improve your code.
More protection for ISV’s over their IP.
Standard web API moving out of beta. Will support webhooks, OAS 3.0, OData v4, and versioning.
As noted in the release notes, the above features are things that are slated to be released anywhere between April 2019 and September 2019. Some of the features may be available for preview as early as February 2019.
The above is just a highlight of what’s coming down the road for Business Central and as you can see we are in for quite a lot of new features and quite a few old features that are being resurrected in a new a better way.
UPDATE (Jan 15, 2019): Since writing this post, the process has become much easier. Instead of downloading the nightly binaries, set your Docker Desktop installation to use the Edge channel and then get the latest update. That update now includes the executable files to run containers in process isolation mode! I’ll leave the original post here for posterity.
Well, it looks like all of the pieces are finally coming together where we can run our Docker containers on a Windows 10 machine without the overhead of Hyper-V. Don’t get me wrong, I’ve been running my containers always on Windows 10 without much issue, but being able to not have to allocate RAM and letting the o/s handle it like it does o Windows Server is a very welcome change!
The process you are about to see involves manually replacing your Docker executables with ones from the nightly Docker build repository. If this does not sound appealing to you, I’d recommend to wait for the official Docker release that has this feature.
First off, I’m not going to pretend I’m any sort of Docker expert. I know it well enough to be ‘comfortable’, but I’m still very much a rookie in many ways (Docker networking!? Yikes…..).
One thing I do know though, is that running Docker on Windows 10 has always leveraged the built-in Hyper-V layer to manage the containers. This adds some overhead when it comes to CPU and RAM usage, and also meant that you had to specify a “maximum RAM” amount for each container you created. Running too many containers meant likely a visit from the big bad blue screen. On an 8gb machine, that often means being able to run only 1 container at a time.
On Windows Server the Hyper-V is not required (although it can be if you desire) as the containers run in what is called Process Isolation. I’m not going to get into the differences of Process vs. Hyper-V isolation (you can read about that in Freddy’s Blog here) but the thing to know is that process isolation does NOT use Hyper-V, so no extra overhead, and no need to specify any amount of allocated RAM. You can run multiple containers at a time and the operating system manages everything.
What you need to do
Here are the steps to getting your system configured for running Docker containers in process isolation on Windows 10. This process assumes that you have already installed and configured Docker on your Windows 10 machine and that it functions correctly.
If you’ve not installed Docker yet, you can grab it from here. Make sure you set Docker to use Windows Containers.
1. Apply the Windows 10 – October 2018 update
The first thing that you need to do is apply the Windows 10 update from October 2018. This will update your system to version 1809 which is required in order to run Windows containers in process isolation mode.
By the time this post is published, you should be able to get the update via Windows Update, but if not, you can manually the update using the Update Assistant here.
After the update you can use the winver command from your Start Menu to verify you are running version 1809.
2. Download Docker nightly build binaries
The ability to run Windows 10 containers without Hyper-V is not a fully baked feature in Docker yet (again, if this freaks you out, you may want to wait), so what you need to do is get the nightly build binaries that contain this feature.
These files can be downloaded from the Docker Master Binaries site. You have a load of options here as to what binaries you can get so make sure you get the correct ones.
I find the easiest file to grab is the docker.zip file. You can bookmark the link to this file and it will always get you the latest build. If you are browsing through the site though, the file I’m talking about is shown below. You can see that as of this post the file is dated December 20, 2018 but that will likely change by the time you download the file.
Once you have the file downloaded, extract it and you will see 2 files inside:
3. Replace Docker binaries
We need to replace the Docker binaries that are currently installed with the new ones that we downloaded in step 2. The first thing we need to do is stop Docker. Do that by right-clicking on the Docker whale icon in your system tray and choose Quit Docker Desktop.
Once Docker has stopped we can replace the existing files. You will find them at the following locations:
Before replacing any files make sure to backup the original ones!!!
One thing to note is that after doing this a few times, once in a while stopping Docker was not enough. I also had to also go into Computer Management and stop the Docker services. Just right-click on each service and select Stop.
4. Reboot your system
Yes you can probably just restart everything that you stopped in step 3, but I like to do a full reboot so that I can make sure everything starts up as it normally would.
5. Turn off Docker update checks [OPTIONAL]
This step is not required, but you may or may not want to do it depending on how tempted you are to click on the install button the next time Docker prompts you that an update is available. Remember we’re using an unreleased set of binaries now so before taking any update, make sure that it’s not going to revert you to a version that still requires Hyper-V. If you want to turn off those prompts you can do so in the Docker Desktop Settings.
If you are using NavContainerHelper to do all of your Dynamics NAV and Business Central container management then make sure to update to the latest version so that when you pull images and create containers, you will be pulling the ltsc2019 images, which Freddy explains all about here.
At this point your system is ready to run Windows containers without Hyper-V. If you have any containers that you had created before doing the above updates, they will continue to use Hyper-V. You’ll probably want to recreate those containers using the new ltsc2019 images and if you do, you will then want to clean up your old containers and images. Once again, I can defer to Freddy on how to do this.
That’s it! Until next time, happy coding…and Dockering!?
Since moving to the Web Client, have you seen this at all?
You probably have, and has it popped up while you were running a long processing routine? Yup, me too.
When you kick off those long running routines, your Web Client basically sits idle while the Service Tier is doing the processing. Once that idle time reaches a particular limit, the Service Tier shuts down that connection.
Changing the Timeout
When using the Windows Client it’s easy to set a few settings (see here) in the Service Tier configuration in order to adjust the session timeout for a user. Moving forward it remains just as easy, but if you’ve tried using the same settings as in the past, you’ve certainly noticed that they don’t work for the Web Client.
The session timeout for the Web Client is now controlled by settings in the Service Tier and in the Web Client configuration. I wish there was just a single setting, but maybe once the Windows Client is gone we’ll see some of the old settings go away as well.
In order to change the timeout for the Web Client, you need to change two settings. Thankfully though, we can easily change these settings using a couple of PowerShell commands.
This setting is found in the Microsoft Business Central Server configuration.
Set-NAVServerConfiguration DynamicsNAV130 -KeyName ClientServicesIdleClientTimeout -KeyValue "00:20:00"
The timeout uses this format: [dd.]hh:mm:ss[.ff]
dd – number of days
hh – number of hours
mm – number of minutes
ss – number of seconds
ff – hundredths of a second
You can also set the setting to “MaxValue” in order to indicate no timeout. This is also the default value for a new installation.
You must restart the service tier for the new setting to take affect.
This settings is found in the navsettings.json file on the Microsoft Business Central Web Server.
Set-NAVWebServerInstanceConfiguration -WebServerInstance DynamicsNAV -KeyName SessionTimeout -KeyValue "00:20:00"
The timeout uses this format: [dd.]hh:mm:ss[.ff]
dd – number of days
hh – number of hours
mm – number of minutes
ss – number of seconds
ff – hundredths of a second
The default value is “00:20:00” (20 minutes) for a new installation.
How the Settings Work Together
The above settings are used in conjunction with each other. A session will be closed based on the setting that has the shortest time period.
By default, the ClientServicesIdleClientTimeout setting is set to “MaxValue”, which means that in a default installation, the SessionTimeout settings is what will be used.
This is also why configuring the Microsoft Business Central Server to a higher timeout does not work, since it is the setting that has the shortest time period that is used.
The ClientServicesIdleClientTimeout and SessionTimeout settings work together to determine the timeout of the Web Client. The setting that has the shortest time period is the one that is used to determine when a session is closed.
This means that in a default installation you can leave the ClientServicesIdleClientTimeout at its default value, and just change the SessionTimeout setting on the Microsoft Business Central Web Server to your desired timeout.
You can read more on this and other configurations you can set here.
I realize it’s been a bit since my last update. I decided to take a week of vacation (no, not brought on by this conversion process!), and then decided to build a separate app to compliment our ISV solution.
Back to the conversion project….I’ve been able to spend a little over a week worth of time since my last update , so I’ve got a few things I want to cover.
I was asked a little while ago what the environment is that I’m using, so I’ll quickly explain. I’m using a 100% Docker-based system running locally on my Windows 10 Surface Book 2. With the luxury of 16GB RAM available on my machine, I’m able to dedicate 8Gb to the container which allows for a nice smooth experience without having to switch to Windows Server. If you want to get into building your own Docker system, check out Freddy’s post to get started.
As for the image I’m using, I’m using the Business Central insider builds. You may want to choose another image to use, or if you do not have access to the insider builds, refer to this post to determine what’s right for you.
Where I’m at in the Process
At the end of the last post, I had tackled some of the easy things. Now I’ve been able to get through a large chunk of the more tedious things. Remember, I’m not necessarily fixing issues right now, I’m still working my way towards an extension that builds and publishes.
Issue 1 – Report DataItem Naming
One of the issues that came up was with the converted reports. It appears as though that in our original reports, we had named various dataitems with the name ‘Labels‘. Well, guess what is a reserved word in AL? This was an easy fix as it just involved renaming the dataitem. Since then I’ve tried to reproduce the error but can’t so I’m wondering if this has already been fixed in the more recent AL Language extension that I’m now using.
Issue 2 – TextConst Dropped in Conversion
This is a weird one. I’ll mention it here in case anyone else comes across this, but somewhere in the conversion of my CAL objects to AL files, a bunch of TextConst variables were dropped. I don’t know why, and there’s a possibility that it was something I did, but nonetheless, I had a bunch of files I had to go through in order to fix the missing variables.
Issue 3 – Trigger Modifications Unsupported…or are they?
This one was a bit annoying, but I understand why it gets flagged by the Txt2AL conversion tool. If you’re converting an ISV, you’ll be almost certain to run into this.
In our table and page extensions, there a load of places where we had put code in various triggers, such as onValidate, onOpenPage, onAfterGetCurrentRecord, etc. All of these changes were marked as “Unsupported” during the conversion process.
In your extension object, you do get a nice indicator of what the change was. The example below shows that I had made a modification to the onOpenPage trigger and added some code at the end to populate a ‘User ID Filter’. I often found myself going back to C/Side just to confirm the exact modification and what code was around it.
This is a bit misleading though as you can create the necessary trigger in the extension file and then add your existing code to it. Using the example above, my extension file would now look like this:
The caveat to this, and the reason why the conversion tool flags these changes, is that you have to be conscious of when the triggers are fired and where your original code was within the trigger.
If your original code was at the start of the onOpenPage trigger, your new code that you add to the onOpenPage trigger in the extension object will not fire until AFTER the “original” trigger fires. Given this, while you may be able to recreate the triggers needed and then put your code in them, the code may not actually be firing when you intended.
If your existing trigger code was somewhere in the middle of the old trigger code, you will need to rework your solution to work within the onBefore/onAfter structure.
Some triggers (e.g. onInitPage) are not available in extension objects, so you need to also be aware that. Available triggers also change depending on whether or not you are adding your own field/control to the page, or modifying an existing one.
You can always see what triggers are available to you by pressing Ctrl+Space after the ‘trigger‘ keyword.
Knowing all of this information, you can see why it doesn’t make sense for the conversion to automatically assume all of your trigger code can simply be moved over ‘as-is’. This one’s going to require some developer know-how!
Alright, I think this is it for now. I have more updates to share, but at the risk of turning this post into a novel, I’ll save those for the next post.
Well, what can I say……….this is going to take a while. 🙂
If you have no idea what I am talking about, start here.
After getting the objects converted to AL (using the standard process documented here), I was immediately greeted in VS Code by just over 8000 errors/warnings. Great start.
Luckily half of those were generated by the code analyzers. If you don’t know what they are, see here. Yes, at this point in the project I am considering that half of my issues are “only non-standard and poorly formatted code”. Gotta try and stay positive!
This brings me to my first “recommendation” in this process:
Turn off ALL the code analyzers.
The code analyzers are enabled by default, but can be turned off in your VS Code settings (see here). Once I get to a point where the “non-syntax” errors have been addressed, I will re-enable the analyzers and then deal with that barrel of fun. I’ve done this before in much smaller apps and very quickly got tired of typing ‘()’ 🙂
After disabling the analyzers my list of errors/warnings was brought “all the way down to” just over 4000. Oh wow I’m halfway done!! Ha ha.
The next thing I decided to tackle was another fairly easy one. Dealing with Product Group Code. If you’re not already aware, the Product Group Code feature was deprecated in favour of an improved parent/child Item Category structure. The Product Group Code fields however, were left in the product (not sure I like that, but we can deal with it) and marked for removal (see ObsoleteState property here). This causes any references to those fields to be flagged as warnings. Your code will still build, but this is a heads up that at some point in the future the fields will (probably!?) be removed. As I’m already head deep in things to fix and rework, I decided I’d rather not wait and I will remove references to those fields now.
For me, removing the references to the Product Group Code was pretty easy. We didn’t have major functionality tied to that field, but other ISV solutions may require more effort to remove those references, or, you may just choose to not deal with that now. Up to you.
That’s my update for now, back to fixing more issues. More updates to come!