Category Archives: X++

How to Debug batch jobs and service operations in Dynamics AX 2012

All batch jobs and service operations now run in managed code (IL) and require different debugging steps.  Rather than setting breakpoints within X++, you need to set them within the IL code that corresponds to the X++ code and debug in Visual Studio.

  1. Open Visual Studio as ‘administrator’ and attach the debugger to the Ax32Serv.exe process.
  2.  Note that it may also be necessary to change the ‘Attach to’ selection to ‘Managed (v4.0) code’ and make sure “just my code” is unchecked in VS: tools->options->debugging->General
  3. Once done, open up the file you want to debug in Visual Studio. All of the X++ code is compiled into IL and can be found in the following directory after deployment: ..\Program Files\Microsoft Dynamics Ax\6.0\Server\AxaptaDev\Bin\XppIL\source\
  4. Set a breakpoint in the file you opened.
  5. Go to Ax and run the process in batch mode, or execute the service operation. This will end up hitting your breakpoint, provided you set it in the right place.

If you make some changes to X++ code and want those changes reflected in the generated IL code, you need to do generate incremental CIL which reflects in IL code.

Soure:

Muhammad Afsar Khan

Thanks and Happy DaXing…

Uploading a ​file to FTP server through X++ with detail explanation.

The File Transfer Protocol (FTP) is a standard network protocol used to transfer computer files between a client and server on a computer network but in our case, transfers file from AX client to file directory present on FTP server. You can easily find the code on the web on how to upload a file to FTP through X++ code but not in detail. In this post, I will try to explain detail about each line what it does during execution. So, let’s start.

  • The file name must not have spaces and colons in it otherwise it throws error. so, below in the example

filename = File09-12-2016_11.25.59pm.CSV;//Correct
filename = File09-12-2016_11.25.59 pm.CSV;//wrong, because there is space before pm
filename = File09-12-2016_11:25:59pm.CSV;//wrong, there is colon characters between hour, minutes and seconds.

  • Make sure you must have proper file path otherwise, it throws an error.

TempPath = System.IO.Path::GetTempPath(); //Automatically creates temporary directory
TempPath += filename;//append file to TemPath without using ‘/’ backslash.

  • If you don’t want to rename file name while file uploading on FTP server, then, use below code which works perfectly. FTP server gives it own name to file

ftpFilename = “ftp://ftpname.com”;
request = System.Net.WebRequest::Create(new System.Uri(ftpFileName));
ftpRequest = request; //Type casting object to ftpwebrequest object
credential = new System.Net.NetworkCredential(“Uname”, “Pword”);
ftpRequest.set_Credentials(credential);
//FTP file UploadFileWithUniqueName represents STOU
ftpRequest.set_Method(“STOU”);

  • If you want to rename file name while file uploading on FTP server, then use below code which works perfectly

fileNameString = YourDesiredName.extension;
//if you don’t use @”/”, will get error.
ftpFileName = “ftp://ftpname.com” + @”/” + fileNameString;
request = System.Net.WebRequest::Create(new System.Uri(ftpFileName));
ftpRequest = request; //Type casting object to ftpwebrequest object
credential = new System.Net.NetworkCredential(“Uname”, “Pword”);
ftpRequest.set_Credentials(credential);
//FTP file UploadFile represents STOR
ftpRequest.set_Method(“STOR”);

  • If you want to rename file name while file uploading on FTP server, then disable the proxy of FTP web request.

//UploadFile is not supported through an Http proxy, disable the proxy for this request.
ftpRequest.set_Proxy(null);

  • The entry point for access stream to FTP server, which generally throws error, if any one of above mentioned statements have errors, so, be careful while writing code in above mentioned statements.

requestStream = ftpRequest.GetRequestStream();

  • Don’t keep open temporary directory in file explorer from which FTP Server reads file, otherwise, it throws  timeout error.
  • Below is perfect code to upload file to FTP server, please have a glance.

