web
You’re offline. This is a read only version of the page.
close
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

System.IO throwing errors when running as batch job

(0) ShareShare
ReportReport
Posted on by

Hi Experts.

I get error while deleting the file using system.io delete during batch job. however get no error & fiile get successfuly deleted when running same code as non btach.

Please suggest fix for following

1. How do i get to delete the file in batch & non batch mode

2. How do i get to move the file in batch & non batch mode.  

3. Currently it does not capture the details of why the batch job failed, what can i do to improvise my catch block so that it capture the details of generic failures i.e. exception from info cllass's add exception .

Here is the complete code. Thanks in advance.

public void run()
{

    str                          fileNameString,fileNamePath;
    MyCustom  msg;
    System.IO.DirectoryInfo     directory,processedDirectory;
    System.IO.FileInfo[]        files;
    System.IO.FileInfo          file;
    //Set                 permissionSet;
    InteropPermission           permission;
    counter                     filesCount;
    FilePath                    processedFilePath,processedFileCompletePath;
    Filename                    filename,filepath,fileType;
    Filename                    tmpFilePath;
    Filename                    tmpFileNameShort;
    Filename                    tmpFileExt;

    counter                     loop;
    str                         fileNameOnly,fileNameTemp;
    filetype                    type;
    boolean                     skipZeroTrans;
    boolean wrongFileFormat = false;

    #FILE

    try
    {

        permission  = new InteropPermission(InteropKind::ClrInterop);
        permission.assert();

        select   myCustomTable;
      
        skipZeroTrans = myCustomTable.skipZeroTransVal;

        directory   = new System.IO.DirectoryInfo(@myCustomTable.FilePath);
        filepath = @myCustomTable.myCustomTablelFilePath;
        
        processedDirectory = new System.IO.DirectoryInfo(@myCustomTable.ProcessedFilePath);
        processedFilePath = @myCustomTable.ProcessedFilePath;

        files       = directory.GetFiles("*.csv*");
        filesCount  = files.get_Length();

        for (loop = 0; loop < filesCount; loop  )
        {
            file = files.GetValue(loop);
            fileNameTemp = file.get_FullName();

            filename = fileNameTemp;
            info(strFmt("filename: %1",filename));


             if (strLen(fileNameTemp) > 0)
                {
                    [tmpFilePath, tmpFileNameShort, tmpFileExt] = fileNameSplit(fileNameTemp);
                    fileNameString= tmpFileNameShort   tmpFileExt;
                    info(strFmt('Import filename=%1', fileNameTemp));

                    if(tmpFilePath && tmpFileNameShort && tmpFileExt == #csv)
                    {
                   
                        msg = this.processFile(fileNameTemp,skipZeroTrans);
                 
                    }
                    else
                    {
                        if (strLen(tmpFilePath) == 0)
                        {
                            error("Filepath not specified");
                        }

                        wrongFileFormat = true;
                        Error (strFmt("%1 unsupported fileType", tmpFileExt));
                    }

                    if ( strScan(msg,"Error",0,strLen(msg)))
                    {
                        throw error("Error encountered while processing file");
                    }

                    this.myWriteMessage(tmpFilePath,tmpFileNameShort,msg);
                    info(msg);
                    System.IO.File::Delete(filename);                                                                             //TODO 1   RUNS FINE IN NON BATCH MODE BUT ERRORS IN BATCH MODE  ONCE FIXED USE either DELETE or MOVE 


                    // CHECK FILE MOVE CODE
                  /* // processedFilePath = processedFilePath   "\n\\"  tmpFileNameShort;
                    //permissionSet =  new Set(Types::Class);
                    //permissionSet.add(new FileIOPermission(filename, #io_write));
                    //permissionSet.add(new FileIOPermission(processedFilePath, #io_write));
                    //permissionSet.add(new InteropPermission(InteropKind::ClrInterop));
                    //CodeAccessPermission::assertMultiple(permissionSet);
                   // CodeAccessPermission::revertAssert();
                    //processedFileCompletePath = processedFilePath "\n\\" tmpFileNameShort  tmpFileExt;
                    //System.IO.File::Move(filename,processedFileCompletePath);
                    //System.IO.File::Move(fileName, newFileName); */                                                             //TODO 2 ERRORS IN BOTH BATCH & NON BATCH MODE
                }


        }// for ends
    } // Try ends
    catch
    {

        if (wrongFileFormat == true)
        {
            this.myWriteMessage(tmpFilePath,tmpFileNameShort,msg);
            throw Error (strFmt("%1 Unsupported file type", fileType));
        }


       else if (Exception::Error &&  Exception::CLRError)
        {
           
            this.myWriteMessage(tmpFilePath,tmpFileNameShort,msg);
            throw Error (msg   "Exception" );                                                                        //TODO 3  Explore how can you replace "Exception" with exception from info add exception so as to capture the details of geneic failures.

        }


        else if (Exception::DuplicateKeyException && Exception::DuplicateKeyExceptionNotRecovered)
        {
    
                                     
             this.myWriteMessage(tmpFilePath,tmpFileNameShort,msg);
             throw error(strFmt("Error encountered while processng the file. \n Read log at %1 path for details",tmpFilePath));

        }

    }
}//Run method ends

Thanks

Mav

I have the same question (0)
  • Martin Dráb Profile Picture
    237,959 Most Valuable Professional on at

    What's the type of exception and the message? You can use the debugger to find this information (refer to Debugging in Microsoft Dynamics AX 2012 > Batch jobs if you don't know how).

    Also, don't forget to generate CIL after compilation of X++.

  • Mav Profile Picture
    on at

    Yep did the incremental CIL & can see the updated class in VS

    When trying to debug in VS , i see batch job in never ending executing status in AX, when i re run it ,this time disabling debugging point in VS , the code executes completely & I get my custom error message , there is something wrong in my catch block which is preventing the catch block to capture actual exception & message.

    Any suggestion.

    Thanks

    Mav

  • Verified answer
    Martin Dráb Profile Picture
    237,959 Most Valuable Professional on at

    I would focus on the code in question; the status in AX doesn't sound relevant to me. If you have problem with debugging, try recompiling code and generating full CIL. And review your debugging setup in Visual Studio (e.g. "Enable just my code").

    Regarding your catch clause, I have no idea what you hope to achieve by conditions like if (Exception::Error &&  Exception::CLRError). It makes no sense to me.

    To catch CLR exceptions, use something like this:

    catch (Exception::CLRError)
    {
    	throw error(AifUtil::getClrErrorMessage());
    }
    catch
    {
        ...
    }

    getClrErrorMessage() gives you just a message of the inner exception. If you want more details, use CLRInterop::getLastException().ToString().

    I don't know what code you have in myWriteMessage(), but I suggest removing it for now, because it may be throwing an exception when you're trying to handle other exceptions.

  • Mav Profile Picture
    on at

    Thanks Martin, will look in into your suggestion.

    BTW Captured this in my event viewer

    "Object Server 01:  

      Microsoft.Dynamics.Ax.Xpp.BreakException: Exception of type 'Microsoft.Dynamics.Ax.Xpp.BreakException' was thrown. at Microsoft.Dynamics.Ax.MSIL.Interop.throwException(Int32 ExceptionValue) at Microsoft.Dynamics.Ax.MSIL.cqlClassIL.create(Int32 classId, Object[] parameters, Type[] types, Object[] varargs, Type[] varargsTypes, Object ILObject) at Microsoft.Dynamics.Ax.Xpp.XppObjectBase.createKernelClass(Object[] parameters, Type[] paramTypes, Object[] varargs) at Dynamics.Ax.Application.SkipAOSValidationPermission.new() at Dynamics.Ax.Application.SkipAOSValidationPermission..ctor() at Dynamics.Ax.Application.BatchRun.serverFinishTask(Int64 batchId, Boolean isErrorCaught, Exception exception, BatchRunType batchRunType, Int32 infoCnt, Boolean , Boolean ) in BatchRun.serverFinishTask.xpp:line 10 at Dynamics.Ax.Application.BatchRun.@serverFinishTask(Int64 batchId, Boolean isErrorCaught, Exception exception, BatchRunType batchRunType, Boolean ) at Dynamics.Ax.Application.BatchRun.serverFinishTask(Int64 batchId, Boolean isErrorCaught, Exception exception) at BatchRun::serverFinishTask(Object[] ) at Microsoft.Dynamics.Ax.Xpp.ReflectionCallHelper.MakeStaticCall(Type type, String MethodName, Object[] parameters) at BatchIL.taskThreadEntry(Object threadArg)

    "

    Thanks

    Mav

  • Mav Profile Picture
    on at

    Hi Martin after using CLRInterop::getLastException().ToString(); i got this in error message

    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.IOException: The process cannot access the file 'Filepath\myCSVFILE1.csv' because it is being used by another process.

      at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

      at System.IO.File.InternalDelete(String path, Boolean checkHost)

      at Dynamics.Ax.Application.myClass.Run() in myClass.run.xpp:line 96  (LINE 96 is  System.IO.File::Delete(filename))

      --- End of inner exception stack trace ---

    Thanks

    Mav

  • Mav Profile Picture
    on at

    I think this may go away by using Text IO .finalize(). Will try & use .finalize() to see if it helps & update this thread.

  • Suggested answer
    Mav Profile Picture
    on at

    I am able to delete the fils via system IO using myTextIO.finalize()

    However when trying to move the file from 1 folder to other i keep getting the below error message even when there is no file in the destination folder

    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.IOException: Cannot create a file when that file already exists.

      at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

      at System.IO.File.InternalMove(String sourceFileName, String destFileName, Boolean checkHost)

      at Dynamics.Ax.Application.myclass.run.() in myclass.run.xpp:line 105

      --- End of inner exception stack trace --

    Change made to code shared earlier for moving file to different folder.

    //System.IO.File::Delete(filename);  commented delete action
    
    
                  
    processedFileCompletePath = processedFilePath tmpFileNameShort  tmpFileExt;  // Uncommented these 2 lines for moving the file
    System.IO.File::Move(filename,processedFileCompletePath);
    
    
                   

  • Verified answer
    Community Member Profile Picture
    on at

    Here is an demo to catch the error information when using .net:

       Boolean                  res = true;

       System.Text.UTF8Encoding encode;

       System.IO.FileStream     fs;

       System.Byte []           info;

       System.String            fileName;

       System.IO.StreamWriter   sw;

       str                      mystr;

       System.Exception         ex;

       ;

       try

       {

           new InteropPermission(InteropKind::ClrInterop).assert();

           encode = new System.Text.UTF8Encoding(true);

           info  =  encode.GetBytes("Create test content");

           mystr = System.Guid::NewGuid().ToString("N");

           mystr = directory + @"\"+mystr+@".txt";

           fileName = mystr;

           fs = System.IO.File::Create(fileName);

           fs.Write(info, 0, info.get_Length());

           fs.Close();

           fs.Dispose();

           sw = System.IO.File::AppendText(fileName);

           sw.Write("Modify test content");

           sw.Close();

           sw.Dispose();

           System.IO.File::Delete(fileName);

           CodeAccessPermission::revertAssert();

       }

       catch(Exception::CLRError)

       {

           ex = ClrInterop::getLastException();

           if (ex != null)

           {

               ex = ex.get_InnerException();

               if (ex != null)

               {

                   error(ex.ToString());

               }

           }

           CodeAccessPermission::revertAssert();

           res = false;

       }

  • Mav Profile Picture
    on at

    I think i found the issue which is that my processedFilePath does not contain "\" this in end which leads my

    processedFileCompletePath to something like "C:\myFiles\ Processed file myFile1.xls"

    where as objective is to get values like below C:\myFiles\Processed file \ myFile1.xls (Which is correct path)

    For processedFilePath  i have tried using both below approach but none of below approach helped me in getting "\" after the filepath.

     processedDirectory = new System.IO.DirectoryInfo(@myCustomTable.myProcessedFilePath);

     processedFilePath = @myCustomTable.myProcessedFilePath;

    & if i forcefully add "\" by using code

    processedFileCompletePath = processedFilePath+"\n\\"+tmpFileNameShort+ tmpFileExt;

    I get illegal value in path error.

    Can you please suggest a fix.

  • Martin Dráb Profile Picture
    237,959 Most Valuable Professional on at

    Mav, \ is a special character - notice that you also use it for \n. You need \\ to represent \, or use a verbatim string (e.g. str path = @'c:\temp\file.txt').

    Leo.Wang, please use Insert > Insert Code (in the rich-formatting view) to paste source code. This is the result:

    Boolean                  res = true;
    System.Text.UTF8Encoding encode;
    System.IO.FileStream     fs;
    System.Byte []           info;
    System.String            fileName;
    System.IO.StreamWriter   sw;
    str                      mystr;
    System.Exception         ex;
    
    try
    {
    	new InteropPermission(InteropKind::ClrInterop).assert();
    	encode = new System.Text.UTF8Encoding(true);
    	info  =  encode.GetBytes("Create test content");
    	mystr = System.Guid::NewGuid().ToString("N");
    	mystr = directory   @"\" mystr @".txt";
    	fileName = mystr;
    	fs = System.IO.File::Create(fileName);
    	fs.Write(info, 0, info.get_Length());
    	fs.Close();
    	fs.Dispose();
    	sw = System.IO.File::AppendText(fileName);
    	sw.Write("Modify test content");
    	sw.Close();
    	sw.Dispose();
    	System.IO.File::Delete(fileName);
    	CodeAccessPermission::revertAssert();
    }
    catch(Exception::CLRError)
    {
    	ex = ClrInterop::getLastException();
    	if (ex != null)
    	{
    	   ex = ex.get_InnerException();
    	   if (ex != null)
    	   {
    		   error(ex.ToString());
    	   }
    }
    CodeAccessPermission::revertAssert();
    res = false;

    A few comments to this code:

    • Close() and Dispose() do the same thing; you don't have to call them both.
    • You're not disposing fs and sw objects if an exception occurs
    • You don't have to call CodeAccessPermission::revertAssert() if you don't have other code in your method when the permissions shouldn't apply. Usually it's better to design small single-purpose methods rather and revertAssert() isn't typically needed in such a case. Also, you call revertAssert() twice (in the successful scenario, which isn't necessary).
    • You could replace most of your code with System.IO.File::WriteAllText().

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

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
Martin Dráb Profile Picture

Martin Dráb 592 Most Valuable Professional

#2
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 478 Super User 2025 Season 2

#3
BillurSamdancioglu Profile Picture

BillurSamdancioglu 305 Most Valuable Professional

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans