One of the main features introduced in AX for Retail R3 was the unified pricing engine in the Commerce Runtime (CRT). The exact same code is compiled and deployed to Enterprise POS, Mobile POS / Retail Server, Online Store, and the new Call Center. Furthermore, the source code for the entire pricing engine is included in the Retail SDK so it is very straightforward for a developer to make changes and deploy a customized version of the DLL to all of the channels.
In the initial R3 release you could deploy the exact same DLL to all channels. However, in the CU8 and later version of the SDK there is a slightly different way that you have to compile the DLL for Call Center. Unfortunately the Retail SDK shipped with a missing C# project that prevents you from deploying a customized version of the price engine for Call Center. Here are the steps to work around the issue until we release an updated version of the SDK in a future hotfix. The good news is that you do not have to have different branches of code for your customization.
Defining the Problem
In R3, the PricingEngine project only referenced the CRT as one DLL. For CU8 the CRT was broken out into multiple DLLs to make the code more flexible for other platforms. If you open the PricingEngine project you can see the differences:
The problem with the splitting of the DLL into four new ones, is that our build process doesn’t allow new DLLs to be introduced to the AX Client or AOS in a minor release like a cumulative update. To work around this issue, the Retail product team created a special “collapsed” version of the CU8 CRT which combined everything back to one DLL. If you look at Microsoft.Dynamics.Commerce.Runtime.dll in both your EPOS folder and you AX Client bin folder, you can see that they are very different. Likewise, the Microsoft.Dynamics.Commerce.Runtime.Services.PricingEngine.dll file is slightly different between the two folders.
The first task is to create a new C# project for the AX (Call Center) version of the DLL and update the references to point to the correct CRT.
Create the PricingEngineAX project
I will doing the steps on a CU9 instance, but the issue is also in CU8 so these instructions will work for both.
The first step is to navigate to the Pricing Engine subfolder under your Retail SDK location. By default the location should be: C:\Users\Administrator\Documents\Retail SDK CU9\Commerce Run-time\Services\Pricing
Create a new subfolder and call it PricingEngineAX:
Next, go into the PricingEngine directory and copy the Properties subfolder and Runtime.Services.PricingEngine.csproj file into the PricingEngineAX folder. After the copy is complete, rename the project file to Runtime.Services.PricingEngineAX.csproj. Your result should look like this:
Edit the project file
First we will fix up the project file a bit manually. Open your favorite text editor and load the Runtime.Services.PricingEngineAX.csproj file. Make the following changes:
- Lines 11-14: Delete these four references. We will add back the single reference in Visual Studio.
- Add the following to every line that starts with <Compile Include=”: ..\PricingEngine\ . This will make a relative link to the same source files that are in the other (non-Call Center) project.
- Search for IndiaPriceHelper.cs and delete the line. This file will not compile with the collapsed version of the SDK.
- There are two <OutputPath> entries, one for Debug and one for Release. The non-AX version of our DLL already goes to a “References” subfolder. Since our DLL will be named the same we don’t want to overwrite that version of the DLL. We will use the standard Visual Studio folders for this project. Do a search for the two <OutputPath> instances and change them to these:
- It’s also not a bad idea to generate a new GUID for the project. Search for <ProjectGuid> and copy in a newly-generated GUID. Hint: do a Bing search for “online guid generator” to find an online tool for creating a GUID.
Make sure to save the project file before going to the next step.
Add the project to the Commerce Runtime solution
Start a new instance of Visual Studio and open the Commerce Runtime solution. By default the location is C:\Users\Administrator\Documents\Retail SDK CU9\Commerce Run-time\Sdk.CommerceRuntime.sln
In the Solution Explorer, right-click on the solution and select Add > Existing Project. Navigate to the PricingEngineAX project file and add Runtime.Services.PricingEngineAX.csproj.
Before compiling, we need to add the reference to the correct CRT. In the new project, right-click on References and select Add Reference.
On the Reference Manager form, click on Browse on the left and then click the Browse button. Navigate to the AX client bin folder and select Microsoft.Dynamics.Commerce.Runtime.dll. Press the Add button to add the reference. If you don’t have an AX client on this machine, you can copy this DLL from another machine to any folder and reference it from there.
After you add the reference, find it in Solution Explorer and change the Copy Local property to False.
Before building the project, make a very simple code change so we can make sure the customized version of the price engine DLL is being used in Call Center.
Open Pricing\PricingEngine\PricingCalculators\BasePriceCalculator.cs and go to the CalculatePriceLines() method. On line 77 or so, add the following line to hard-code the price to 99.99 as shown in the picture:
Now right-click on the Solution and select Build Solution. If it builds with no errors you can navigate to the Bin\Debug folder and verify you got a new pricing engine DLL:
Note: If you get a Cryptographic failure error, see the note at the end of this article.
Updating AX to use the customized DLL
Make sure that your AOS is stopped and then copy your file to both the AX client bin and AOS bin folders. Make a backup of the existing price engine DLL first. On my test machine these are the locations:
- C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin
- C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin
If you plan on debugging the price engine, copy the PDB file across as well.
After restarting the AOS, start AX and open a developer workspace (AOT). Go to the References node and right-click to add a reference.
Click on the Browse button and select the DLL that you copied to the Client\Bin folder.
Press OK to add the reference to the AOT. Note that you may get a “Subnode already exists” error the first time you try this. If so, just go through the process a second time and it should work.
Expand out the References node and you should now see that PricingEngine is in your developer layer. You’ll also notice that the PublicKeyToken has changed to the signature of the keyfile you used when building the project.
You will have to compile a few classes for Call Center to pick up the new reference. To be on the safe side you should do a full compile of the AOT and generate a full CIL, but if you’re anxious to try things out, you can get away with just compiling the RetailSalesOrderCalculator and RetailPricingEngine classes.
After your compilation is complete, restart your AOS one last time to make sure that nothing is cached.
Test the custom price engine in Call Center
If everything worked correctly you can now test your custom price engine in Call Center. Log in to AX as a Call Center user. [See this blog post for setting up a Call Center user: http://blogs.msdn.com/b/axsupport/archive/2014/09/02/call-center-channel-user.aspx]
Go to Call Center > Common > All sales orders and create a new sales order for any customer. Add an item to the transaction and verify that your 99.99 price is calculated:
Now that you know it works you can start in on your actual development!
If you are getting a cryptographic failure when compiling the price engine project it means you don’t have a certificate (SNK) file where the C# projects expects it to be. By default, all projects in the SDK look for a file named StrongNameKey.snk in the root of the SDK: C:\Users\Administrator\Documents\Retail SDK CU9
For testing purposes you can just generate a quick test key with this filename and drop it in that folder. If you already have a signing key file you can update the projects in Visual Studio to point to that one instead. You can also create an unsigned version of the pricing engine which should work as well.
If you are having troubles getting AX to recognize your custom DLL there are a couple things you can try. First of all, the screenshot below is the most likely error:
Note that the PublicKeyToken of the DLL that is attempting to be loaded: it is Microsoft’s public key token. This means that it is not even trying to call the custom version.
The first thing you can try is to temporarily turn off CIL. In a developer workspace, go to Tools > Options > Development and turn off the Execute business operations in CIL option:
Another thing to check is to make sure DLLs aren’t getting loaded from the cached assembly folder. Here is an example of a such a folder: C:\Users\Administrator\AppData\Local\assembly\dl3\. If you delete all files under this folder, the cache will be rebuilt the next time you restart the AOS.
If all else fails, you can try these full steps to clean up the X++ compile and CIL. Some of these steps may be a bit too much, so you can try smaller steps:
- Stop the AOS
- Delete all AUC files for the user doing the compile (C:\Users\Administrator\AppData\Local)
- Delete all files C:\Program Files\Microsoft Dynamics AX\60\Server\<AXServerName>\bin\XppIL on the AOS server (you can back up this folder first).
- Truncate the SysXppAssembly table in SQL.
- Start the AOS
- Do a full X++ compile (use the AxBuild.exe trick for parallel compilation)
- Do a full CIL generation
- Restart the AOS
Attached below is my version of the .csproj file that you can try out in case you don’t want to make all of the manual edits.
My next blog post on this topic will be some tips and tricks for debugging the pricing engine so stay tuned for that!