Sending Flat Files from Dynamics 365 for Operations to a Different Location
One of the challenges we have found with Dynamics 365 for Operations is the export of flat files. Recently we had to get data (as a flat file) out of Dynamics 365 for Operations and place it in a location for a separate system to process. The process had to be secure.
Initially, we were going to use the .NET Framework functionality for FTP-ing the data to an FTP site, but found that out of the box .NET does not provide the secure FTP functionality. There are many different options (some freeware, some paid). This discussion will implement a freeware version using SSH.NET (https://github.com/sshnet/SSH.NET).
The first step is to build the dll. Once built, a reference needs to be added to the Visual Studio project. One issue we found is that this reference needs to be in a location that will be available on all different environments (Development, UAT, and Production). We ended up copying the dll (Renci.SshNet.dll) to the AOS file structure, and placing it in the root of our Model (see screenshot below).
This file was added to the Visual Studio project, and then added into version control. This allows the file to follow the project throughout the promotion of code.
The code below is part of a class that was created to allow the batching of the file upload process (which is called AFTER the file has been created and validated to exist). The code logs into the FTP site, and once successful uploads the file to the defined location.
All of the configuration information is stored in a custom table called SysFTPSiteInfo.
Below is the code for the ftp method used. Error trapping is NOT implemented in this demonstration code.
/// This method implements sftp functionality
public void ftpFile()
// find the location where to save the file
select firstonly pathFile;
filePath = pathFile.FilePath;
// get the ftp site info
select firstonly ftpInfo;
ftpAddress = ftpInfo.FTPSite;
ftpLocation = ftpInfo.FTPFolder;
ftpUser = ftpInfo.FTPUserId;
< CODE REMOVED FOR READABILITY>
// decrypt the password
ftpPW = cryptography.decrypt(ftpInfo.FTPPassword);
fileName localfileName = filePath + @'\' + expFileName;
[filepath, filename, fileType] = fileNameSplit(localfileName);
ftpFileName = ftpAddress + '/' + ftpLocation + '/' + fileNameString;
reader = new System.IO.StreamReader(localfileName);
utf8 = System.Text.Encoding::get_UTF8();
bytes = utf8.GetBytes( reader.ReadToEnd() );
// secure file transfer via SFTP
using (var sftp = new Renci.SshNet.SftpClient(ftpAddress,ftpUser,ftpPW))
sftp.ChangeDirectory(@"/" + ftpLocation);
using (var fileStream = new System.IO.FileStream(localfileName, System.IO.FileMode::Open))
sftp.BufferSize = 4 * 1024;