How to use a recurring Integration Endpoint for importing data
You are here
Upgrading Classes from 2012 to D365FO
Related to this post, we're going to take a closer look at classes ( and jobs ) and go over some of the common scenarios for code upgrade. The LCS Code upgrade tool will do its best to intelligently upgrade and convert your code but it will need your help a lot of the time. First, the tool is saving you tons of re-work. While it may get it wrong some of the time, its still doing lots of work. You will still need a 2012 instance with the code base available for reference. Second, this exercise is where if you, or any other developer, were lazy, you now have more work. If you didn't follow good practices for commenting, using layers correctly, not making changes in the USR layer, making changes in production and only in production, and so on, this is where you'll feel that pain. As a good first step, clean up your 2012 code before you upgrade it. Take the time to go back and clean it up, remove pointless carriage returns, if any, add comments, just follow all of the best practices that Microsoft recommends and the upgrade process will go more smoothly. With that out of the way, let's look at a few common scenarios you'll have and how to handle them.
Classes
We'll start in the "delta" directories in our model directory for classes. For instance K:\AosService\PackagesLocalDirectory\ApplicationPlatform\ApplicationPlatform.CUS Model\AxClass\Delta. This directory will contain all of our overlayer elements. Anything that is not an overlayer (ie, a net new class) will appear 1 directory up in K:\AosService\PackagesLocalDirectory\ApplicationPlatform\ApplicationPlatform.CUS Model\AxClass\
New Method(s) (and only new methods)
This is the simplest case and the one of the best to run into. Here is an example.
This is a diff inside VS. On the left hand side is the baseline object from Microsoft. On the right is my upgraded code from 2012 placed into an overlayer model (In Application Platform) on class ApplicationVersion. In this instance, we have a single new method and that's it. No other overlayers in any other methods. For this new method, we just need to move it into an extension. You can right click on ApplicationVersion then select "Create Extension" or add a new class and call it ApplicationVersionBMC_Extension ( or [ClassName][CodeOwnerSuffix]_Extention ). Next, just copy, paste the method into the new extension class, like so:
[ExtensionOf(classStr(ApplicationVersion))]
final class ApplicationVersionBMC_Extension
{
public static str BMC_Version()
{
return "6.3.5000.0016.00";
}}
Also, as a call out, anything overlayered will appear on a light blue background so when looking at code for the element, it stands out.
Overlayers
Next, we'll cover overlayers - or changes in which you made customizations to a method and now need to refactor that so it works in an extension model. Let's use the code below as an example. You'll notice the code below has the original code commented out, we have comments and in general, everything looks good from a best practice perspective. Hopefully this is what you will experience. If you decided to be lazy a year or two ago, this is when the laziness tree will bare fruit most foul.
In class CustCreditLimit, we want to add an additional condition to the return of method mustCheckCreditLimit. This is a great candidate to refactor using Chain of Command. Like our last example, we'll want to make an extension class, then add the following method:
[ExtensionOf(classStr(CustCreditLimit))]
final class CustCreditLimitBMC_Extension
{
/// <summary>
/// BMC_276 start 7/13/2017
/// </summary>
/// <param name = "_salesTable"></param>
/// <param name = "_creditMaxCheck"></param>
/// <returns></returns>
public static boolean mustCheckCreditLimit(SalesTable _salesTable, CustCreditMaxCheck _creditMaxCheck)
{
//call base logic
boolean ret = next mustCheckCreditLimit(_salesTable, _creditMaxCheck);//take that result and combine it with our additional condition
return (ret && !_salesTable.BMCAllowCreditOverride);
}}
As you can see, its fairly simple to handle in this case as its just an extra condition and its a fairly elegant solution to our overlayer problem. However, not everything is this simple so you'll have to do your best to determine where to hook in / extend to get your desired results. Depending on what you are doing you may have to go a few methods up and out to find a good place.
Total Rewrites
If you or Microsoft made significant changes or re-writes to something, it can be a hassle to track all of that down. Let's consider this code:
It looks scary as we have some red and a lot of green. After more inspection, method showErrorMesg in class CustCreditLimit had a major refactor between AX 2012 CU12 and Version 10 of Dynamics 365 for Finance and Operations. We'll not have to evaluate exactly what was in this specific customization in 2012, even though we have some great comments, then pick it apart into pieces of that customization then rebuild and integrate it into extensions in D365FO. In each scenario where you encounter major differences, you'll have to break it all apart and rebuild it in the new extension model. This can be time consuming but also can help deliver some more elegant and re-usable solutions.
Manual KB Merges
Although most won't admit to it, they have manually copy/pasted code for KBs directly from LCS just because they only needed 1 or 2 lines of code and didn't want to take a bunch of other KBs that came with the 1 KB you want. It's not great but it happens. What that will look like for upgraded code is simlar to this:
Notice we have no green or red on either column on the right. This means we have an overlayer with a net no difference in terms of the output. However, the upgrade tool saw the CUS layer model from 2012 and upgraded it in place and it just happened to upgrade the code into exactly what is in the baseline object in version 10. This is an overlayer with no changes in the overlayer. To resolve this, we just have to delete the overlayer element. Because of how some 2012 KBs are packaged, there may be no way around this or it may not be practical. This is an easy case to resolve - its just annoying.
Net New Classes
All new classes will show up 1 directory above the delta directory, ie K:\AosService\PackagesLocalDirectory\ApplicationSuite\ApplicationSuite.CUS Model\AxClass. These classes simply just need to be moved into your target model for your organization. To do this, find the file in source control explorer, right click then select "Move..." and move it from the overlayer models folder to the target models folder. Look at the "Processing (Net) New Elements" in this article for additional info.
Jobs
During the upgrade, all jobs are turned into classes. Since the concept of a job no longer exists in D365FO, you'll have to evaluate if each job did anything valuable and if so, rebuild it so it can be used via the standard web interface and their is no AOT anymore outside of the developer environment. It has been my experience that most jobs upgraded to classes are just deleted. LCS will commit them to source control initially so you can always look them up if you need them back. However, management / resolution of data issues via a job is no longer an option so these are more like post-it notes for a solution rather than a solution anymore.
Bringing It all together
Once you have started upgrading your code, you'll notice all of the other dependencies to get stuff simply to compile. When starting this effort, keep in mind what you are doing and make sure you are starting with a good, clean, hopefully BP rich code base. If not, you'll have a fair amount of detective work to determine how to refactor some code. Once you get started, you'll be surprised how fast it goes and great it is to work with extensions. Next time we'll talk about EDTs and tables.