Skip to main content

Notifications

D365FO Use of FileUpload control to Read CSV file

Sukrut Parab Profile Picture Sukrut Parab 71,656 Moderator

In Dynamics Ax implementation very often we get requirement to upload data using csv files. Although in Dynamics 365 for operations it can be easily done using data entities and data packages, in this blog we will see how can we use new FileUpload control and design classes to read, download files.

In  Dynamics 365 for operations  application runs on cloud and the client is in web , so Microsoft has introduce new process to read files using Azure blob. When we upload file, that file gets uploaded to Azure blob and we have to read that file from Azure blob to retrieve data.

Design classes:

There are two main types of classes that developers can work with for the file upload control:

  • Upload strategy class – This class lets developers control various parameters that should be enforced for uploaded files, such as the types of files that a user can upload and the maximum size of a file. It also lets developers determine where and how the uploaded file should be stored. All upload strategy classes must inherit from the abstract FileUploadStrategyBase class. The framework provides a default upload strategy class named  FileUploadTemporaryStorageStrategy

  • Upload result class – This class lets developers access the details of a file that was uploaded by a user, such as its name, content type, and upload status. It also lets developers open and delete the corresponding file. All upload result classes must inherit from the abstract FileUploadResultBase class. Default upload result class that is named FileUploadTemporaryStorageResult. This upload result class stores uploaded files to the temporary blob storage and provides a download URL.

    Below is X++ code to create dialog which uploads file in to blob storage and get temporary URL to retrieve data from the file.

    public Object dialog()
    {
        DialogGroup      dialogGroup;
        FormBuildControl formBuildControl;
        FileUploadBuild  dialogFileUpload;
        Set              enumSet = new Set(Types::Enum);
                
        ;
        
        dialog = super(); 		        
        dialogGroup = dialog.addGroup("File path");
        formBuildControl = dialog.formBuildDesign().control(dialogGroup.name());
        
        dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), FileUploadName);
        dialogFileUpload.style(FileUploadStyle::MinimalWithFilename);
        dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy));
        dialogFileUpload.fileTypesAccepted(availableTypes);
        dialogFileUpload.fileNameLabel("@SYS308842");
    
        return dialog;
    }


You can see in the above code I used FileUploadBuild control and provided base class FileUploadTemporaryStorageStrategy to method baseFileUploadStrategyClassName which will be used to upload file to azure blob.

The FileTypesAccepted property of the file upload control lets you limit the types of files that users can upload

dialogFileUpload.fileTypesAccepted(availableTypes);

availableTypes is private Variable declared in classdeclaratoin which

private str                 availableTypes = ".csv";

In the class Declaration control names for OK and upload control

private const str OkButtonName = 'OkButton';

private const str FileUploadName = 'FileUpload';

Following methods is required to Enables or disables the dialog Ok button.

protected void setDialogOkButtonEnabled(DialogRunbase _dialog, boolean _isEnabled)
{
        FormControl okButtonControl = this.getFormControl(_dialog, OkButtonName);

        if (okButtonControl)
        {
            okButtonControl.enabled(_isEnabled);
        }
}
protected FormControl getFormControl(DialogRunbase _dialog, str _controlName)
{
        return _dialog.formRun().control(_dialog.formRun().controlId( _controlName));
}



Once the file has been uploaded to blob storage ok button needs to be enabled. Following method takes care of that by calling callback event handler to be notified when upload is complete.

protected void uploadCompleted()
 {
        FileUpload fileUpload = this.getFormControl(dialog, FileUploadName);
        fileUpload.notifyUploadCompleted -= eventhandler(this.UploadCompleted);
                
        textFile = fileUpload.fileName();

        this.setDialogOkButtonEnabled(dialog, true);
  }


/// Disables the dialog Ok button until the file upload is complete.
    
    public void dialogPostRun(DialogRunbase _dialog)
    {
        FileUpload fileUpload = this.getFormControl(_dialog, FileUploadName);
        fileUpload.notifyUploadCompleted += eventhandler(this.uploadCompleted);
        this.setDialogOkButtonEnabled(_dialog, false);
    }
  

Once dialog is open you can see file upload control where you can select file and Ok button is disabled.

Image1.JPG

Once file is uploaded to blob Ok button is enabled, you can see that in below screen.

 image2.JPG   

Here is the code which reads the CSV file

void processCSVFile()
    {
        #File
        container               currentLine;
        int                     totalOfLines;
        CommaTextStreamIo       localStream;
        Num                     number;
            
       
        FileUpload fileUploadControl = this.getFormControl(dialog, FileUploadName);
        
        FileUploadTemporaryStorageResult fileUploadResult = fileUploadControl.getFileUploadResult();
        
        if (fileUploadResult != null && fileUploadResult.getUploadStatus())
        {
            textFile = fileUploadResult.getDownloadUrl();
        }
        
        localStream = CommaTextStreamIo::constructForRead(File::UseFileFromURL(textFile));
       
          
        if (localStream.status() != IO_Status::Ok)
        {
            throw error(strfmt('Is not possible to open the file. Error %1',enum2str(localStream.status())));
        }
    
        localStream.inFieldDelimiter("\,");
        localStream.inRecordDelimiter("\n");
    
        currentLine = localStream.read();
        fileLineNumber++;
    
        if(conlen(currentLine) == 1)
        {
            throw error('Is not possible to import the file, incorrect format');
        }
    
            
        currentLine = localStream.read();
        fileLineNumber++;
    
        while(currentLine)
        {
            number = conPeek(currentLine,1);

            info(strFmt("Number : %1",number));

             
            currentLine = localStream.read();
                
        }
    
 
    }

   Here is my Sample CSV file to test the code

Image3.JPG

Infolog showing values of the number column from csv file.

image4.JPG

If you have any feedback feel free to comment. Thanks for reading the blog and have a great day.

Reference

https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/user-interface/file-upload-control

 

Comments

*This post is locked for comments

  • Ahtisham Ud Din Profile Picture Ahtisham Ud Din 2
    Posted at
    public Object dialog() method is declared as final how can someone overide it ? Sukrut Parab I try to use your all code in UI Builder class which extend SysOperationAutomaticUIBuilder and it give me error on the declaration of public Object Dialog as this method is declared as final in base code of microsoft
  • Crispin John Augustine Profile Picture Crispin John Augustine 37,081
    Posted at
    Very very helpful, Sukrut. Thanks for sharing this.
  • Steve Bredall Profile Picture Steve Bredall 20
    Posted at
    Very good article with one exception......We don't have all of the code which Adolfome9 pointed out on 7/11/2019. For example, in your first code block you make a call to super().....what is super()? Is it possible to share all of the code in your example? Thanks in advance.
  • Denis Trunin Profile Picture Denis Trunin 175
    Posted at
    Just a note - don't use CommaTextStreamIo to read CSV files. It contains several issues for reading file if cells are empty(you can check on yammer by searching CommaTextStreamIo if you have access for Dynamics AX7 group). Use either TextIO(TextStreamIO) or Microsoft.VisualBasic.FileIO (you can find full description on denistrunin.com/xpptools-readexcelfile/)
  • Adolfome9 Profile Picture Adolfome9 110
    Posted at
    Please, could you share your complete code?
  • cauditor Profile Picture cauditor
    Posted at

    In Dynamics AXR3 we had a menu item that excuted a class that read an excel file and by code populated the necessary  tables for invoices.  The invoices would show up on the accounts payable module> pending invoices list page.  We are now testing in the testing phase in 365FO and greatly need this functionality.  

    Can the same thing be accomplished thru this method.  Upload a csv file  to Azure Blob then have a menu item that excecutes code that will populate the tables to 'import' the invoice' into the tables so that the invoices would display on the pending invoices list page and to the user would appear as if they were manually entered and a second user could then review, edit and submit to workflow for approaval

  • Moeen Ahmed Sultan Profile Picture Moeen Ahmed Sultan 1,402
    Posted at

    How can we upload file from specific path in batch jobs?