File Download via HTTP and FTP

I have been working on a solution for file download.  I am now able to download both binary and text files both via http and ftp and both with Classic Client and Role Tailored Client.

Attached is a codeunit that can download a text file via http, a zip file via http and a text file via ftp.  I use dotnet object for the Role Tailored Client to handle files on the client side.

FileDownload

Loading a client file into BLOB with RTC Client

For some time have been looking for a solution on how to upload a file into BLOB with RTC Client.  The built in functions, UPLOAD and UPLOADINTOSTREAM both force an Open Dialog unless you first copy the file to a temporary path.  I already had the file name and wanted to skip that part.

I always stopped on the fact that I was unable to move binary data with code from the client layer to the server layer.  Then today, I finally got an idea on how to solve this.  I convert the client file to a base64 string, transfer that string to the server layer and save as a file.  Then I create a binary server file based on the base64 server file.  That file is identical to the client file and ready to be imported into BLOB on the server side.
[code htmlscript=”false”]IF ISSERVICETIER THEN BEGIN
Document.ADDTEXT(
ClientConvert.ToBase64String(
ClientFile.ReadAllBytes(ImageFileName)));
ServerBase64FileName := ThreeTireMgt.ServerTempFileName(”,”);
ServerFileStream.WRITEMODE(TRUE);
ServerFileStream.CREATE(ServerBase64FileName);
ServerFileStream.CREATEOUTSTREAM(OutStr);
Document.WRITE(OutStr);
ServerFileStream.CLOSE;

ServerDocumentFileName := ThreeTireMgt.ServerTempFileName(”,”);
ServerDocumentFile.WriteAllBytes(
ServerDocumentFileName,
ServerConvert.FromBase64String(
ServerBase64File.ReadAllText(ServerBase64FileName)));

ServerFileStream.OPEN(ServerDocumentFileName);
ServerFileStream.CREATEINSTREAM(InStr);
Image.CREATEOUTSTREAM(OutStr);
COPYSTREAM(OutStr,InStr);
ServerFileStream.CLOSE;
ServerBase64File.Delete(ServerBase64FileName);
ServerDocumentFile.Delete(ServerDocumentFileName);
END ELSE BEGIN
Image.IMPORT(ImageFileName,FALSE);
END;[/code]
This should support files upto 1.5GB in size.

ImageTest

Import a text to RTC Note in the Record Link Table

In the process of importing data from MSSQL into NAV I needed to import a comment text. I wanted to import the text into the Note BLOB field in the Record Link table. It was not obvious how to do this but after some work I successfully imported all my comments.

I first start to create the record link with the following code
[code htmlscript=”false”]IF Note <> ” THEN BEGIN
LinkID := DestTbl.ADDLINK(”,DestTbl.TABLECAPTION);
RecordLink.GET(LinkID);
RecordLink.Type := RecordLink.Type::Note;
RecordLink.Note.CREATEOUTSTREAM(OutStr);
OutStr.WRITE(Text2NoteText(Note));
RecordLink.MODIFY;
END;[/code]
After my first round I found out that I needed to include the length of the Note as a Char in the beginning of the note. Then I noticed that my Icelandic characters where not correctly imported and after some study found out that the content of the BLOB needs to be UFT-8 encoded. This led me to create the Text2NoteText function.
[code htmlscript=”false”]Text2NoteText(NoteToImport : Text[1024]) NAVNode : Text[1024]
NAVNode := UTF8Encode(NoteToImport);
NoteLength := STRLEN(NAVNode);
IF NoteLength <= 255 THEN BEGIN
Char1 := NoteLength;
NAVNode := FORMAT(Char1) + NAVNode;
Char2 := 1;
END ELSE BEGIN
Char1 := 128 + (NoteLength – 256) MOD 128;
Char2 := 2 + (NoteLength – 256) DIV 128;
NAVNode := FORMAT(Char1) + FORMAT(Char2) + NAVNode;
END;[/code]
And the UFT8Encode function
[code htmlscript=”false”]UTF8Encode(String2Encode : Text[1024]) EncodedString : Text[1024]
MakeVars;
String2Encode := CONVERTSTR(String2Encode,NavStr,AsciiStr);
FOR Index := 1 TO STRLEN(String2Encode) DO BEGIN
Char2 := String2Encode[Index];
IF Char2 <= 127 THEN
EncodedString := EncodedString + FORMAT(Char2)
ELSE IF Char2 <= 192 THEN BEGIN
Char1 := 194;
EncodedString := EncodedString + FORMAT(Char1) + FORMAT(Char2);
END ELSE BEGIN
Char1 := 195;
Char2 := Char2 – 64;
EncodedString := EncodedString + FORMAT(Char1) + FORMAT(Char2);
END;
END;[/code]
The MakeVars function creates the NavStr and AsciiStr that I need for the conversion. This is similar to function InitCharTables in Codeunit 424 except I am not using Excel to convert the strings.

Attached is a codeunit with these functions.

RTCNoteTool

 

Icelandic Localization

In the localized version of Dynamics NAV 2009 R2 the report layout for Role Tailored Client is missing.  I have created the layout and applied a few fixes to the reports.

ID Name Caption
204 Sales – Quote Sala – Tilboð
205 Order Confirmation Pöntunarstaðfesting
206 Sales – Invoice Sala – Reikningur
207 Sales – Credit Memo Sala – Kreditreikningur
210 Blanket Sales Order Standandi sölupöntun
405 Order Pöntun
406 Purchase – Invoice Innkaup – Reikningur
407 Purchase – Credit Memo Innkaup – Kreditreikningur
10911 IRS Details Upplýs. vegna skattstofu
10912 Trial Balance – IRS Number Prófjöfnuður – Skattst.númer
10913 IRS notification Tilkynning skattayfirvalda
10940 VAT Balancing A VSK-afstemming A
10941 VAT Balancing Report VSK

The following ZIP file is encrypted.

NAV IS2009R2 Reports

File download with RTC

My earlier post on File Download used the responsestream property of WinHTTP. On my latest project I needed to use Windows Authentication on my website and found out that I needed to create the WinHTTP automation on client level to login with the current user. This also means that I cannot use built in streaming functions to download the file. Instead I used ADOStream function to download the file and in the example that follows I am saving the file to the temporary directory for the current user.
[code htmlscript=”false”]DownloadFile(URL : Text[1024]) FileName : Text[1024]
IF ISCLEAR(WinHTTP) THEN
CREATE(WinHTTP,TRUE,TRUE);

WinHTTP.open(‘GET’,URL,FALSE);
WinHTTP.send(”);

IF WinHTTP.status <> 200 THEN
ERROR(Text023,WinHTTP.status,WinHTTP.statusText);

FileName := WinHTTP.getResponseHeader(‘Content-Disposition’);
IF STRPOS(FileName,’filename=’) = 0 THEN
FileName := ”
ELSE BEGIN
FileName := COPYSTR(FileName,STRPOS(FileName,’filename=’) + 10);
IF ISCLEAR(ADOStream) THEN
CREATE(ADOStream,TRUE,TRUE);

IF ADOStream.State = 1 THEN
ADOStream.Close;

ADOStream.Type := 1; // adVarBinary
ADOStream.Open;
ADOStream.Write(WinHTTP.responseBody);

IF ISCLEAR(FileSystem) THEN
CREATE(FileSystem,TRUE,TRUE);

FileFolder := FileSystem.GetSpecialFolder(2);
FilePath := FileFolder.Path;
ADOStream.SaveToFile(FilePath + ‘\’ + FileName,2);
FileName := FilePath + ‘\’ + FileName;

ADOStream.Close;
END;

CLEAR(WinHTTP);[/code]
Where my variables are

FileSystem – Automation – ‘Windows Script Host Object Model’.FileSystemObject
FileFolder – Automation – ‘Windows Script Host Object Model’.Folder
WinHTTP – Automation – ‘Microsoft XML, v6.0’.XMLHTTP
ADOStream – Automation – ‘Microsoft ActiveX Data Objects 2.8 Library’.Stream
FilePath – Text[1024]

Blob and RTC Client

I am working on a RTC interface for my Payroll System.  To my suprice some of the codes that are running perfectly on Classic Client do not work on the RTC Client.  One example is the code
[code htmlscript=”false”]DeleteOutgoingMessage(VAR Statement : Record "Payroll Statement")
WITH Statement DO BEGIN
TESTFIELD(Status,Status::Created);
CLEAR("Outgoing Message");
MODIFY;
END;[/code]
that worked in the Classic Client but needed to be
[code htmlscript=”false”]DeleteOutgoingMessage(VAR Statement : Record "Payroll Statement")
WITH Statement DO BEGIN
TESTFIELD(Status,Status::Created);
CALCFIELDS("Outgoing Message");
CLEAR("Outgoing Message");
MODIFY;
END;[/code]
to work in both clients.

Add Namespaces to outgoing XML

The tax authority in Iceland are using Soap web services.  I have built XML Ports in NAV to create the request XML and another one to read the response XML.

I already wrote about using stylesheet to strip namespaces from the incoming XML before passing it to the XML Port.  I previously just added namespaces to the outgoing XML with attributes in the request XML Port.  This does not work in Role Tailored Client.

The solution was to remove all the namespaces attributes from the request XML Ports and create a function to add namespaces to the XML before passing it to the web server.  This work both in Classic Client and in Role Tailored Client.

AddNameSpaces source code

File Handling and RTC

In the Role Tailored Client all file system commands used by the Classic Client have been removed.  For those who have been using commands such as EXISTS, RENAME and ERASE there is a code update to be done.  I created a codeunit that includes these functions and can be used to replace the commands in the old code.  These functions work both in the Role Tailored Client and in Classic Client.

The attached code includes the following functions;

  • SelectExcelFileName
  • ConfirmFileExists
  • FileExists
  • FileRename
  • FileErase
  • FileCopy

Code is attached here.