Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Answered

Why text files cannot be written when executing a process that runs on batch?

(0) ShareShare
ReportReport
Posted on by 25

Hi, everybody.

Found myself once again with a tricky error.

I programmed a functionality, that runs on both client and server, that attaches both the XML & PDF files for the CFDI 3.3 Electronic Invoice to the sales order and the invoice.

If I execute the process on Client, it displays an infolog message that both files were saved successfully. Then, in AX I open the sales order and on the menu I click the Attachments button to confirm the files are attached to the order and displaying in the document handling form; so far my process runs smoothly and without errors.

pastedimage1649347782155v2.png

However, the problem comes when that same process runs on batch. I check into the Logs of my process in the Batch Job History form, and it displays two messages:

  • One is an infolog that states the PDF was sucessfully saved.
  • The other is a warning that the directory does not exists.

pastedimage1649347183329v1.png

If I go back to the sales order and open the document handling form, I confirm that the PDF file has been attached to the order but not the XML file, hence, I assume the "directory does not exists" error is linked to the problem that the XML files won't be created if the process runs on batch.

pastedimage1649348164526v3.png

When I was first programming this process in earlier stages I used the EInvoiceReadWriteFile_MX class to generate the XML files, but after I ran the first developer tests on batch from the results in the batch history log I got errors. Then, I analyze the class' properties and understood it runs only on Client, that's why it cannot run in a batch process.

What I chose to circumvent that hurdle was duplicating the class and made the needed tweaks so that the duplicate class runs on Server.

After that, I implemented the calls of the duplicated class in code within the overall process flow.

This is the method's code for my process to call the duplicate class when executing in batch:

