Tuesday 5 June 2018

Import label files X++

Following job can be used to import multiple label files from a folder. The label files are not automatically saved in AOT so a manual Save all is required.

static void LabelFileImport(Args _args)
{
    #File
    
    FilePath                        directoryPath, filePath;
    Filename                        fileName, fileNameWithPath;
    SysLabelFile                    labelFile;
    Set                             languages;    
    
    System.String[]                 files;
    System.Collections.IEnumerator  enumerator;
    
    directoryPath = @"D:\TempNav\LabelFiles"; // folder to import from
    info(strFmt("Import path: %1", directoryPath));
    
    try
    {
        files = System.IO.Directory::GetFiles(directoryPath, '*.ald');
        enumerator = files.GetEnumerator();
    }
    catch
    {
        info(strFmt("Failed to get file list from path %1", directoryPath));
    }
    
    if (enumerator)
    {
        while (enumerator.MoveNext())
        {
            fileNameWithPath = enumerator.get_Current();
            
            try
            {
                [filePath, fileName] = fileNameSplit(fileNameWithPath);
                
                labelFile = SysLabelFile::newFilename(fileNameWithPath);
                languages = new Set(Types::String);
                languages.add(labelFile.parmLanguageId());
        
                SysLabelFile::createLabelFileInAOT(labelFile.parmModuleId(), languages);
                labelFile.importAldFile(fileNameWithPath);
        
                info(strFmt("@SYS322092", fileName));
            }
            catch
            {
                info(strFmt("Filed to import file %1", fileName));
            }
        }
    }
}

This posting is provided "AS IS" with no warranties. Use code at your own risk.

Tuesday 22 May 2018

Export label files X++

Following job can be used to export multiple label files of a particular language to a folder. There is an option to save the files as a different language file as well (in case the files are to be used for translation or to be imported as different language)