Public void uploadFiletoFTPServer
{
System.Object request,response,credential;
System.IO.StreamReader streamReader;
System.IO.Stream requestStream;
System.Array files;
System.Net.FtpWebRequest ftpRequest;
System.Net.FtpWebResponse ftpResponse;
System.Byte[] bytes;
System.Text.Encoding getUTF8;
System.Exception sysException;
Str 120 TempPath,executedate;
str timeinstr,nextFile;
Commaio file;
container line;
Filename filepath,fileType,fileNameString,ftpFileName,fileName;

//removed spaces and colons because of FTP protocol voilation and throws error
timeinstr = time2str(timeNow(),DateSeparator::Dot,DateSeparator::Dot);
timeinstr = strRem(timeinstr,” “);

new InteropPermission(InteropKind::ClrInterop).assert();
//part of filename
executedate = date2Str(today(),213,DateDay::Digits2,
DateSeparator::Hyphen,
DateMonth::Digits2,
DateSeparator::Hyphen,
DateYear::Digits4)+”_”+timeinstr+”.CSV”;

TempPath = System.IO.Path::GetTempPath();
//complete filename with full path
TempPath += “mydesiredname”+executedate;
if (TempPath == ”)
{
error(“Please set up the location for export file.”);
return;
}

line = [“Microsoft”,”Dynamics”,”AX”,”7.0″,”ERP”];
file.writeExp(line);
file = null;

try
{
// reading filepath, filname and filetype in container
[filepath, filename, fileType] = fileNameSplit(TempPath);
ftpFileName = “ftp://ftpname.com” + @”/” + fileNameString;
//reading file in stream buffer
streamReader = new System.IO.StreamReader(TempPath);
//Encode characters and get buffer in array of bytes, then close stream buffer
getUTF8 = System.Text.Encoding::get_UTF8();
bytes = getUTF8.GetBytes(streamReader.ReadToEnd());
streamReader.Close();
// little workaround to get around the casting in .NET
request = System.Net.WebRequest::Create(new System.Uri(ftpFileName));
ftpRequest = request; //Type casting object to ftpwebrequest object
credential = new System.Net.NetworkCredential(“Uname”, “Pword”);
ftpRequest.set_Credentials(credential);
ftpRequest.set_ContentLength(bytes.get_Length());
//FTP file UploadFile represents STOR
ftpRequest.set_Method(“STOR”);
//UploadFile is not supported through an Http proxy, disable the proxy for this request.
ftpRequest.set_Proxy(null);
//entry point for ftp server
requestStream = ftpRequest.GetRequestStream();
requestStream.Write(bytes,0,bytes.get_Length());
requestStream.Close();
response = ftpRequest.GetResponse();
ftpResponse = response;//Type casting object to ftpwebresponse object
//Delete file from Temporary directory once it is uploaded to FTP server successfully.
if(ftpResponse != null)
{
WinAPI::deleteFile(nextFile);
}
}
catch(Exception::CLRError)
{
sysException = CLRInterop::getLastException();
info(sysException.get_Message());
}

CodeAccessPermission::revertAssert();

}

Hope you find my post as comprehensive and please feel free to comment below with your errors in code if you have any, I will try to figure and let you know.

Thanks and Happy DaXing..,

 

Display Email of a customer through x++

Hi Axaptians,

Today, I will going to post on displaying Email of a Customer through x++ code.

Without any delay, here is code….

//Email
select firstonly Location from dirPartyLocation
where dirPartyLocation.Party == custTable.Party
join logisticsElectronicAddress
where logisticsElectronicAddress.Location == dirPartyLocation.Location
&& logisticsElectronicAddress.IsPrimary == NoYes::No
&& logisticsElectronicAddress.Type == LogisticsElectronicAddressMethodType::Email;

return logisticsElectronicAddress.Locator;

Till then, Happy DaXing..,

How to find model of specific object through X++

Hi Experts,

Hope you are doing well.
I would just like to update you with new stuff which I have learnt recently. So, I will write a piece of code which returns model of specific object, in my case, I will use Class as object but you can use others objects as well. So, here you go.

static void jobGetObjectModel(Args _args)
{
SysDictClass sysDictClass = new SysDictClass(classNum(YourClass));
SysModel sysModel;
SysModelManifest sysModelManifest;

select Model, Name, Publisher, DisplayName from sysModelManifest
where sysModelManifest.Model == sysDictClass.treeNode().AOTGetModel()
join firstonly Layer from sysModel where sysModel.RecId == sysModelManifest.Model
&& sysModel.Layer == UtilEntryLevel::sys; // Change layer here

if (sysModelManifest)
info(strFmt(“Model: %1”, sysModelManifest.Name));
else
info(“Object is not apart of model in given layer”);

}

Query will fetch Model, its name, Publisher and DisplayName.

Note: Select layer in which you are looking for…

Thanks and Happy DaXing…

 

Importing data from an XML file

This is a part of previous post on reading and writing xml file from/to AX.

