AX2012 Terminating a compile worker


Moral of the story: NEVER KILL A COMPILER WORKER WINDOW EVER

There was a time I “accidentally” closed a compiler widow of a 10 worker process in the 2nd run.
Even though the main window notified that a worker terminated without any reason code, it still continued the process and reported that the compile was successful. Including an error log with a clean compile log (except for warnings, who looks at warnings!!! ūüėČ )
The next part which is compile the CIL went a bit weird.

The CIL compiler would start and AX stared at me for about a minute (as if its doing something, even the processors reported a good 98% usage for the AOS process) and then the AX screen came back to life.

The weirdness continues

  • It didn’t report anything.
  • There was no infolog to tell me that the services were generated, or the CIL compiler had failed.
  • There was nothing in the event log.
  • I even did a AOS restart with the deletion of the xppil folder, and yet I got the same result.
  • There was no CIL compiler log generated either.

So turns out (whatever happens inside the engine) that you should NEVER KILL A COMPILER WORKER WINDOW EVER !

via arkansas-investigations.com

[AX2012] Compare objects between models


SQL Makes everything better

When ever adding a new hot-fix or a new model from another source we need to compare the code touch points between that and existing code.

Ax makes that easy using the compare layers tool, however that only compares layers

So the other way is to go code upgrade and use those tools which may or may not work depending on your case (for example you put a 3rd part model and want to compare what var or cus or usr layer code you need to change)

This brings to writing x++ code or so in yummy SQL

Requirements:

  1. Know what models have changed

  2. Know what models will be affected / need to be compared

Know what models have changed

You know what hotfixes have been put in and there may be more than one. so note the numbers of the hotfixes or models that were added. Use the Get-AxModel command to get the models Ids for them

Know what models will be affected / need to be compared

You will probably need to know all the Models Id’s from the higher layers. So if you have a hotfix that you added then take a note of all model id’s that are a part of isv, isp, var, vap, cus, cup, usr, usp …. you know what i mean

The Fun begins with SQL

select et.ElementTypeName, et.TreeNodeName, med1.ParentHandle, med1.ElementHandle, me.* from ModelElementData med1
join ModelElement me
on ((me.ElementHandle = med1.ParentHandle and med1.ParentHandle <> 0)
or (med1.ParentHandle = 0 and me.ElementHandle = med1.ElementHandle))
join ElementTypes et
on et.ElementType = me.ElementType

where med1.ModelId in (<model ids changed in csv>)
and med1.ElementHandle in (select medisv.ElementHandle from ModelElementData medisv
where medisv.ModelId in (<model ids affected in csv>))
order by me.ElementType

That gives us a result set with main element type and the path to it.

Hopefully this gives an easier way to figure out what has changed and reduces your time. If this post does help you let me know, I am planning to invest in a query to further give more details about each element.

[AX2012] The AXRDCE extension caught an unexpected exception for report AutoReport


One of the errors received when running Print from a Form in AX 2012 (File > Print > Print, Or Ctrl + P) is the following:

The AXRDCE extension caught an unexpected exception for report AutoReport.

With the following message in the infolog

