Introduction
Seasoned developers are probably aware of the benefits of using a package manager tool for installation and updates of packaged reference files and libraries. Such packages contain reusable code that are published to a central repository for consuming by other programs. The advantages to using such a tool is to maintain any common code in a common location, rather than needing to copy the individual files around and maintain their versions separately and manually. There are many public package managers available for different languages, frameworks, and platforms; such as the popular NuGet, npm, Bower, and yarn. This article focuses on the usage of NuGet because it is the standard package manager for Microsoft.NET – the platform used for Acumatica and its customizations.
Since I began developing customizations in Acumatica five years ago, and also coming from a deep .NET and client/server full-stack background, I’ve always wanted the Acumatica common libraries to be available as a package and have wondered why such packages weren’t already readily available. I have long wanted to fill this void myself in order to simplify the referencing of these libraries for our own custom code extension libraries. I recently was able to set this up for our company, Aktion Associates (an Acumatica VAR and Gold Certified Partner), and I’d like to share with you how this can be accomplished.
What is NuGet?
Stepping back for a moment, NuGet is a .NET package manager that’s integrated with Visual Studio.NET – the Microsoft development environment integrated and recommended for use to author code extensions for Acumatica customizations. NuGet is used to create and share reusable packages from a designated public or private host. https://www.nuget.org/ is the main NuGet Gallery repository to which public packages can be published, and from which .NET projects can consume. Popular packages such as Json.NET – a JSON parser and serializer – can be found here, as well as Microsoft.NET framework packages, and many others. Instead of searching the web for an installation program or the specific download file you need for a third-party library, NuGet can be used to retrieve and install the appropriate package of files and the version required simply by selecting it from its public host. NuGet can also be used for packages hosted privately for use internally for yourself or your company. Since Acumatica libraries are not available publicly via nuget.org, this article explains setting up these common libraries as private packages for use in your own customization projects.
There are many more guidelines for using and configuring NuGet that can be found within its documentation found at https://docs.microsoft.com/en-us/nuget than what is described here.
Using NuGet with Acumatica
To reference a NuGet package in your own customization extended library’s Visual Studio project, open your project in Visual Studio, right-click on the project’s References node in the Solution Explorer, and select the Manage NuGet Packages context menu option. This will open a window like the image in Figure 1, which displays NuGet packages already installed, and those available for install. If you Browse for “Newtonsoft.Json”, for example, from nuget.org, it should display that package in the results. When you select a package, you can then choose a specific version available from the specified package host and install it. That package will then show under your project references and its files can be referenced within your extended code. See Figure 2 for an example of referencing the Json.NET library in a C# Visual Studio project after installing it via NuGet.
Figure 1: NuGet Package Manager in Visual Studio
Figure 2: Referencing Json.NET after installing as a reference
The advantage to referencing libraries via NuGet like this is the simplicity, and allowing it to manage libraries and their versions without needing to do so manually. To then install a newer version of the library, you open the NuGet Package Manager again in Visual Studio from Figure 1, change the version to another available version, and Update. This is how I’d like Acumatica common library references to behave, and which is now possible with the solution outlined below.
Creating a NuGet Package
The first step is to create a NuGet package containing common Acumatica libraries. These common libraries are the most often used when writing a code extension in an external library. They include the following:
- PX.Common.dll
- PX.Common.Std.dll
- PX.CS.Contracts.dll
- PX.Data.dll
- PX.Objects.dll
I also like to include PX.Data.BQL.Fluent.dll because I prefer using Fluent BQL syntax within code.
The Package Manifest
A NuGet package manifest is created by defining the contents in a .nuspec XML file. The schema for a .nuspec file can be found within its documentation at https://docs.microsoft.com/en-us/nuget/reference/nuspec. The following XML shows an example of the contents of a .nuspec file (e.g. Acumatica.nuspec) for the Acumatica libraries mentioned above.
(Acumatica.nuspec contents)
GIST: https://gist.github.com/tlanzer-aktion/e76f8bc275cc3415344a1183666e59b5
Within this XML, the package is supplied a name (<id>) and a version (<version>), the files to reference in the destination Visual Studio project (<references>), and the source files to include in the package (<files>). Notice in this example that I’m naming the package Acumatica.PX.Main, and I’m including Acumatica build version 22.100.178 of its libraries.
Creating the Package
The next step is to create the package from the .nuspec package manifest. You can download nuget.exe from https://www.nuget.org/downloads, which is a command-line program used to create a NuGet package from a NuGet manifest. On the command line, the syntax to create the example package using nuget.exe is:
nuget pack Acumatica.nuspec -NoPackageAnalysis
This syntax assumes that both nuget.exe and Acumatica.nuspec is accessible within the current path, so if not, the path for one or both should be specified. The resulting package created from the example should be Acumatica.PX.Main.22.100.178.nupkg.
Additional Package Versions
Now that we have one build version of Acumatica’s common libraries packaged, you can continue creating additional versions as needed or as they are released by Acumatica. To create a new package for the following build version – 22.101.85 – you can repeat the instructions above but replace the version number and include that version of the libraries. You should then end up with a new package named Acumatica.PX.Main.22.101.85.nupkg, and so on.
Setting Up a NuGet Feed
To make a package available for project reference, it needs to be published to a NuGet feed. Since the package is meant for your own consumption, you’ll want to create a private feed for yourself or your organization. A private feed can be a local file share or server, or a remote private hosting service like Azure Artifacts or GitHub Package Registry. At Aktion Associates we use Azure DevOps as our source control repository, so we use Azure Artifacts as our feed host, and this will also be used for examples in this article.
Creating the Feed
To create a NuGet Feed in Azure Artifacts, open the Azure DevOps project in which you want to create a feed and choose Create Feed on the main Artifacts page. The dialog shown in Figure 3 should open. After naming and configuring the feed according to the visibility and scope of your needs, create the feed.
Figure 3: Create New Feed dialog
Publishing to the Feed
Now that you have both a NuGet package and a NuGet feed set up, you can publish the package to the feed. On the main Azure Artifacts page, choose Connect to Feed, then select NuGet.exe as the connection type, and copy the new feed URL shown. Then, on the command line, the syntax to publish the example package using nuget.exe is:
nuget push -Source <feed url> -ApiKey <any string> Acumatica.PX.Main.22.100.178.nupkg
This syntax assumes that both nuget.exe and Acumatica.PX.Main.22.100.178.nupkg is accessible within the current path, so if not, the path for one or both should be specified. The specified package should now be published to the feed and be accessible for referencing according to the configuration of your feed. Figure 4 shows an example private feed and package inside Azure Artifacts after creation and publishing.
Figure 4: Feed created in Azure Artifacts
Using Your NuGet Feed
After publishing your packages to your NuGet feed, you should be able to then reference the package and version from your feed inside your Visual Studio project as described in Using NuGet with Acumatica. In the NuGet Package Manager, add your new package source (i.e. the NuGet feed you created) from the Options dialog opened from the gear icon next to the Package source dropdown. After adding the feed, the published package should display in the list of available packages. Select the package in the list, and then the different published versions should be available in the Version dropdown to choose for installation or update. See Figure 5 for an example of what the Package Manager shows after selecting the package (e.g. Acumatica.PX.Main) in your new NuGet feed.
Figure 5: Selecting a NuGet package and version
Once you choose a package and appropriate version, installing or updating it creates reference to that package’s library versions in your Visual Studio project. See Figure 6 for an example of a C# Visual Studio project after installing the Acumatica.PX.Main NuGet package from a NuGet feed.
Figure 6: Visual Studio project after package installation
Other Acumatica Libraries
You can take this solution further and create additional NuGet packages for other commonly used Acumatica libraries like PX.Api, PX.Caching, PX.Web, etc. and repeat the steps mentioned above for these. Once those packages are created and published to your feed, you will also be able to reference these in the same manner.
Your Own Packages
If you have your own custom code extensions or common libraries that are generic enough for sharing across Acumatica modules, customization projects, or even instances; this solution is also a great option for reusing your own Acumatica custom extended libraries by creating NuGet packages for them. For example, Aktion has our own API custom library which adapts the existing Acumatica API to our own best practices for integration and communication, and we share it across projects via our own private feed.
Summary
I hope you find this solution for setting up a NuGet feed for Acumatica library packages useful, and I’d love to hear from you and how you’ve put it into use or adapted it for your own needs. It does require a bit of maintenance to keep package versions updated in your feed, but the efficiency gained by easily referencing and consuming an appropriate library version for your customizations and upgrade needs is substantial and valuable.
Happy Coding!