static void LabelFileExport(Args _args)
{
    #File

    SysLabelFile    sysLabelFile;
    str             labelModule, labelFileName, labelLanguage;
    str             labelSaveAsLanguage, labelSaveAsFileName;
    container       labelModuleCon;
    int             i;
    FilePath        path;
    FileName        fileName;

    path                = @"D:\TempNav\LabelFiles"; // folder to export to
    labelModuleCon      = str2con("ASC,ASG"); // labels to export
    labelLanguage       = "en-us";
    labelSaveAsLanguage = "en-za"; // set as "" to export with original language name

    if (!strEndsWith(path, #FilePathDelimiter))
    {
        path += #FilePathDelimiter;
    }
    info(strFmt("Export path: %1", path));

    for (i = 1; i <= conLen(labelModuleCon); i++)
    {
        labelModule = conPeek(labelModuleCon, i);

        try
        {
            labelFileName = strFmt("Ax%1%2.ald", labelModule, labelLanguage);

            if (labelSaveAsLanguage != "")
            {
                labelSaveAsFileName = strFmt("Ax%1%2.ald", labelModule, labelSaveAsLanguage);
                fileName = path + labelSaveAsFileName;
            }
            else
            {
                fileName = path + labelFileName;
            }

            sysLabelFile = SysLabelFile::newFilename(labelFileName);
            sysLabelFile.toFile(fileName);

            if (labelSaveAsLanguage != "")
            {
                info(strFmt("Successfully exported label file %1 as %2", labelFileName, labelSaveAsFileName));
            }
            else
            {
                info(strFmt("Successfully exported label file %1", labelFileName));
            }
        }
        catch
        {
            info(strFmt("Failed to export label file %1", labelFileName));
        }
    }
}

This posting is provided "AS IS" with no warranties. Use code at your own risk.

Thursday 5 April 2018

Access error in batch jobs/printing of reports

Recently we had production machines operating system patched. After the patching, we had a production deployment of new code. When the AOS were brought back up, some of the application processes started throwing errors. These included AIF/workflow batch jobs, printing of some reports etc. The error message was as follows


Infolog for job AIF (5641187121)
Infolog for task AifInboundProcessingService (5651730951)
Cannot read a record in AifResponse (AifResponse).
The corresponding AOS validation failed.
AifInboundProcessingService-run
Microsoft.Dynamics.Ax.Xpp.ErrorException: Exception of type 'Microsoft.Dynamics.Ax.Xpp.ErrorException' was thrown.
   at Microsoft.Dynamics.Ax.MSIL.Interop.throwException(Int32 ExceptionValue)
   at Microsoft.Dynamics.Ax.MSIL.cqlCursorIL.DeleteAll(IntPtr table)
   at Dynamics.Ax.Application.AifResponse.deleteExpiredResponses() in AifResponse.deleteExpiredResponses.xpp:line 7
   at Dynamics.Ax.Application.AifInboundProcessingService.Run() in AifInboundProcessingService.run.xpp:line 35
   at Dynamics.Ax.Application.BatchRun.runJobStaticCode(Int64 batchId) in BatchRun.runJobStaticCode.xpp:line 54
   at Dynamics.Ax.Application.BatchRun.runJobStatic(Int64 batchId) in BatchRun.runJobStatic.xpp:line 13
   at BatchRun::runJobStatic(Object[] )
   at Microsoft.Dynamics.Ax.Xpp.ReflectionCallHelper.MakeStaticCall(Type type, String MethodName, Object[] parameters)
   at BatchIL.taskThreadEntry(Object threadArg)
Infolog for task AifGatewayReceiveService (5651730959)
Cannot create a record in Gateway queue (AifGatewayQueue).
The corresponding AOS validation failed.
Cannot create a record in Gateway queue (AifGatewayQueue).
The corresponding AOS validation failed.
Cannot create a record in Gateway queue (AifGatewayQueue).
The corresponding AOS validation failed.
Cannot create a record in Gateway queue (AifGatewayQueue).
The corresponding AOS validation failed.
Cannot create a record in Gateway queue (AifGatewayQueue).
The corresponding AOS validation failed.


Infolog for job Workflow message processing (5641359370)
Infolog for task Workflow message processing task (5652234909)
User 'BatchUser' is not authorized to update a record in table 'SYSWORKFLOWTABLE'. Request denied.
Cannot edit a record in SysWorkflowTable (SysWorkflowTable).
Access Denied: You do not have sufficient authorization to modify data in database.
User 'BatchUser' is not authorized to update a record in table 'SYSWORKFLOWTABLE'. Request denied.
Cannot edit a record in SysWorkflowTable (SysWorkflowTable).
Access Denied: You do not have sufficient authorization to modify data in database.
SysWorkflowQueue-activate
SysWorkflow-lock
SysWorkflow-fault
SysWorkflow-internalFault
SysWorkflow-faultWorkflowInstance
Microsoft.Dynamics.Ax.Xpp.ErrorException: Exception of type 'Microsoft.Dynamics.Ax.Xpp.ErrorException' was thrown.
   at Microsoft.Dynamics.Ax.MSIL.Interop.throwException(Int32 ExceptionValue)
   at Microsoft.Dynamics.Ax.MSIL.cqlCursorIL.update(IntPtr table)
   at Dynamics.Ax.Application.SysWorkflow.faultWorkflowInstance(SysWorkflowTable _workflowTable, String _user, String _faultMessage) in SysWorkflow.faultWorkflowInstance.xpp:line 66
   at Dynamics.Ax.Application.SysWorkflow.internalFault(WorkflowContext _workflowContext, String _user, String _faultMessage) in SysWorkflow.internalFault.xpp:line 56
   at Dynamics.Ax.Application.SysWorkflow.fault(WorkflowContext _workflowContext, String _user, String _faultMessage) in SysWorkflow.fault.xpp:line 32
   at Dynamics.Ax.Application.SysWorkflowQueue.dispatch(Guid _affinity) in SysWorkflowQueue.dispatch.xpp:line 185
   at Dynamics.Ax.Application.SysWorkflowQueueTask.Run() in SysWorkflowQueueTask.run.xpp:line 13
   at Dynamics.Ax.Application.BatchRun.runJobStaticCode(Int64 batchId) in BatchRun.runJobStaticCode.xpp:line 54
   at Dynamics.Ax.Application.BatchRun.runJobStatic(Int64 batchId) in BatchRun.runJobStatic.xpp:line 13
   at BatchRun::runJobStatic(Object[] )
   at Microsoft.Dynamics.Ax.Xpp.ReflectionCallHelper.MakeStaticCall(Type type, String MethodName, Object[] parameters)
   at BatchIL.taskThreadEntry(Object threadArg)


The error message showed that user does not have access to the tables. However even granting System Administrator was not fixing the issue. The only workaround we could find was to deactivate an AIF port. This somehow fixed the issue.


We opened a case with Microsoft and solution provided by MS engineer was to make sure that the SID in the following registry key was that of the account running AOS service. In our case the SID was that of the user who installed the AOS on these machines.


HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Dynamics\6.0\Setup\Dynamics Server\setupuser




After changing the registry key on all AOS (while the AOS service was not running), the error disappeared. Please take a backup before modifying registry.


This posting is provided "AS IS" with no warranties. Use code at your own risk.

Saturday 24 March 2018

BizTalk Server Application Configuration - SSO database export file enctyption/decryption

While working on AX integration using BizTalk, a requirement arose to save some of the configuration data. There are several options available as described in this article.

We decided to store the configuration in the SSO database. While the MMC snap-in provided by Microsoft is good enough, there is no option to bulk edit the Key/Value pairs stored in the SSO database. The snap-in does allow to export the file, but its encrypted and hence cannot be edited outside of the snap-in.

We wrote a small utility which allows to decrypt/encrypt the files exportable from the snap-in. Once exported, the file can be decrypted, edited in a text editor, encrypted again and can be imported in the snap-in to create the key/value pairs in the SSO database.


The utility can be downloaded from here.

This posting is provided "AS IS" with no warranties. Use code at your own risk.

Tuesday 20 February 2018

Synchronization error due to SQL Plan Guides



Recently we had to create a plan guide in SQL Server (not a good long term solution). Everything seemed to be working fine until we had a production deployment and the database synchronization failed as shown in the screenshot below.




It seems that during synchronization a store procedure is recreated. As our plan guide was based on queries in the stored procedure, AX was unable to drop it. Only solution was to drop the plan guide (disabling the plan guide did not help) and re-create it after the synchronization.


This posting is provided "AS IS" with no warranties. Use code at your own risk.