The error message was:
 Unable to find appropriate service endpoint information in the configuration object.
 Unable to find appropriate service endpoint information in the configuration object.
    at Microsoft.Dynamics.AX.Framework.Services.Client.Configuration.CustomConfigurationChannelFactory.UpdateServiceEndpoint(ServiceModelSectionGroup group, ChannelEndpointElement selectedEndpoint, ServiceEndpoint serviceEndpoint)
    at Microsoft.Dynamics.AX.Framework.Services.Client.Configuration.CustomConfigurationChannelFactory`1.CreateDescription()
    at System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address)
    at Microsoft.Dynamics.AX.Framework.Services.Client.Configuration.CustomConfigurationChannelFactory`1..ctor(Configuration configuration)
    at Microsoft.Dynamics.AX.Framework.Services.Client.Configuration.ChannelFactoryConfigurator.CreateClientChannelFactory[T](Configuration explicitConfiguration)
    at Microsoft.Dynamics.AX.Framework.Services.Client.Configuration.ClientConfigurationInternal.CreateXppChannelFactory[T](String relativeUri)
    at Microsoft.Dynamics.AX.Framework.Services.Client.XppServiceClient`1.CreateChannelFactory()
    at Microsoft.Dynamics.AX.Framework.Services.Client.ServiceClientBase`1.get_ChannelFactory()
    at Microsoft.Dynamics.AX.Framework.Services.Client.ServiceClientHelper.InvokeChannelOperation[TResult,TChannel](IServiceClient`1 client, Func`2 operationInvoker, Func`2 exceptionWrapper)
    at Microsoft.Dynamics.AX.Framework.Reporting.Shared.SRSFrameworkServiceProxy.Microsoft.Dynamics.AX.Framework.Reporting.Shared.IXppSRSFrameworkService.getRelationLinkTargetList(SRSFrameworkServiceGetRelationLinkTargetListRequest request)
    at Microsoft.Dynamics.AX.Framework.Reporting.Shared.SRSFrameworkServiceClient.Microsoft.Dynamics.AX.Framework.Reporting.Shared.ISRSFrameworkService.GetRelationLinkTargetList(String tableFieldsListEncodedStr)
    at Microsoft.Dynamics.AX.Framework.Reporting.Shared.TableFieldMenuItemService.GetRelationLinkTargetList(String fieldList)
    at Microsoft.Dynamics.AX.Framework.Reporting.Shared.TableFieldMenuItemService.Resolve(String encodedString)
    at Microsoft.Dynamics.AX.Framework.Reporting.Shared.AutomaticDrillThroughStep.Transform(XDocument report, ILocalReportContext reportContext, ILocalUserContext userContext)
    at Microsoft.Dynamics.AX.Framework.Reporting.Shared.CustomizationExtensionImplementation.ProcessReportDefinition(Byte[] reportDefinition, ILocalReportContext reportContext, ILocalUserContext userContext, Byte[]& reportDefinitionProcessed)

This Probably points to a corrupt configuration for the AIF services

What one may require to do is to Reconfigure the services by going to the Microsoft Dynamics Ax Configuration Utility and click the “Refresh” button in the “Connection” tab.

This should refresh the links to the WCF services.
Open the client using this updated config file and try it again

Other solutions that may work for you:
AX 2012 – Fatal AXRDCE Exception Error Addressed
Error printing within AX (To the screen and Physical printer)

AX 2012 ‚Äď Model dependencies and Install Order ‚Äď Part 2 – The app


Credit Nasa

From the follow up from Part 1, this post is more about how to find what models are dependent on what. I have created a console app which outputs csv files and can be downloaded here.

The inner workings:

So we know that ModelElement and ModelElementData hold the AOT objects for the respective models.

ModelElementData is the granular data. So a table field, a class method, a form control are stored here. They link to their parent using the ParentHandle field, or straight to the Main AOT object using the RootHandle.

The app takes every layer, from the ISV onwards , analyses each model and the model element data in them. It then looks if the element is used by any other layer below it OR if the root element is used in any other layer below or in the same layer.

How to use the App:

  • Set the minimum access layer – If you dont care about the SYS /SYP then set the Layer id to that of the ISV. Ofcourse if you work from VAR and beyond, then you probably dont care about ISV / ISP. So look at the Layer table and set the minimum access layer
    Set this in the Tag “MinApplicationLayer” inside the App.config file
  • Connection String – You dont need to set this up, unless you want to default to a specific Ax Database. This is good if you only care about one application. When the App runs, it will ask for user input for the database server and name. Not entering it will revert to the connection string in the App.config file

This is still a command line application, the output is still on the screen. But that’s the next phase of this app, to output the data to files or on screen. And also to make it power shell friendly

Ok, how the app works now:

Run the Exe in a command prompt: AxModel.Common.Exe (I will work on the name, I promise), put the database server, and the database name, and after  a few verbose output data in a CSV format is spit on the screen.

Copy that to excel and it should be all good from there.

The verbose output also outputs the dependencies if you want to look at it, which may be helpful.

Limitations: If you are referencing objects from one model to another in code, like a method in another object is  called from a class, then that will not be detected. This is mainly because cross reference will need to be looked at and is out of scope at this stage. I am focusing on installation dependencies

The code is available on GitHub and I should be updating it more as I conduct more tests and get more input about this.

Download Binaries

AX2012 Moving a project to another model


Do you need to worry about this?
1. You have more than one model in your layer (Apart from the base layer i.e. ISV layer)
2. The elements in your project can belong to more that one model in the same layer.

If you answered yes to any one of them, then word of caution, do not move the project directly.
Moving a project to another Model is a different Cookie. IT MOVES ALL THE ELEMENTS INSIDE IT TO THE LAYER YOU MOVE THE PROJECT TO!!! Yes that is in CAPS.

Method 1: Create a new Project in the desired Model and then Drag the elements from the original project into this new one.

Method 2: Database Crazy: You can play with the model database to do this, but i shall hold my guns on this one. I wouldn’t recommend this right now. Hint: ModelElementData.ModelId

Update 16/04/2015: I have created a script to assist you with this. Use this carefully. Link: https://github.com/shashisadasivan/MyScripts/blob/master/AX%202012/SQL/MoveProjectToAnotherModel.sql

AX 2012 – Model dependencies and Install Order – Part 1


Models in AX 2012 are a brilliant way to separate code between solutions in the same applications. They reduce merge time, allow code segregation and a lot more benefits.

Although, we do come to a point when code can start to depend on one another and even though it may look like it all works, at the time on installing those models into another application can cause an issue.

You say how?

Lets consider we are making changes to the VAR and the USR layer.

VAR Layer changes:

The VAR layer has the model, VAR_1 which has a class called: MyVar1Class, and this has methods method1, method2

At this stage we can export this model out and know that when installing this, it will not error out as this is not dependant on anything else.

USR Layer changes:

The USR layer has a model USR_1 which has a class MyUsr1Class with methods usr1Method1, usr1method2

At this stage, if we only take USR_1 model and put it into another application, we will not get an error. However, we add a method in class MyVar1Class called usr1MethodInVar1Class

Ok, we just complicated it. USR_1 model requires VAR_1 model.

Some more USR Layer changes:

Lets add a new model USR_2, with a class MyUsr2Class and some more methods in this. At this stage USR_2 is not dependant on the models VAR_1 or USR_1.

But if we add a method usr2MethodInUsr1Class in the class MyUsr1Class, now USR_2 is dependant on USR_1 which is dependant on the VAR_1 model.

Round robin change:

Switching back to the USR_1 model, we add a method to the class MyUsr2Class called usr1MethodInUsr2Class. This just means USR_2 is dependant on USR_1 which is dependant on USR_1 as well. The application compiles, its still a perfectly valid scenario.

So the Problem: With the above example when we export our models, and import it to another application, we will put in VAR_1 model first. Now while putting in USR_1 model, we will need the createparents switch which will create a virtual model, then we import the USR_2 model overwriting the existing model. This is a Giant mess. Not as giant as VAR code using USR layer code.

Save my day:

So I embarked on a mission to find out

  1. How could I figure out what models are dependant on what?
  2. How do i find from that, the sequence in which the models should be installed. (Some of the applications i deal with can have over 10 models in the same layer)

The answer: 42

Ummmmm, well, in some ways. There are other intergalactic species finding the ultimate question to that answer. But our answer lies in a few tables. Some of the tables conveniently hidden away from our sight, somewhere in the model database.

The model database has 2 tables I rely on for the dependency, ModelElement and ModelElementData.

ModelElement Table¬†: This Table is a collection of all the elements in the AOT, down to every node. from tables, fields, relations, enums, EDT’s, classes methods.

ModelElementData Table : This holds the actual content of the element, be it properties for elements like Tables, fields, EDTs or method definitions for classes. This links back to the ModelElement table. So the ModelElementData can be many records for a single ModelElementRecord. In our example, if we were to overwrite the method \Classes\MyVar1Class\method1 in USR_1 model, then we would end up having 2 records in the ModelElementDataTable for method1. The ModelElementData table also holds the information to what model and layer the element belongs to.

So from the information of these 2 tables, along with helper tables like ElementTypes, Model, ModelManifest and Layer I was able to find out what elements are common between models. I could then use this to map all the dependencies and find out the ordering in which to set the models to be imported in.

More to be continued ..

In the next post I will discuss the workings of the tool that will take the database, analyse the models and output a couple of CSV files, for the  dependencies and the model order.

AX2012 – Delete Ax Transactions


So there are apparently times when you would want to delete the transactions from the Ax 2012 installation, keeping all the parameters and configurations intact.

Ax has always had a class called SysDatabaseTransDelete which help in deleting the transaction tables. There are however rules on how and why it deletes them which can be followed by viewing that class.

In my Ax2012 cu7 environment I created a job which implements the same concept like the class, but outputs the result to a CSV file for you to analyze what will be deleted and what wont along with the record count. The record count is however company specific, so i would encourage you to dig straight into SQL to find the tables sizes and merge the results from there.

The Job in Ax 2012

Download the XPO and have a go at it.

It creates a File (hardcoded) in CSV format with the following header:

Table Group,Company Specific,Table name,SQL Table Name,Will be deleted,Row Count

Open the file in Excel, filter, sort, have fun.

What to learn from this

Table Group should be specified for every table that you create in Ax. If you leave it as miscellaneous, then Ax will never use it. This property is also used in analytics so its highly recommended to set this up.

Global Tables are not deleted by this unless handled specifically.

AX 2012 – Add elements to version control


Ive written a few jobs to scan the AOT and add it to version control.
(manged to misplace the job a few times now)

I stumbled across the following post regarding the same: Objects not in Version Control (AX 2012)

However, i changed some code in there to make sure that the job types were valid (like DEL_ names didnt get added to version control)

Following is the change i made to the code mentioned in the link above:

if(vcsSys.allowCreate(controlable))
{
    //sysTreeNode is of type SysTreeNode
    sysTreeNode = sysTreeNode::construct();
    sysTreeNode.parmTreeNode(pNode);
    if(sysTreeNode.canCreate() == true)
    {
        //do something if it isn't in version control
        info(strfmt("%1 %2",pNode.treeNodePath(), modelName));
        vcsSys.commandAdd(controlable); //SHS add to version control
    }
}

This job still requires refinement because it still adds Private projects which i want to avoid

AX 2012 – Export models in Sequence


Using powershell to import Ax model is a very straight forward approach.

I come under the situation where i have to export more than 1 model and need to let others know what sequence they go in because of their dependencies.

For this I maintain an excel sheet which the models / ID’s

So that means a few things while exporting:

1. They need to be in sequence

2. File naming conventions (Because we all have our own)

3. Painstaking process when we have to type the file name, model for each model we export.

Solution steps:

1. Powershell

2. Profits!

Ok explaining the solution, here is my powershell script which takes in the ModelId’s as a CSV string (no spaces) (so -ModelIds 32,33,45)

The database and server (database server) are defaulted (which can still be changed). Even the folder where this goes has a parameter.

It reads the modelIds that need to be exported (in the same sequence) and create file names with the suffix so that they are numbered.

You might say that if there are more than 9 models to be exported, then i need to do something with it (I havent reached that stage yet), but here is the script to share:

Param(
	#[Parameter(Mandatory=$true)]
	[String]
	$AxDBServerSource = 'SQLSERV_2012_1',
    [String]
	#[Parameter(Mandatory=$true)]
	$AxDBSource = 'ax_2012_r2_cu6_model',
#	[String]$AxDBServerDest = '.',
#	[String]
#	[Parameter(Mandatory=$true)]
#	$AxDBDest = 'AX_Standard_2012_new',
	#[Parameter(Mandatory=$true)]
	[String]$FolderTempModelStore = 'E:\temp\shashi\models'
	,[Parameter(Mandatory=$true)]
	[int[]]$ModelIds
)
#Created By: Shashi Sadasivan

function deleteLocalCache {
	Write-host 'Deleting *.AUC files'
    $localAppDataDir = "$(gc env:LOCALAPPDATA)"
	del $localAppDataDir\*.auc
}

CLS #Clears the screen
#Load the Ax Powershell script
Write-Host 'Loading Ax powershell scripts....'
& "E:\Program Files\Microsoft Dynamics AX\60\ManagementUtilities\Microsoft.Dynamics.ManagementUtilities.ps1"

#Printing the Details of values (Not necessary)
Write-Host 'Host Database: ' $AxDBServerSource'\'$AxDBSource
#Write-Host 'Destination Database: ' $AxDBServerDest'\'$AxDBDest
Write-Host 'Temporary folder:' $FolderTempModelStore

deleteLocalCache

#Export Models from source
#Delete Contents of Folder first
Write-Host 'Deleting Contents of Folder.....'
Get-ChildItem -Path $FolderTempModelStore -Recurse | Remove-Item -Force -Recurse
Write-Host 'Exporting Models to Folder......'

$AxModelListSource = Get-AXModel -Server $AxDBServerSource -Database $AxDBSource
$sequence = 0
foreach($modelId in $ModelIds)
{
	$sequence++
	$modelSource = $AxModelListSource | Where-Object {$_.ModelId -eq $modelId}
	if($modelSource -eq $null) {
		Write-Host "Model id" $modelId "not found in the application" -foregroundcolor "Red"
	}
	else {
		#Write-Host "Export Model " $modelSource.Name
		$locFileName = "$FolderTempModelStore\$($sequence)_$($modelSource.Layer)_$($modelSource.Name)_$($modelSource.Version).axmodel"
		#Write-Host $locFileName
		#Write-Host 'Exporting Model' $modelSource.Name
		Export-AXModel -Server $AxDBServerSource -Database $AxDBSource -Model $modelSource.ModelId -File $locFileName
	}
}