In Dynamics AX, XML file importing is done in a very similar way as exporting. In this recipe, we will continue using the System.XML wrapper application classes. We will create a new class which reads XML files and displays the content on screen. As a source file, we will use the previously created sales.xml file.

How to do it…

Carry out the following steps in order to complete this recipe:
1. Open the AOT, and create a new class named ReadorWriteXml with the following code.
Use the document created in the previous post:
class ReadorWriteXml
{
}

public void readXMLFile()
{
XmlDocument doc;
XmlNodeList data;
XmlElement nodeTable;
XmlElement nodeId;
XmlElement nodeName;
XmlElement nodeCustAccount;
#define.filename(@’C:\Temp\sales.xml’)
doc = XmlDocument::newFile(#filename);
data = doc.selectNodes(‘//’+tableStr(SalesTable));
nodeTable = data.nextNode();
while (nodeTable)
{
nodeId = nodeTable.selectSingleNode(fieldStr(SalesTable, SalesId));
nodeName = nodeTable.selectSingleNode(fieldStr(SalesTable, SalesName));
nodeCustAccount = nodeTable.selectSingleNode(fieldStr(SalesTable, CustAccount));
info(strFmt(“%1 – %2 – %3”,nodeId.text(),nodeName.text(),nodeCustAccount.text()));
nodeTable = data.nextNode();
}
}
public static void main(Args args)
{
ReadorWriteXml file = new ReadorWriteXml();
file.readXMLFile();
}

2. Run the class. The Infolog should display the contents of the sales.xml file on the screen:

1

How it works…

In this recipe, we first create a new XmlDocument. We create it from the file and hence we have to use its newFile() method. Then we get all the document nodes of the table as XmlNodeList. We also get its first element by calling the nextNode() method.

Next, we loop through all the list elements and do the following:
1. Get salesId node as an XmlElement.
2. Get salesname node as an XmlElement.
3. Get cust account as an XmlElement.
4. Display the text of nodes in the Infolog.
5. Get the next list element.
In this way, we retrieve the data from the XML file. A similar approach could be used to read any other XML file.

If you need xpo file of this, please specify your mail address in comment.

Hope you understood….
Till then, Happy DaXing…

Exporting data to an xml file

Hi Folks,
Today, I would like to emphasis on exporting data to an xml file in AX 2012.

Extensible Markup Language (XML) defines a set of rules for encoding documents electronically. It allows the creation of all kinds of structured documents to exchange between systems. In Dynamics AX, XML files are widely used across the application.

For example, user profiles can be exported as XML files. Business data, such as financial statements can also be exported as extensible Business Reporting Language (XBRL) files, which are based on XML.

Probably, the main thing that is associated with XML in Dynamics AX is the Application Integration Framework. It is an infrastructure that allows exposing business logic or exchanging data with other external systems. The communication is done by using XML formatted documents. By using the existing XML framework application classes prefixed with Axd, you can export or import data from or to the system in an XML format to be used for communicating with external systems. It is also possible to create new Axd classes using the AIF Document Service Wizard from the Tools menu to support the export and import of newly created tables.

Dynamics AX also contains a set of application classes prefixed with Xml, such as XmlDocument and XmlNodeBasically, those classes are wrappers around the System.XML namespace in the .NET framework.

In this recipe, we will create a new simple XML document by using the latter classes, in order to show the basics of XML. We will create the file with the data from the SalesTable table and will save it as an XML file.

Following are the steps…

Carry out the following steps in order to complete this recipe:
1. Open the AOT and create a new class named ReadorWriteXml with the following code:

class ReadorWriteXml
{
}

public void writeXMLFile()
{
XmlDocument doc;
XmlElement nodeXml;
XmlElement nodeTable;
XmlElement nodeId;
XmlElement nodeName;
XmlElement nodeCustAccount;
SalesTable salesTable;

#define.filename(@’C:\Temp\sales.xml’)
doc = XmlDocument::newBlank();
nodeXml = doc.createElement(‘xml’);
doc.appendChild(nodeXml);

while select RecId, SalesId,SalesName,CustAccount from SalesTable where salesTable.CustGroup == ‘AGENCY’
{
nodeTable = doc.createElement(tableStr(SalesTable));
nodeTable.setAttribute(fieldStr(SalesTable, RecId),int642str(salesTable.RecId));
nodeXml.appendChild(nodeTable);

//append salesId
nodeId = doc.createElement(fieldStr(SalesTable,SalesId));
nodeId.appendChild(doc.createTextNode(salesTable.SalesId));
nodeTable.appendChild(nodeId);

//append salesname
doc.createElement(fieldStr(salesTable,SalesName));
nodeName.appendChild(doc.createTextNode(salesTable.SalesName));
nodeTable.appendChild(nodeName);

//append custaccount
nodeCustAccount = doc.createElement(fieldStr(salesTable,CustAccount));
nodeCustAccount.appendChild(doc.createTextNode(salesTable.CustAccount));
nodeTable.appendChild(nodeCustAccount);

}
doc.save(#filename);
info(strFmt(‘file is created.’, #filename));
}

public static void main(Args args)
{
ReadorWriteXml file = new ReadorWriteXml();
file.writeXMLFile();
}

2. Run the class. The XML file sales.xml should be created in the specified folder.Open it using any XML editor or viewer, such as Microsoft Internet Explorer, and review the created XML structure:

Untitled

How it works…

We start the recipe by creating a new XmlDocument using its newBlank() method,which represents an XML structure. Then we create its root node named xml using the createElement() method, and add the node to the document by calling the document’s appendChild() method.

Next, we go through the SalesTable and do the following for each record:
1. Create a new XmlElement node, which is named exactly as the table name, and add
this node to the root node.
2. Create a node representing the salesId field and its child node representing its value. The salesId  node is created using createElement(), and its value is created using createTextNode(). The createTextNode() method basically adds a value as text with no XML tags.
3. Add salesId node to the table node.
4. Create a node representing the sales name field and its child node representing
its value.
5. Add salesname node to the table node.
6. Add Cust Account node to the table node.
Finally, we save the created XML document as a file.
In this way, we can create documents having virtually any structure.

My next post will highlight Importing data from xml.
If you need xpo file of this, please specify your mail address in comment.

Hope you understood….
Till then, Happy DaXing…

Creating a custom service in ax 2012

Hi Experts,

I just thought of updating AIF stuff. Let’s start on digging on creating custom service. Before that, let’s elaborate custom service.

A custom service in Dynamics AX allows any X++ logic to be exposed as a service. Custom services are normal X++ classes decorated with attributes, which allow any existing methods to be exposed as service operations without writing any additional code.

In this, we will create a new custom service with a single, simple operation. The operation will accept salesId of sales order and return sales name.

Following are the steps…

1. In the AOT, create a new class named CustomServiceDemo with the following code:

class CustomServiceDemo
{

}
[SysEntryPointAttribute]
Public SalesName getSalesName(SalesId _salesId)
{
return SalesTable::find(_salesId).SalesName;
}

9

2. Set the class properties as follows:

1

3. In the AOT, create a new service with the following properties:

2

4. Expand the newly created service and choose the Add Operation option from the Operations node’s right-click context menu.

5. On the Add service operations form, select the getSalesName line by marking the Add checkbox and clicking on OK:

3

6. The service in the AOT should look like the following screenshot:

4

7. In the AOT, create a new service group named CustomServiceSalesName.

8. In the service group, create a new service node reference with the following properties:

 5

9. Deploy the service group by selecting the Deploy Service Group option from its right-click context menu. The Infolog should display a number of messages about successful deployment.

10. Open System administration | Setup | Services and Application Integration Framework | Inbound ports to check the newly deployed service:

6

How it works…

In Dynamics AX, any class can be a custom service. Here, we create a new one with a single method that accepts salesId  and returns the sales name. To enable the method as a service operation, we specify the SysEntryPointAttribute attribute at the top of the method, which will ensure that the method is available in the service operation list when creating service nodes. We also set the class to run on the server.

Next, we create a new service node and add the newly created operation to it. In order to deploy it, we also have to create a new service group that includes the created service. Once deployed, a new record is created in the Inbound ports form.

If everything is successful the service will be ready to be consumed, which is explained in the next step.

Consuming a custom service

Custom services are consumed in a way quite similar to any other Dynamics AX service.

The difference is that each custom service can have a totally different set of operations, where the system or document services always expose the same list operations.

In this recipe, we will create a .NET console application to demonstrate how to consume a custom service. We will use the service created in the Creating a custom service recipe, which returns a sales name of the provided salesid.

How to do it…

Carry out the following steps in order to complete this recipe:
1. In Visual Studio, create a new Visual C# Console Application project named
ConsumeServiceSalesName.
2. Add a new service reference named CustomServiceSalesName to the project.
3. Copy the address from the WSDL URI field, from the Creating a custom service recipe, into the Address field:
7

4. Add the following code to the top section of the Program.cs file:

using customServiceSalesName.CustomServiceSalesName;

5. Add the following code to the Main() method:

CustomServiceSalesNameClient serviceClient = new CustomServiceSalesNameClient();
CallContext context = new CallContext{Company = “UK13”};
string SalesName = serviceClient.getSalesName(context, “SO000395276-UK13”);
Console.WriteLine(SalesName);
Console.ReadLine();

6. Run the program to display the results as shown in the following screenshot:

8

How it works…

We start this recipe by creating a new Visual C# Console Application project and adding a new service reference pointing to the address from the previous recipe. Then, we allow the use of the type in a namespace.

The code in the Main() method is very similar to the other recipes. Here, we create a new service client object and call its getSalesName() operation to find the sales name.

Hope you understood my stuff. Happy DaXing…

Cache lookup property in table Dynamics AX 2012

Table level cache has been performance improving feature. we can set both client and server side (AOS) level caches.

When cache at client and server side enabled. Then user query, first search will be done on client side cache, result not found then Ax tries to locate record at server side. In the case of record not found at server side, they will be fetch from table.

Client side cache is exclusive for every  client, while Server side cache can be access by any client.

we can set two types of Cache, Single record or set based Cache

In the case of single record based cache, we can set following properties in cache lookup

  • NotInTTS,
  • Found
  • FoundAndEmpty

For Set-based cache, we have to set the cache lookup to Entire table.

Capture

 Go through these following links for caching.

Set-based Caching

Single-record caching

CacheLookup is a method where some records will be loaded into memory at start-up of AX or when loading the table the first time.

The setting Entire table will do the caching at start-up of AX. When it is a parameter table with one record or a group (setup) with a few records and this content is not supposed to change (once or twice a year) you can use the Entire table cache.

When the number of records are enormous it will cause performance issues when starting AX. When you are changing the contents a lot (e.g. multiple times a day for records in that table) it could cause other sessions to keep working with the old cached data.

Also go through this below for more information.

Selecting cached tables

Thanks & Happy DaXing…..

Top 10 issues discovered from Dynamics AX Code Review

Hi folks,

Hope you are doing well. I have great article to spread across Dynamics AX professionals. When I was searching for contents on Table group and Cache lookup properties at Table level, I came across one article published by Bertrand Caillet who has highlighted Top 10 issues discovered from Dynamics AX.

I would suggest to have deep breathe and take some time to examine this article.

Top 10 issues discovered from Dynamics AX Code Review

Thanks and Happy DaXing……….

 

How to export table data in excel file in AX 2012

Hi Experts,

We have inbuilt classes to import/export data into excel file. We have robust features available where we can design worksheet, format text  & secure document beside just importing/exporting.

Lets start with today’s stuff on exporting data outside of AX into excel file. The following code writes table data into xls file.

SysExcelApplication     application;
SysExcelWorkbooks       workbooks;
SysExcelWorkbook        workbook;
SysExcelWorksheets      worksheets;
SysExcelWorksheet       worksheet;
SysExcelCells           cells;
SysExcelCell            cell;
SysExcelFont            font;
int                     row;
YourTable yourTable;

// intializing classes to export excel
application = SysExcelApplication::construct();
workbooks = application.workbooks();
workbook = workbooks.add();
worksheets = workbook.worksheets();
worksheet = worksheets.itemFromNum(1);
cells = worksheet.cells();
cells.range(‘A:A’).numberFormat(‘@’);

// Setting Header values
cell = cells.item(1, 1);
cell.value(“HeaderValue1”);
font = cell.font();
font.bold(true);

cell = cells.item(1, 2);
cell.value(“HeaderValue2”);
font = cell.font();
font.bold(true);
row = 1;

// inserting data row wise
while select yourTable
{
row++;
cell = cells.item(row, 1);
cell.value(yourTable.field1);
cell = cells.item(row, 2);
cell.value(yourTable.field2);
}

application.visible(true);

There are lot of things to discuss on exporting excel. I will share some link so that you can through these fruitful links.

The following link will help if you get error as “The number of arguments provided is different from the number of arguments accepted by the method.”

Coding Champ (Mohammed Zahid)

The following link will help if you get error as “the method has been called with an invalid number of parameters.”

Mohammed Afsar khan

Thanks & Happy Daxing……..