Application Integration Framework – download messages from log

I had to verify inbound messages but there where to many messages to go thru. So i decided to download them all and search thru them all via Notepad++.

Below code will download XML messages from the AIF log and save them on disk.

static void saveAifXmlBasedOnQuery(Args _args)
{
 #File
 #AIF

 date dt;
 utcDateTime utcDT;
 int timeOfday;

 str fileName, filePath;
 XmlDocument xmlDocument;
 AifMessageLog aifMessageLog;
 AifDocumentLog aifDocumentLog;
 AifXmlViewer aifXmlViewer;
 boolean xmlIsValid;

 filePath = @"c:\temp\";

 dt = today();
 timeOfday = str2time("00:00");
 utcDT = datetimeutil::newDateTime(dT,timeOfday);

while select aifMessageLog
 join aifDocumentLog
 where aifMessageLog.MessageId == aifDocumentLog.MessageId
 && aifMessageLog.Company == "<DATAAREAID>"
 && aifMessageLog.ActionId == @"<SERVICE.ACTION>"
 && aifMessageLog.PortName == @"<SERVICE>"
 && aifMessageLog.createdDateTime >= utcDT
 {
 fileName = strFmt("%1.%2", guid2str(aifDocumentLog.MessageId),"xml");

aifXmlViewer = AifXmlViewer::construct(aifDocumentLog.DocumentXml, AifXmlType::XML, guid2str(aifDocumentLog.MessageId));

if (aifDocumentLog.DocumentXml)
 {
 xmlDocument = new XmlDocument();
 if(xmlDocument)
 if(xmlDocument.loadXml(aifDocumentLog.DocumentXml))
 {
 xmlIsValid = true;
 }
 else{
 xmlIsValid = false;
 }
 }

if (aifXmlViewer.parmEncoding() == #Base64Encoding)
 {
 AifUtil::saveBase64ToFile(filename, aifDocumentLog.DocumentXml);
 }
 else if (xmlIsValid){
 AifUtil::saveXmlToFileOnClient(filePath+fileName, aifDocumentLog.DocumentXml, aifXmlViewer.parmEndpointId());
 }
 else{
 AifUtil::saveTextToFile(filename, aifDocumentLog.DocumentXml, aifXmlViewer.parmEncoding());
 }
 }
}

AX 2012 – RecordInsertList (basic sample)

Sample code….

Bad Practice:

RandomTable randomTableBuffer;

// Imagine this loop returns 10000 records.
while select randomTableBuffer where randomTableBuffer.RandomField1 == "1"
{
randomTableBuffer.RandomField2 == "2";
randomTableBuffer.insert();
}

This would insert a record in the database 10000 times. Of course this would work just perfectly fine but would give you horrible performance.

To avoid performance issues you can use a list of records and insert the records all at once.

Best Practice:

RandomTable randomTableBuffer;
RecordInsertList recordList = new RecordInsertList(tableNum(RandomTable));

// Imagine this loop returns 10000 records.
while select randomTableBuffer where randomTableBuffer.RandomField1 == "1"
{
randomTableBuffer.RandomField2 == "2";
recordList.add(randomTableBuffer); // Here you add the record currently in the tablebuffer into the array
}
recordList.InsertDatabase(); //Insert the records all at once.

To read it in more detail a nice blog post by Sávio Mendes de Figueiredo can be found here.

Dynamics AX 2012 R3 – Keeping track of errors

While debugging or any other development process you come across errors. Sometimes you click away the errors to fast or your client can crash. For these scenarios I created a error log. I only use this in my dev environment.

Add the following piece of code in the “Info” class, “Add” function.

Below is a table declaration.

//TODO NOT TO PRODUCTION!
//START DECL
DEVErrorLog errorLog;
//END DECL

At the end of the function you insert this piece of code just before the returning value.

//TODO NO TO PRODUCTION!
//START
if (_exception == Exception::Error || _exception == Exception::Warning)
{
ttsBegin;
errorLog.Exception = _exception;
errorLog.ErrorDescription = _txt;
errorLog.insert();
ttsCommit;
}
//END

If this class generates any Error or Warning messages it will insert it in the error log table. Error messages color RED and warnings will be yellow.

Download the two XPO files from https://www.dropbox.com/sh/zlyfbg9bqe4aowo/AACKO9wftOwbWBzfqiOyeL8na?dl=0

Dynamics AX 2012 – Update data progress bar

This job example will explain the use of SysOperationProgress class;

static void DEV_progress_example(Args _args)
{
 int i;
 #AviFiles
 
 SysOperationProgress progress = new SysOperationProgress();
 
 progress.setCaption('Processing something please wait'); /* Caption of the progress bar */
 progress.setAnimation(#AviUpdate); /* You can set different animations */
 progress.setTotal(100); /* Set total to keep progress of the progress bar (this case total records) */

 for (i=1;i<100;i++)
 {

 try
 {
 /* Setting the count on the progress bar */
 progress.setCount(i, 1);
 sleep(100); /* Sleep to demonstrate the progress bar */
 /* insert logic here */ 
 }
 catch
 {
 /* Some error handling */
 }
 }
}

Dynamics AX 2012 – Active Directory Users

Today i found a project i created in my early stages of programming in DAX. Here you can download the code, modify it to your needs.

Managing user accounts in Dynamics AX 2012 can be a hard task to handle. Type of licensing, user counts etcetera. To make life easier for the IT operation guys/girls i created a quick tool.

Project consists of a temporary table and a form. In this form you can query all the users of type Active Directory against your Active Directory to check if the account is active or not. It will return all the users in the form that have a disabled user account in active directory.

There is also a button available to disable the account in Dynamics AX 2012.

ToDo:

  • Create a menu item for the form

Tip: To make things faster you can remove the code from the form and create a class.

Download XPO: https://www.dropbox.com/s/sioaia1c8jxkevq/PrivateProject_DEV_ActiveDirectory.xpo?dl=0

Dynamics AX 2012 – axbuild.exe xppcompileall exception

Having several errors while developing in the development AX environment i decided it was time to do a recompile.

While executing the axbuild xppcompileall command for my AOS it returned the following error in the command prompt.

“Unhandled Exception: System.Runtime.InteropService.SEHException: External Component has thrown an exception. at wmainCRTStartup()”

The application log gave the following information.

“Log Name: Application Source: Dynamics Server Date: 6/3/2016 10:24:30 AM Event ID: 117 Task Category: None Level: Error Keywords: Classic User: N/A Computer: SERVERNAME Description: Object Server 03: The database reported (session 1 (-AOS-)): [Microsoft][SQL Server Native Client 11.0][SQL Server]The EXECUTE permission was denied on the
object ‘XU_GetSchemaVersion’, database ‘AX2012_model’, schema ‘dbo’.. The SQL statement was: “{ ? = CALL [AX2012_model].[dbo].[XU_GetSchemaVersion](?, ?) }””

I connected to the MSSQL server to check my security rights on the model store. For some reason my security rights where deleted from the model database. After i recreated my security rights on the MSSQL server instance it was possible for me to recompile again.

Dynamics AX – Common Solutions

Most common solutions you can use in Dynamics AX

  • Reset your usage data (File > Tools > Options )
  • Delete the AUC files from your local cache in your user profile
  • Compile if your code is giving errors you might not expect. Do not forget the forward compile if you extend classes
  • Synchronise the data dictionary
  • Restart the client
  • Restart the AOS

Edit:

Came across a more detailed list. Click here!

Dynamics AX 2012 – AUC files

While developing and testing i faced caching issues. As a user with -SYSADMIN- rights the code was executing correctly but as a normal user the code was not executing and was throwing weird errors. One of the errors created was “Function SysOperationDataContractInfo::newParameterInfo has been incorrectly called“.

The custom code extended the SysOperationServiceController and had complex levels of abstraction and old code was probably cached in the roaming profile of the user. After resetting the usage data the error was still thrown, time to remove the AUC files.

What are AUC files?
AUC files help speed up the application by storing objects locally, known as cache files. This means that you don’t need to download objects every time your using a functionality in Dynamics AX.

To ensure your executing new code while testing you need to remove these AUC files. The files are located in C:\Users\%username%\AppData\Local\ and have a GUID number in the filename and have the extension .AUC. Select the files and delete them.

If your not using a local profile remove the files from your roaming profile example network path: \\fileshare\userprofiles$\%username%\AppData\Local\.

When we removed the files and (re)started the Dynamics AX 2012 application the code was executing fine.