Skip to main content

Notifications

Netmodules and X++

Netmodules and X++

In this blog we will discuss the concept of netmodules and how it relates to X++. You can argue that the concept of netmodules should not be of particular interest because the system manages it all for you, but there is some satisfaction in knowing how things work.

What are netmodules?

Netmodules are simply collections of compiled code; Managed DLLs can contain code of their own but can also contain references to any number of netmodules. The feature was originally implemented by the .NET team to allow a DLL to contain contributions from different programming languages: Contributions from VB.NET and C# for instance can be combined in an assembly by using the assembly linker tool, or though the C# compiler. This is what building an assembly with two netmodules looks like:

csc.exe /t:module /out:CsharpClass.netmodule CsharpClass.cs
vbc.exe /t:module /out:VbClass.netmodule VbClass.vb  
csc.exe /t:exe /out:Program.exe /addmodule:CsharpClass.netmodule /addmodule:VbClass.netmodule Program.cs

Here a C# class and a VB.NET class are compiled into netmodules with their respective compilers, using the /target (or /t) switch. Then these netmodules are combined in the last C# compiler invocation, creating the Program.exe assembly. Each netmodule has its own PDB file for the code residing in the netmodule. Using command line commands like show above is the only way to build netmodules; there is currently no support for combining contributions in different languages in Visual Studio.

How is it relevant?

In the C# world things are simple: The source code files in a project are presented to the C# compiler, that compiles them all and creates an assembly containing the IL code (and many other things). This is quite different from the way that an F&O application is built: The X++ code is organized in such a way that packages can contains millions of lines of code. If we did like C# does, we would have a truly terrible developer experience: If you added a semicolon somewhere, you would have to compile all the millions of lines of code again.
The reason we have this situation today is that breaking up the source code into smaller, more manageable chunks (possibly introducing namespaces in X++ as well) is a very expensive process, that we have not been able to undertake. The older technology we had in Ax2012 used an interpreter that did not care about these things. In Ax 7 we use the concept of netmodules to address these problems, as we will explain here.
The way we use netmodules is different when we do full builds and incremental builds.

Full builds:

Full builds are triggered by using the Build models… menu item as shown underlined in red below:
The Build models... menu item

and selecting the modules (aka packages) that you want to build. Here are the results of the full build operation on a module named AAAModel032022:

Netmodules in the output directory

Even when there are two forms in a module (called AAAForm1 and AAAForm2 in the screenshot below) there is one netmodule containing both the forms (namely Dynamics.AX.AAAModel03032022.Forms.0.netmodule). Netmodules are organized by the type of artifact they contain, and that is why there are netmodules with "Forms" as part of their names. The compiler puts around two hundred artifacts into each netmodule, so if there are more than two hundred forms, then the compiler allocates a new netmodule to put the next two hundred and so forth (By the way: The exact details about this can change in the future but will be transparent to the developers).

Incremental builds:

Incremental builds are triggered from the solution explorer, as shown below:

Incremental builds from the project

In the incremental mode the IL code for each element in the project generates its own netmodule. After doing an incremental build you will notice that forms AAAForm1 and AAAForm2 have been compiled into their own appropriately named netmodules, not bundled into a common one, among the rest of the elements in my solution:
Results of incremental build
For the debugger to load the proper symbols for your form(s) (or any other artifact in the projects inside the solution), all the model elements on it need to be incrementally built. This is because the F&O Visual Studio extension iterates over the complete list of elements in the project and adds the symbols (PDB files) for each of them to the debugger configuration before the debugging session starts.
So what happens when you have a package that has been subject to a full compilation and you now add a few artifacts to the VS project and compile? Surely the artifacts that are added are then already found somewhere in the netmodules that contain hundreds of other artifacts as well: Now the system needs to create a netmodule that only contains one artifact. Since we cannot have the same artifact defined in two different places the system will do a reorganization where it regenerates the original netmodule without the artifacts that are added to the project.
So now you may realize that the X++ compiler sometimes compiles many more artifacts that what initially meets the eye. That is the price we pay for the organic growth of the application code.

Comments

*This post is locked for comments

  • ES-Morten Profile Picture ES-Morten 12
    Posted at
    Hello. I have received a software deployable package from one of our vendors. This SDP contains the following files in the /bin folder. Dynamics.AX.CustomModel.0.netmodule Dynamics.AX.CustomModel.0.pdb Dynamics.AX.CustomModel.3.netmodule Dynamics.AX.CustomModel.3.pdb Dynamics.AX.CustomModel.4.netmodule Dynamics.AX.CustomModel.4.pdb + a lot of other files (.md, .dll, etc.) Since we started building our code base on platform version 10.0.31 we are facing this error when creating the software deployable package in the hosted pipeline. ##[error]Netmodule file missing:Dynamics.AX.Palette.1.netmodule, Netmodule file missing:Dynamics.AX.Palette.2.netmodule, The following article explains the error in detail: alexdmeyer.com/.../ Now the vendor is suggesting that we delete the .netmodule files and then re-install the software deployable package. This should supposedly solve the issue. However, I do not fully understand what complications this may have or if this is a viable solution. Can you shed some light on this?
  • MihaVuk Profile Picture MihaVuk 35 User Group Leader
    Posted at
    Hi Frank, I can debug the system code (including Application Suite) without adding it the the project or recompiling it. In VS options you should have 'Load symbols only for item in the solution' flag disabled. Then just open the source file, add a breakpoint and attach to the process.
  • _Frank Profile Picture _Frank 15
    Posted at
    Hi Peter, thanks for the explanations. So if I understand that correctly, it makes no sense to add an object of the Application Suite to my solution to be able to debug the code of that object. Because I would have to incrementally compile this Application Suite object which leads to a complete compilation of the Application Suite to remove that object from its existing modules. Am I right?