<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: luke</title>
    <description>The latest articles on DEV Community by luke (@justlucdewit).</description>
    <link>https://dev.to/justlucdewit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F942489%2F461019a2-c15b-43be-a0f7-c56aef89fb43.png</url>
      <title>DEV Community: luke</title>
      <link>https://dev.to/justlucdewit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/justlucdewit"/>
    <language>en</language>
    <item>
      <title>Dynamics365 Business central - Upgrade tags</title>
      <dc:creator>luke</dc:creator>
      <pubDate>Wed, 18 Jan 2023 09:37:04 +0000</pubDate>
      <link>https://dev.to/justlucdewit/dynamics365-business-central-upgrade-tags-335</link>
      <guid>https://dev.to/justlucdewit/dynamics365-business-central-upgrade-tags-335</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Sometimes you get into situations in which you need to change certain things within the BC database, or some other third party service, before allowing the user to use the application&lt;/p&gt;

&lt;p&gt;Maybe you want to migrate some records from table A to table B, or turn on a new setting on all existing records within a table.&lt;/p&gt;

&lt;p&gt;On most platforms, something like that would be called an "upgrade script", or a "seeder", and a system like this is definitely possible using business central's "upgrade tags"&lt;/p&gt;




&lt;h2&gt;
  
  
  Upgrade tags
&lt;/h2&gt;

&lt;p&gt;In Business central, you can add upgrade tags to your application which keeps track of all of the previous versions. That way you can compare the last upgrade tag to the current version, and do certain upgrade functions based on that.&lt;/p&gt;

&lt;p&gt;This is all handled within your install codeunit (a codeunit with SubType=Install), and upgrade codeunit (a codeunit with SubType=Upgrade).&lt;/p&gt;

&lt;p&gt;These upgrade tags do have a specific format standardized by Microsoft, however you can technically use any format. Microsoft recommends using &lt;code&gt;[CompanyPrefix]-[ID]-[Description]-[YYYYMMDD]&lt;/code&gt;. For example: &lt;code&gt;ABC-1234-MyExtensionUpgrade-20201206&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Install codeunits
&lt;/h2&gt;

&lt;p&gt;In the install codeunit, we need to set the upgrade tags that you decided to have until now, for example:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Whats happening here isn't that complicated. All we are doing is checking if an upgrade tag exists, and if not: make it exist.&lt;/p&gt;

&lt;p&gt;That way, when we freshly install the extension, we can be sure that all upgrade tags have been initialized, and therefore no upgrade function will be run (since we only want to run them when you upgrade from version A to version B, not when you do a fresh install).&lt;/p&gt;




&lt;h2&gt;
  
  
  Upgrade codeunit
&lt;/h2&gt;

&lt;p&gt;Now in the upgrade codeunit, we can check what upgrade tags we are missing, in which case we can activate some upgrade function, and add the upgrade function when we are done.&lt;/p&gt;

&lt;p&gt;This is done like the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;h2&gt;
  
  
  Debugging upgrade codeunit
&lt;/h2&gt;

&lt;p&gt;You might have some troubles debugging the upgrade script since its only triggered once you upgrade from one version to another. However this is easily fixed since you can force upgrade business central to upgrade from version X to the same version X. This wont actually do anything except trigger the upgrade codeunit (which we want)&lt;/p&gt;

