A tipical performance tip is to put all display methods on datasource cache:
https://msdn.microsoft.com/en-us/library/aa596691.aspx
Using something like that on init method of datasource
this.cacheAddMethod(tableMethodStr(CustTable, Name));
Pay attention, the value of all cached methods is set when data is fetched from the back-end database. If you put a display method on a separated tab, not vibile when the form is opened, the method is called the same for each record of datasource when form start, causing a performance problem if the display method is complex. If you remove the method from the cache the display method is called only when the control appears to the user.
Than, add the method cache only if the control is visibile to the user into the main grid or main tab, otherelse assessed whether the performances have a real advantage.
martedì 28 giugno 2016
giovedì 9 giugno 2016
INFO: Dynamics AX 2009 file extensions
I found good
information which I want to share with all of you, some times we wonder as to
what a particular ax system file is and what it does now you can bank upon the
list given below for all such enigma. Dynamics AX uses a lot of file
extensions, but luckily, there is a logic to them, so you can easily identify
their purpose.Most of these files are located in the application folder (AX
2009):
C:\Program
Files\Microsoft Dynamics AX\50\Application\Appl\[your_application]
The extensions have 3 characters:
- The first character indicates the owner of the file:
- a: application
- k: kernel
- The second character indicates the content of the file:
- l: label
- o: object
- t: text
- d: developer documentation
- h: help
- Third character indicates the type of file
- d: data
- i: index
- c: cache
- t: temporary
Using this logic, we can easily name all file extensions, and understand their purpose.
In the application folder:
- ALD extension: Application Label Data files These files contain the labels and label comments for a specific language of a label file.
- ALC extension: Application Label Cache files These files contain the application label cache. These files can be deleted when the AOS is stopped.
- ALI extension: Application Label Index files The .ali files contain an index to the .ald files. These files can be deleted when the AOS is stopped.
- ALT extension: Application Label Temporary files. These files contain new labels before they are committed to the .ald file.
- AOI extension: Application Object Index file. The AOI file contains an index to the AOD files. You can delete this file when the AOS is stopped. Be sure to delete this when you have copied layers from one AX installation to an other.
- ADD extension: Application Developer Documentation Data files. These files contain the documentation that is found under the Application Developer Documentation node. These files are localized, just like label files.
- ADI extension: Application Developer Documentation Index files. This is the index to the ADD file.
- AHD extension: Application Help Data files. The AHD file contains the documentation aimed at the end user. In the AOT, this is found in the “Application Documentation” node.
- AHI extension: Application Help Index files. This is the index to the AHD file.
- AOD extension: Application Object Data file. This is the ‘AX layer file’, each of these files represents one layer.
- KHD extension: Kernel Help Documentation files. These files contain the kernel help documentation you can find in the AOT in the tree node System Documentation.
- KHI extension: Kernel Help Index files. The KHI file is the index to the Kernel Help file. Located in Server/bin:
- KTD extension: Kernel Text Data file. This file contains system text strings. These are used in the interface of AX and for system messages.
- KTI extension: Kernel Text Index file. This is the index to the KTD file.
Client side (not following the naming logic):
- AUC extension: Application Unicode Object Cache file (as from AX 4.0). This file is created on the client side, and is used to improve performance by caching AX objects. When you are in the situation where an AX client keeps using ‘old code’, or where something works on one client and not on the other, removing the AUC file might be the solution. You can find this file in the directory "C:\Documents and Settings\[USERNAME]\Local Settings\Application Data for xp, or C:\Users\USERNAME\AppData\Local for vista.
- AOC extension: Axapta Object Cache file (Untill Axapta 3). This is the ‘old’ version of the AUC file but serves the same purpose.
* Note: GREEN file's can be deleted when AOS is stopped
giovedì 26 maggio 2016
HOWTO: Debug the AifOutboundProcessingService
If you need to go more in depth using debugging of an outbound you have to write down a couple of customization on standard code:
- Comment out the runas method on AifOutboundProcessingService.runAsUserInPartition method and replace with a direct call to processAsUser method.
/*
// runAs currentUser and process all messages in the container.
new RunAsPermission(runAsUserId).assert();
// BP deviation documented
runas(runAsUserId,
classnum(AifOutboundProcessingService),
staticmethodstr(AifOutboundProcessingService, processAsUser),
messageIdContainer,
runAsCompany,
'',
runAsPartition);
// Revert the permission
CodeAccessPermission::revertAssert();
*/
AifOutboundProcessingService::processAsUser(messageIdContainer);
Important: You have to run the code on the same company and partition specified on runAsCompany and runAsPartition parameter.
- Comment out or o skip execution this line of code on AifDispatcher.dispatchOperation method
//new AifDispatcherPermission().demand();
For process the message queue use the new AifOutboundProcessingService().run() method
HOWTO: Create computed columns in Views on Dynamics AX 2012
Computed columns have been using in SQL server since many versions but this feature was available Dynamics AX since version 2012.
Follow steps described here to learn how to create view and walthrough the complete example to understand how can we add computed columns in AX 2012 Views. More examples can be found from here; http://daxmusings.codecrib.com/2011/10/computed-view-columns-in-ax-2012.html
Well, here is an example which illustrates how can we add computed columns in a view with different logic.
Follow steps described here to learn how to create view and walthrough the complete example to understand how can we add computed columns in AX 2012 Views. More examples can be found from here; http://daxmusings.codecrib.com/2011/10/computed-view-columns-in-ax-2012.html
Well, here is an example which illustrates how can we add computed columns in a view with different logic.
Computed column; Returning Field in View
public static server str compAmount()
{
#define.CompView(SWProjForecastCost)
#define.CompDS(ProjForecastCost)
#define.CostPrice(CostPrice)
return SysComputedColumn::returnField(tableStr(#CompView), identifierStr(#CompDS), fieldStr(#CompDS, #CostPrice));
}
Computed column; Converting UTC Date to Date in View
public static server str compDate()
{
#define.CompView(SWProjForecastCost)
#define.CompDS(ProjForecastCost)
#define.ActualDateTime(ActualDateTime)
str sDateTime;
sDateTime = SysComputedColumn::returnField(tableStr(#CompView), identifierStr(#CompDS), fieldStr(#CompDS, #ActualDateTime));
return SysComputedColumn::fromUtcDateToDate(sDateTime);
}
Computed column; Returning Enum Value in View
public static server str compGeneralTransType()
{
return SysComputedColumn::returnLiteral(Transaction::ProjectInvoice);
}
Computed column; Multiplying two coulmns and returning resultant from View
private static server str compTotalCostPrice()
{
#define.CompView(SWProjForecastCost)
#define.CompDS(ProjForecastCost)
#define.QtyCol(Qty)
#define.PriceCol(CostPrice)
return SysComputedColumn::multiply(
SysComputedColumn::returnField(
tableStr(#CompView),
identifierStr(#CompDS),
fieldStr(#CompDS, #PriceCol)
),
SysComputedColumn::returnField(
tableStr(#CompView),
identifierStr(#CompDS),
fieldStr(#CompDS, #QtyCol)
)
);
}
Computed column; Case Statement in View
public static server str TransType()
{
#define.CompDS(ProjForecastCost)
#define.CompView(SWProjForecastCost)
str ret;
str ModelId = SysComputedColumn::returnField(identifierStr(SWProjForecastCost), identifierStr(ProjForecastCost), identifierStr(ModelId));
ret = "case " + modelId +
" when 'Sales' then 'Forecast Sales' " +
" when 'Orders' then 'Forecast Orders' " +
" when 'Latest' then 'Forecast Latest' " +
" end";
return ret;
}
Case Statement for this view looks like in SQL server as below;
CASE T2.MODELID
WHEN 'Sales' THEN 'Forecast Sales'
WHEN 'Orders' THEN 'Forecast Orders'
WHEN 'Latest' THEN 'Forecast Latest' END
mercoledì 4 maggio 2016
martedì 19 aprile 2016
X++: How to find what projects an object from the AOT exists in (Recursive)
To find out what projects an AOT object exists in, use this script.
It's recursive, than it can find methods or inner nodes too
ProjectNode projectNode;
ProjectListNode projectListNode;
TreeNode treeNode;
TreeNodeIterator treeNodeIterator;
// Object we are searching for
TreeNode tnSearch = TreeNode::findNode(@'\Classes\MHT_DOCF_MasterTable');
void find(TreeNodeIterator _innerTreeNodeIterator)
{
TreeNode innerTreeNode;
;
innerTreeNode = _innerTreeNodeIterator.next();
while (innerTreeNode)
{
if (innerTreeNode.treeNodePath() == tnSearch.treeNodePath())
info(strfmt("Found in shared project %1", treeNode.AOTname()));
find(innerTreeNode.AOTiterator());
innerTreeNode = _innerTreeNodeIterator.next();
}
}
;
projectListNode = SysTreeNode::getSharedProject();
treeNodeIterator = projectListNode.AOTiterator();
treeNode = treeNodeIterator.next();
while (treeNode)
{
projectNode = treeNode;
projectNode = projectNode.loadForInspection();
find(projectNode.AOTiterator());
treeNode = treeNodeIterator.next();
}
It's recursive, than it can find methods or inner nodes too
ProjectNode projectNode;
ProjectListNode projectListNode;
TreeNode treeNode;
TreeNodeIterator treeNodeIterator;
// Object we are searching for
TreeNode tnSearch = TreeNode::findNode(@'\Classes\MHT_DOCF_MasterTable');
void find(TreeNodeIterator _innerTreeNodeIterator)
{
TreeNode innerTreeNode;
;
innerTreeNode = _innerTreeNodeIterator.next();
while (innerTreeNode)
{
if (innerTreeNode.treeNodePath() == tnSearch.treeNodePath())
info(strfmt("Found in shared project %1", treeNode.AOTname()));
find(innerTreeNode.AOTiterator());
innerTreeNode = _innerTreeNodeIterator.next();
}
}
;
projectListNode = SysTreeNode::getSharedProject();
treeNodeIterator = projectListNode.AOTiterator();
treeNode = treeNodeIterator.next();
while (treeNode)
{
projectNode = treeNode;
projectNode = projectNode.loadForInspection();
find(projectNode.AOTiterator());
treeNode = treeNodeIterator.next();
}
TIP: Error executing code: The field with ID '0' does not exist in table 'SysExtensionSerializerExtensionMap'.
If you ever get "Error executing code: The field with ID '0' does not exist in table 'SysExtensionSerializerExtensionMap'." error in CIL, it may happen it is the table extension framework + the standard buf2buf function to blame.
Somehow, if you pass a Map instead of a table to buf2buf function, the following line fails:
_to.(fieldId) = _from.(fieldId);
However, if you replace this line with:
fieldName = fieldId2name(_from.TableId, fieldId);
_to.setFieldValue(fieldName, _from.getFieldValue(fieldName));
everything is fine both in X++ and in CIL.
P.S. I didn't dare to change the standard buf2buf method. Istead, I created another method and used it in the table extension framework logic, which failed because of the issue (\Data Dictionary\Maps\SysExtensionSerializerMap\Methods\copyExtensionTableData)
Reposted: https://community.dynamics.com/ax/b/dynamicsaxnotesonthecuffs/archive/2016/04/04/error-executing-code-the-field-with-id-39-0-39-does-not-exist-in-table-39-sysextensionserializerextensionmap-39
martedì 12 aprile 2016
AX7: How to Connect a Microsoft Dynamics AX 7 TFS Project
Very interesting article about source control and how to add and configure mapping a project on source control: https://stoneridgesoftware.com/how-to-connect-a-microsoft-dynamics-ax-7-tfs-project/
venerdì 8 aprile 2016
HOWTO: Delete Label Files from AX 2012
Here are the steps to delete Label Files from AX 2012:
- Create a new model. You could call it "LabelsBeGone".
- Open the AOT and move the Label File(s) you want to get rid of to the new model.
- Close AX and stop the AOS.
- Use AXUtil to delete the new model.
- Delete the label files from the server folder; C:\Program Files\Microsoft Dynamics AX\60\Server\...\bin\Application\Appl\Standard
- Start the AOS.
- Skip the upgrade wizard.
venerdì 11 marzo 2016
DIXF: Field 'Entity' must be filled in on DIXF (AX2012)
On AX2012 CU9 or later, if found it on CU10 for example, if you got this error, you can RUN this scripts. Is an update script of CU9, the entity name is a new field inserted on this version.
ReleaseUpdateDB63_DMF releaseUpdateDB63_DMF = new ReleaseUpdateDB63_DMF();
releaseUpdateDB63_DMF.updateEntityType();
Or, more simple, you can delete all entities, when you reopen the entities form all entities will be created. I know, you don't belive me, but it works.
ReleaseUpdateDB63_DMF releaseUpdateDB63_DMF = new ReleaseUpdateDB63_DMF();
releaseUpdateDB63_DMF.updateEntityType();
Or, more simple, you can delete all entities, when you reopen the entities form all entities will be created. I know, you don't belive me, but it works.
lunedì 7 marzo 2016
CODE: Check Security Key via X++ in AX2009
this script you can check if a user has permission for a particular security key by code.
SecurityKeySet securityKeys;
Boolean fullAccess;
;
securityKeys = new SecurityKeySet();
securityKeys.loadUserRights(curuserid());
fullAccess = securityKeys.access(securitykeynum("xxxxxxxxxxxxxxx")) == AccessType::Delete;
info(fullAccess ? "1" : "0");
SecurityKeySet securityKeys;
Boolean fullAccess;
;
securityKeys = new SecurityKeySet();
securityKeys.loadUserRights(curuserid());
fullAccess = securityKeys.access(securitykeynum("xxxxxxxxxxxxxxx")) == AccessType::Delete;
info(fullAccess ? "1" : "0");
lunedì 22 febbraio 2016
HOWTO: Set translation of label on fly by code
Use this script to set the value and comment of an existing label only if this label not exist in a particolar language. You can use it on fly by code whitout use of developer tool.
In my case i can set more than 200+ labels traduction in a couple of minutes.
void modifyLabel(LabelId _labelId, str _srcLanguage, str _trgLanguace, str _trgString, str _trgComment = '')
{
SysLabel srcLang = new SysLabel(_srcLanguage);
SysLabel trgLang = new SysLabel(_trgLanguace);
;
_labelId = "@" + _labelId;
if (!srcLang.exists(_labelId) || !srcLang.extractString(_labelId))
{
warning(strfmt("L'etichetta %1 non esiste nella lingua %2", _labelId, srcLang.languageId()));
return;
}
if (trgLang.exists(_labelId) && trgLang.extractString(_labelId))
{
warning(strfmt("L'etichetta %1 esiste già nella lingua %2 con il valore %3", _labelId, trgLang.languageId(), trgLang.extractString(_labelId)));
return;
}
cnt += trgLang.modify(_labelId, _trgString, _trgComment ? _trgComment : srcLang.extractComment(_labelId));
info(strFmt("Modificata etichetta %1 e impostato il testo %2 in lingua %2", _labelId, _trgString));
}
This script can semplify the same action but in more than one language, example in my case the traduction of en-us and en-gb is the same.
void modifyLabelMultipleLanguagese(LabelId _labelId, str _srcLanguage, container _trgLanguaces, str _trgString, str _trgComment = '')
{
int i;
str trgLanguace;
;
for(i=1;i<=conlen(_trgLanguaces);i++)
{
trgLanguace = conpeek(_trgLanguaces, i);
modifyLabel(_labelId, _srcLanguage, trgLanguace, _trgString, _trgComment);
}
}
In my case i can set more than 200+ labels traduction in a couple of minutes.
void modifyLabel(LabelId _labelId, str _srcLanguage, str _trgLanguace, str _trgString, str _trgComment = '')
{
SysLabel srcLang = new SysLabel(_srcLanguage);
SysLabel trgLang = new SysLabel(_trgLanguace);
;
_labelId = "@" + _labelId;
if (!srcLang.exists(_labelId) || !srcLang.extractString(_labelId))
{
warning(strfmt("L'etichetta %1 non esiste nella lingua %2", _labelId, srcLang.languageId()));
return;
}
if (trgLang.exists(_labelId) && trgLang.extractString(_labelId))
{
warning(strfmt("L'etichetta %1 esiste già nella lingua %2 con il valore %3", _labelId, trgLang.languageId(), trgLang.extractString(_labelId)));
return;
}
cnt += trgLang.modify(_labelId, _trgString, _trgComment ? _trgComment : srcLang.extractComment(_labelId));
info(strFmt("Modificata etichetta %1 e impostato il testo %2 in lingua %2", _labelId, _trgString));
}
This script can semplify the same action but in more than one language, example in my case the traduction of en-us and en-gb is the same.
void modifyLabelMultipleLanguagese(LabelId _labelId, str _srcLanguage, container _trgLanguaces, str _trgString, str _trgComment = '')
{
int i;
str trgLanguace;
;
for(i=1;i<=conlen(_trgLanguaces);i++)
{
trgLanguace = conpeek(_trgLanguaces, i);
modifyLabel(_labelId, _srcLanguage, trgLanguace, _trgString, _trgComment);
}
}
venerdì 12 febbraio 2016
HOWTO: Get error details from INFOLOG by code
You can use this code for getting che last error from INFO LOG.
I tested this code in all situations, using prefix and other conditions, and it works fine.
In the past i found some other scripts to do that, but i some situations does not work.
int i;
container infoLogCon;
container infoLogItem;
Exception infoLogItemExceptionType;
str infoLogItemMessage;
str strInfoLogMessage;
;
try
{
infologCon = infolog.copy(1, infolog.line());
for(i = infolog.line() + 1; i > 1; i--)
{
infoLogItem = conpeek(infologCon, i);
infoLogItemExceptionType = conpeek(infoLogItem, 1);
infoLogItemMessage = conpeek(infoLogItem, 2);
if (infoLogItemExceptionType == Exception::Error)
{
strInfoLogMessage = infoLogItemMessage;
strInfoLogMessage = strreplace(strInfoLogMessage, '\t', ' - ');
break;
}
}
if (!strInfoLogMessage)
strInfoLogMessage = "Errore non definito";
}
catch
{
strInfoLogMessage = "Errore sconosciuto";
}
strInfoLogMessage = strltrim(strrtrim(strInfoLogMessage));
I tested this code in all situations, using prefix and other conditions, and it works fine.
In the past i found some other scripts to do that, but i some situations does not work.
int i;
container infoLogCon;
container infoLogItem;
Exception infoLogItemExceptionType;
str infoLogItemMessage;
str strInfoLogMessage;
;
try
{
infologCon = infolog.copy(1, infolog.line());
for(i = infolog.line() + 1; i > 1; i--)
{
infoLogItem = conpeek(infologCon, i);
infoLogItemExceptionType = conpeek(infoLogItem, 1);
infoLogItemMessage = conpeek(infoLogItem, 2);
if (infoLogItemExceptionType == Exception::Error)
{
strInfoLogMessage = infoLogItemMessage;
strInfoLogMessage = strreplace(strInfoLogMessage, '\t', ' - ');
break;
}
}
if (!strInfoLogMessage)
strInfoLogMessage = "Errore non definito";
}
catch
{
strInfoLogMessage = "Errore sconosciuto";
}
strInfoLogMessage = strltrim(strrtrim(strInfoLogMessage));
lunedì 1 febbraio 2016
HOWTO: [AX2009] Update PURCHQTY of a PURCHLINE
Use this script for update the purchase quantity of a purchline
ttsbegin;
_pLine.PurchQty = q;
PurchLine::modifyPurchQty(_pLine, InventDim::find(_pLine.InventDimId), avoidBox);
InventMovement::bufferSetRemainQty(_pLine);
_pLine.update();
ttscommit;
ttsbegin;
_pLine.PurchQty = q;
PurchLine::modifyPurchQty(_pLine, InventDim::find(_pLine.InventDimId), avoidBox);
InventMovement::bufferSetRemainQty(_pLine);
_pLine.update();
ttscommit;
Iscriviti a:
Post (Atom)
AX 2012: The request was aborted: Could not create SSL/TLS secure channel
The error you're encountering, "The request was aborted: Could not create SSL/TLS secure channel," can occur due to various re...
-
Ussally you have to save a report to an output file for example store it or send it over mail. Here an example to save a report into Excel...
-
A simple way to export a data entity, using the powerful data management framework. You need a definition group, where the entity is mapped ...
-
NumberSeq numberSeq; InventTransferTable inventTransferTable; InventTransferLine inventTransferLine; InventDim inventDim; ; ttsbegin; ...