protected void generateXMLDocExport(FilePath _filePath, EInvoiceJour_MX _eInvoiceJour_MX, boolean _isInBatch = false)
{
#define.FilePrefix('XML_')

CustInvoiceJour custInvoiceJour = CustInvoiceJour::findRecId(_eInvoiceJour_MX.RefRecId);
EInvoiceReadWriteFile_MX fileWriter;
Copy_EInvoiceReadWriteFile_MX copy_fileWriter;
Filename invoiceFileName;

if (!_isInBatch)
{
fileWriter = EInvoiceReadWriteFile_MX::newWriteFile(_filePath);
}
else
{
//new FileIOPermission(_filePath, #io_write).assert();
copy_fileWriter = Copy_EInvoiceReadWriteFile_MX::newWriteFile(_filePath);
//CodeAccessPermission::revertAssert();
}
invoiceFileName = #FilePrefix + custInvoiceJour.InvoiceId;

try
{
if (!_isInBatch)
{
fileWriter.write(_eInvoiceJour_MX.XMLDoc);
}
else
{
//new FileIOPermission(_filePath, #io_write).assert();
copy_fileWriter.write(_eInvoiceJour_MX.XMLDoc);
//CodeAccessPermission::revertAssert();
}
info(strFmt("@SYS341181", invoiceFileName));
}
catch
{
System.IO.File::Delete(_filePath);
error(strFmt("@SYS341182", invoiceFileName));
}

At first I thought the error could be linked to missing permissions, but since the PDF files are still created when the whole process executes in batch the issue lies somewhere else; I mean both XML and PDF files are saved in the same folder.

What else could be causing the issue?

  • GuidoMTY Profile Picture
    25 on at
    RE: Why text files cannot be written when executing a process that runs on batch?

    Thanks for the feedback, Martin.

    Indeed, I checked the WinAPIServer::pathExists(...) method and makes use of System.IO classes, or more specifically the System.IO.Directory class for the aforementioned function.

  • Verified answer
    Martin Dráb Profile Picture
    231,947 Most Valuable Professional on at
    RE: Why text files cannot be written when executing a process that runs on batch?

    I don't have AX 2012 in front of me, but if I remember it correctly, your statetement "the WinApiServer class works only for those processes that run on server like" isn't true. For example, I think that WinAPIServer::pathExists() uses System.IO classes, which work both on client and server, and both in X++ (via Interop) and CIL.

  • GuidoMTY Profile Picture
    25 on at
    RE: Why text files cannot be written when executing a process that runs on batch?

    Thank you very much, Martin.

    You gave me hints as to which objects I should look upon.

    First, I debugged the batch process with Visual Studio and identified that the error was triggered when making call to the newWriteFile method of my duplicate class.

    Next, I looked up in my duplicate class and further identified that within the new method of the class a call is made to a validateWrite method; that is where I located the trigger for the error. The problem was that I made a logical error after duplicating the class and making adjustments to the code. The line commented, in the image below, makes a call to the System.IO.File::Exists(...) method, however, I mistakenly assumed that method can search for both the files & the directory path. Hence, when the function received only the file path, it returned false due that could not find a file with a name same as in the file path.

    pastedimage1649364403360v2.png

    That's when I had an epiphany after reading your comment on the EInvoiceReadWriteFile_MX class and compared both methods between the original and duplicate classes.

    As you can see in the next image the validateWrite function in the original class makes a call to the WinApi::pathExists(...) method, which specifically searches for the file path or directory. Furthermore, from my own understanding and experience the WinApi class is used for functionality that runs on Client, while the WinApiServer class works only for those processes that run on server like, for example, batch processes.

    pastedimage1649364663057v3.png

    The solution I figured out with common sense was replacing the call to System.IO.File::Exists(...) with the WinAPIServer::pathExists(...) method in my duplicate class. Then, I programmed the process to run again in batch and, next, I checked the batch job history logs and confirmed it executed without errors this time.

    pastedimage1649366329749v4.png

    Finally, I checked my sales orders and, indeed, both files were attached to the orders once viewing the document handling form.

    pastedimage1649367891573v5.png

    Again, thanks Martin.

  • Verified answer
    Martin Dráb Profile Picture
    231,947 Most Valuable Professional on at
    RE: Why text files cannot be written when executing a process that runs on batch?

    There probably was the reason why the developer of EInvoiceReadWriteFile_MX explicitly stated that it can only run on client. You can  debug your code to see where it fails. You may be interested in Debugging in Microsoft Dynamics AX 2012 > Batch Jobs.

    By the way, let me add line indentation to your code, to make it easier read. Next time, please use Insert > Code (in the rich formatting view).

    protected void generateXMLDocExport(FilePath _filePath, EInvoiceJour_MX _eInvoiceJour_MX, boolean _isInBatch = false)
    {
    	#define.FilePrefix('XML_')
    
    	CustInvoiceJour custInvoiceJour = CustInvoiceJour::findRecId(_eInvoiceJour_MX.RefRecId);
    	EInvoiceReadWriteFile_MX fileWriter;
    	Copy_EInvoiceReadWriteFile_MX copy_fileWriter;
    	
    	Filename invoiceFileName;
    
    	if (!_isInBatch)
    	{
    		fileWriter = EInvoiceReadWriteFile_MX::newWriteFile(_filePath);
    	}
    	else
    	{
    		//new FileIOPermission(_filePath, #io_write).assert();
    		copy_fileWriter = Copy_EInvoiceReadWriteFile_MX::newWriteFile(_filePath);
    		//CodeAccessPermission::revertAssert();
    	}
    	invoiceFileName = #FilePrefix   custInvoiceJour.InvoiceId;
    
    	try
    	{
    		if (!_isInBatch)
    		{
    			fileWriter.write(_eInvoiceJour_MX.XMLDoc);
    		}
    		else
    		{
    			//new FileIOPermission(_filePath, #io_write).assert();
    			copy_fileWriter.write(_eInvoiceJour_MX.XMLDoc);
    			//CodeAccessPermission::revertAssert();
    		}
    		info(strFmt("@SYS341181", invoiceFileName));
    	}
    	catch
    	{
    		System.IO.File::Delete(_filePath);
    		error(strFmt("@SYS341182", invoiceFileName));
    	}
    }

    Unfortunately, the important code is likely inside Copy_EInvoiceReadWriteFile_MX and not here.

    By the way, you test very different cases and therefore you can' be sure what failed. For instance:

    1. Your code may execute on different computers (the client and the batch AOS may be installed on different machines).
    2. Client code execute in X , while batches runs as CIL.
    3. The process runs under different permissions.

    You may want to run more granular tests, such as running code on server, but in X and without a batch.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Daivat Vartak – Community Spotlight

We are honored to recognize Daivat Vartak as our March 2025 Community…

Announcing Our 2025 Season 1 Super Users!

A new season of Super Users has arrived, and we are so grateful for the daily…

Kudos to the February Top 10 Community Stars!

Thanks for all your good work in the Community!

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 293,274 Super User 2025 Season 1

#2
Martin Dráb Profile Picture

Martin Dráb 231,947 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,156 Moderator

Leaderboard

Product updates

Dynamics 365 release plans