Guidelines for Partners
It is no secret that upgrading to Business Central Cloud environment from a previous version or from an OnPrem environment comes with a lot of changes in code functionality. One such change is in the handling of multiple files, which we can see in the example below.
Let’s say that we want to convert this report to SaaS:
OnPreReport()
FileName1 := ‘CustomerInfo.txt’;
FileName2 := ‘VendorInfo.txt’;
File1.CREATE(‘C:\FILES\’ + FileName1);
File2.CREATE(‘C:\FILES\’ + FileName2);
MESSAGE(‘Files were created’);
File1.TEXTMODE(TRUE);
File2.TEXTMODE(TRUE);
File1.WRITE(PADSTR(‘Customer No.’, 20) + ‘Customer Name’);
File2.WRITE(PADSTR(‘Vendor No.’, 20) + ‘Vendor Name’);
OnPostReport()
File1.CLOSE();
File2.CLOSE();
MESSAGE(‘Done’);
Customer – OnAfterGetRecord()
Text1 := PADSTR(Customer.”No.”, 20) + Customer.Name;
File1.WRITE(Text1);
Vendor – OnAfterGetRecord()
Text2 := PADSTR(Vendor.”No.”, 20) + Vendor.Name;
File2.WRITE(Text2);
This report has two DataItems: Customer and Vendor and upon execution, exports two files in the specified destination:
Since the File datatype cannot be used in the Cloud environment, the code is reworked with streams:
report 50100 MultipleFileDownload
{
UsageCategory = ReportsAndAnalysis;
ApplicationArea = All;
Caption = ‘Multiple File Download’;
ProcessingOnly = true;
dataset
{
dataitem(Customer; Customer)
{
trigger OnAfterGetRecord()
begin
Text1 := PadStr(Customer.”No.”, 20) + Customer.Name + TextBuilder.ToText();
OutStr_1.WriteText(Text1);
end;
}
dataitem(Vendor; Vendor)
{
trigger OnAfterGetRecord()
begin
Text2 := PadStr(Vendor.”No.”, 20) + Vendor.Name + TextBuilder.ToText();
OutStr_2.WriteText(Text2);
end;
}
}
trigger OnPreReport()
begin
FileName1 := ‘CustomerInfo.txt’;
FileName2 := ‘VendorInfo.txt’;
TextBuilder.AppendLine();
TempBlob1.CreateOutStream(OutStr_1);
TempBlob2.CreateOutStream(OutStr_2);
OutStr_1.WriteText(PadStr(‘Customer No.’, 20) + ‘Customer Name’ + TextBuilder.ToText());
OutStr_2.WriteText(PadStr(‘Vendor No.’, 20) + ‘Vendor Name’ + TextBuilder.ToText());
Message(‘Files Created’);
end;
trigger OnPostReport()
begin
TempBlob1.CreateInStream(InStr_1);
DownloadFromStream(InStr_1, ”, ”, ”, FileName1);
TempBlob2.CreateInStream(InStr_2);
DownloadFromStream(InStr_2, ”, ”, ”, FileName2);
Message(‘Done’);
end;
var
TempBlob1: Codeunit “Temp Blob”;
TempBlob2: Codeunit “Temp Blob”;
OutStr_1: OutStream;
OutStr_2: OutStream;
InStr_1: InStream;
InStr_2: InStream;
FileName1: Text;
FileName2: Text;
TextBuilder: TextBuilder;
Text1: Text;
Text2: Text;
}
[Tip: In the original code, the file function TEXTMODE(TRUE) would cause a new line to be added at the end of each WRITE function, but this is not the case with streams. Without manually adding a new line, all the text would be written in one line. This is where TextBuilder becomes useful. The addition of TextBuilder.ToText() at the end of the line ensures that any newly written text in the OutStream will start from a new line.
With TextBuilder:
Without TextBuilder:
]
Unfortunately, after running this code, we can see that only the last file is downloaded, in this case, the VendorInfo.txt file:
We still want to receive two separate files, so in this article we will go over two different ways to overcome this problem.
1. Adding a Confirm prompt before downloading the file
This is the simplest solution, because it only requires two lines of code to be added to the OnPostReport() trigger:
trigger OnPostReport()
begin
TempBlob1.CreateInStream(InStr_1);
If Confirm(‘Would You like to download this file: ’ + FileName1) then
DownloadFromStream(InStr_1, ”, ”, ”, FileName1);
TempBlob2.CreateInStream(InStr_2);
If Confirm(‘Would You like to download this file: ’ + FileName2) then
DownloadFromStream(InStr_2, ”, ”, ”, FileName2);
Message(‘Done’);
end;
Upon running the updated code, we are prompted with these messages:
After accepting, we receive the file:
Then the other confirmation appears:
And after accepting, we get the other file:
2. Creating Zip Files
Another way to overcome this issue is to create a .zip file and download that. This solution requires a bit more code modification:
First, we must add two more variables: a name for the .zip file and a DataCompression Codeunit, which will assist us with creating .zip files:
var
TempBlob1: Codeunit “Temp Blob”;
TempBlob2: Codeunit “Temp Blob”;
OutStr_1: OutStream;
OutStr_2: OutStream;
InStr_1: InStream;
InStr_2: InStream;
FileName1: Text;
FileName2: Text;
TextBuilder: TextBuilder;
Text1: Text;
Text2: Text;
ZipFileName: Text;
DataCompression: Codeunit “Data Compression”;
Next, we add a few lines of code in the OnPreReport() trigger to assign a name to the ZipFileName variable and to create the .zip file:
trigger OnPreReport()
begin
FileName1 := ‘CustomerInfo.txt’;
FileName2 := ‘VendorInfo.txt’;
TextBuilder.AppendLine();
TempBlob1.CreateOutStream(OutStr_1);
TempBlob2.CreateOutStream(OutStr_2);
OutStr_1.WriteText(PadStr(‘Customer No.’, 20) + ‘Customer Name’ + TextBuilder.ToText());
OutStr_2.WriteText(PadStr(‘Vendor No.’, 20) + ‘Vendor Name’ + TextBuilder.ToText());
Message(‘Files Created’);
ZipFileName := FileName1 + ‘ + ‘ + FileName2 + ‘.zip’;
DataCompression.CreateZipArchive();
end;
And lastly, we must modify the OnPostReport() trigger to add the created .txt files to the .zip file and to download the .zip file itself:
trigger OnPostReport()
begin
TempBlob1.CreateInStream(InStr_1);
DataCompression.AddEntry(InStr_1, FileName1);
// DownloadFromStream(InStr_1, ”, ”, ”, FileName1);
TempBlob2.CreateInStream(InStr_2);
DataCompression.AddEntry(InStr_2, FileName2);
// DownloadFromStream(InStr_2, ”, ”, ”, FileName2);
Clear(OutStr_1);
Clear(InStr_1);
Clear(TempBlob1);
TempBlob1.CreateOutStream(OutStr_1);
DataCompression.SaveZipArchive(OutStr_1);
TempBlob1.CreateInStream(InStr_1);
DownloadFromStream(InStr_1, ”, ”, ”, ZipFileName);
Message(‘Done’);
end;
Execution of this code results in this download, which, as we can see, contains both of the files we need:
Conclusion
In summary, there are pros and cons to each of the methods we discussed. A confirmation dialog might be the preferred option if only a few files need to be downloaded, but if there are multiple files to download, the .zip file might be the better way to go. Since both of these workarounds end up changing the original functionality of the code, consider which solution suits your needs better.