&lt;p&gt;To do this, you need to go to your launch.json and set forceUpgrade to true:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "configurations": [
        {
            "forceUpgrade": true
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Upgrade Tags in business central is an excellent tool to handle seeders/upgrade scripts. And I highly recommend this system when tackling this problem.&lt;/p&gt;

&lt;p&gt;Make use of these build-in Microsoft AL functionalities as much as you want, and have fun coding!&lt;/p&gt;

</description>
      <category>welcome</category>
      <category>developer</category>
    </item>
    <item>
      <title>Dynamics365 Business central - Advanced debugging</title>
      <dc:creator>luke</dc:creator>
      <pubDate>Sat, 14 Jan 2023 18:46:41 +0000</pubDate>
      <link>https://dev.to/justlucdewit/business-central-advanced-debugging-3jdm</link>
      <guid>https://dev.to/justlucdewit/business-central-advanced-debugging-3jdm</guid>
      <description>&lt;h2&gt;
  
  
  Debugging in AL used to be a disaster for me
&lt;/h2&gt;

&lt;p&gt;I've always been annoyed by how AL (Application Language) is structured, and how the event based system makes it horrible to debug and trace your program. However, even tho the underlying system has some undeniable flaws, our gods from above (Microsoft) have done everything they could to make the best of it, giving us access to an entire toolkit of debugging methods, some of which, you might not be aware of.&lt;/p&gt;




&lt;h2&gt;
  
  
  Breakpoints
&lt;/h2&gt;

&lt;p&gt;I'm sure everyone and their grandma has heard about breakpoints, and uses them all the time in their day to day AL programming routine. Its a tool in visual studio code that lets you set a red dot on a specific line, forcing the BC server to stop execution of the code, and letting you inspect the surrounding context.&lt;/p&gt;

&lt;p&gt;In the debug panel (at the left side of visual studio code), you can also inspect global and local variables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kjdXIQm3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wm9phhf61rj3avbe8j1k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kjdXIQm3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wm9phhf61rj3avbe8j1k.png" alt="Global and local variables in the AL debugger" width="673" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depending on your preferences, you also might find it annoying that the debugger breaks on errors and/or on changes to records. To enable/disable this behavior, you can alter your launching profile found in &lt;code&gt;.vscode/launch.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"breakOnError"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"breakOnRecordWrite"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Event recorder
&lt;/h2&gt;

&lt;p&gt;One of the biggest question I always had while debugging with breakpoints was: "what caused SomeFunctionA to be called?". In the case of normal procedures, the answer can quickly be found with a simple project scoped ctrl + f on the query &lt;code&gt;SomeFunctionA\(&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;However in the case of events (which is common, since AL is an event based programming language). The answer to this question is often much more difficult to answer. What events are called when? and to what should I subscribe? what is the order of events being called?&lt;/p&gt;

&lt;p&gt;However, recently I found a very nice way to debug this: the build in 'event record'. This is a tool that is used within the business central web application, and can be opened by searching for the &lt;code&gt;Event Recorder&lt;/code&gt; page. When you open it, you will be presented by something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nBQscBW1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/esx0mo1c9k5tb7s00uol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nBQscBW1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/esx0mo1c9k5tb7s00uol.png" alt="The event recorder page" width="880" height="796"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you click &lt;code&gt;Record Events &amp;gt; Start&lt;/code&gt;, BC will start keeping track of any custom, or trigger event, that is being activated. &lt;strong&gt;make sure to not close the event recorder page, instead open new pages, by searching for them using the search glass, else the recording will be canceled.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can then perform all your actions that you want to inspect, and then click &lt;code&gt;Record Events &amp;gt; Stop&lt;/code&gt;, to stop the recording and display the list of activated custom/trigger events.&lt;/p&gt;

&lt;p&gt;Most of the time this will result in hundreds, if not thousands of entries, however just like any BC table, you can filter it on any property.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SbAkiWSK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y18coa1xj97be2fr8m19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SbAkiWSK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y18coa1xj97be2fr8m19.png" alt="Event recorder results" width="640" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This gives you a nice overview of what events are triggered, however, what if you wanted to subscribe a function to one of the events that you found using the event debugger? You could very easily scroll to the right of the event recorder table, until you find the &lt;code&gt;Get AL Snippet&lt;/code&gt; column, where you can click a link to give you automatically generated code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y3-H2ywT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sxvq1xo9gjm2lxwqvoxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y3-H2ywT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sxvq1xo9gjm2lxwqvoxk.png" alt="Auto generated code" width="880" height="801"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is often a huge timesaver since you dont need to dig trough documentation to find the event's arguments.&lt;/p&gt;




&lt;h2&gt;
  
  
  Callstack
&lt;/h2&gt;

&lt;p&gt;This one is a bit more known then the BC event recorder, but still deserves much love. It is a tool within the VSCode AL debugger, just like the local/global variable inspector. It appears when you are stuck on a breakpoint and looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PJUR86w8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ufre92tlgquzeler9sz0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PJUR86w8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ufre92tlgquzeler9sz0.png" alt="Callstack" width="537" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you might notice when trying this out, the top row contains the name of the function you are currently in, with the file and location of the function displayed on the right of that same row.&lt;/p&gt;

&lt;p&gt;But what if you wanted to know from what location the current function was called? maybe its only called in some condition, or maybe its called from some binding to an event.&lt;/p&gt;

&lt;p&gt;The most intuitive way to figure this out is by spamming  breakpoints on all places that calls the current function, however there is a much more efficient way:&lt;/p&gt;

&lt;p&gt;The callstack can be used for this exact purpose, see from what function, the current function has been called. In the image above, you can see that the current function named &lt;code&gt;Code&lt;/code&gt; was called from the function &lt;code&gt;PostSplitJnlLine&lt;/code&gt; which was in turn called from &lt;code&gt;RunWithCheck&lt;/code&gt;. You can also double click these rows to directly jump to that function call.&lt;/p&gt;




&lt;h2&gt;
  
  
  Watches
&lt;/h2&gt;

&lt;p&gt;Another debugging scenario, is when you want to keep track of the value of a variable when stepping trough breakpoints. Maybe you have an integer value named &lt;code&gt;MyNumber&lt;/code&gt; that incremented in different locations within the code, and you want to know how MyNumber ends up being a certain value.&lt;/p&gt;

&lt;p&gt;Instead of having to scroll back down to the variable section of the codeunit, to hover over the variable to inspect it, you could try adding it to the &lt;code&gt;Watch&lt;/code&gt; list in the debugger. Whenever you add a variable here, it will show it along sides its value during your debugging session.&lt;/p&gt;

&lt;p&gt;This way it will always be visible on your screen and you dont need to spam your code with &lt;code&gt;Message(Format(MyNumber));&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Good luck debugging
&lt;/h2&gt;

&lt;p&gt;This is the end of the article, I hope i taught you at least one helpful way of debugging that you didn't know was possible, Maybe I've even helped you prevent hours of debugging.&lt;/p&gt;

&lt;p&gt;Make use of these functionalities as much as you can, and have fun debugging your code!&lt;/p&gt;

</description>
      <category>businesscentral</category>
      <category>al</category>
      <category>microsoft</category>
      <category>dynamics365</category>
    </item>
  </channel>
</rss>
