As I already explained in this blog post you can import text files with encoding in Dynamics NAV 2009 R2 Classic Client and old versions.
Today, I will use the same trick to export a text file with encoding (UTF-8 in the example below).
To illustrate this, let’s export all items in a text file from a Russian database. I’ll use three possible solutions:
1- Via dataport:
2- Via codeunit using variable of type File:
3- Via codeunit using variable of type Automation (Stream):
Now, let’s see the results:
We quickly notice that export via dataport or via File variable does not do the job as Russian characters are not exported correctly whereas export via Stream does the job perfectly.
As always, I let you download the objects and files I used in this blog post.
P.S: If you’re still using Microsoft Dynamics NAV 2009 R2 Classic Client or a previous version, then you may want to continue reading this blog post.
We all know that Microsoft Dynamics NAV 2009 R2 Classis Client supports ANSI only (code page 1252 or depends on your windows localization).
In order to import/export encoded files we usually use some workarounds. In fact, when you google (bing) you will find two main answers:
Ansi-Ascii converter: but you need to add new characters in the codeunit as they come up,
Use some third party tools: but this will create dependency and it will cause a headache to maintain your NAV platform.
The solution I personally prefer is to use “Microsoft ActiveX Data Objects 2.8 Library” automation. In fact, this Dll is available on every windows machine and it offers a an interesting object: Stream.
In order to use it, you need to:
Know your text file encoding,
Check that your OS supports the needed language,
Use a simple code is your NAV:
CREATE(Stream);
Stream.Open;
Stream.Charset(_Charset);
Stream.LoadFromFile(_Path);
Line := Stream.ReadText(1024);
Stream.Close;
Let’s see how this works concretely. In the example below, I will use a Russian Windows Server (change English to Russian):
Then, I will use two Russian text files with different encoding: UTF-8 and IBM855 (OEM 855). Finally, I test all on a NAV 2009 R2 Russian Native Demo Database.
I’ll let you see the results:
Below some comments to understand the results:
Code
Comment
FIL_IBM855
Read a IBM855 encoded file with File variable
FIL_UTF8
Read a UTF-8 encoded file with File variable
IBM_UTF
Read a IBM855 encoded file with Stream automation and wrong Charset = UTF-8
STR_IBM855
Read a IBM855 encoded file with Stream automation and correct Charset = IBM855
STR_UTF8
Read a UTF-8 encoded file with Stream automation and correct Charset = UTF-8
UTF_IBM
Read a UTF-8 encoded file with Stream automation and wrong Charset = IBM855
Finally, I’ll let you download the objects and the files I used in the examples here.
By introducing NAV 2016, Microsoft introduced Try Functions to endow developers with some sort of Try/Catch in C/AL.
The purpose of this blog is not to add another entry to explain how to use Try Functions. José Castro Fernández has already explained this here. The problem with these types of functions is resumed in this sentence from MSDN:
Changes to the database that are made with a try function are not rolled back.
So, inattentive developers may cause some calamities… You know what I mean 😉
Fortunately, Microsoft caught up by the introduction of NAV 2017. It added a new parameter DisableWriteInsideTryFunctions. It is fully documented here.
Okay, this is all good to know but what is the point behind this post?
To answer this question, I will first ask a question 🙂
How can we create a “Try Function” for older versions (5.0 to 2015)?
The answer is simple, and every NAV developer know it (should know it):
IF MyCodeunit.RUN THEN
MESSAGE(‘OK’) // Continue processing…
ELSE
MESSAGE(GETLASTERRORTEXT); // Log the error or display it…
One of the biggest advantages drawbacks to me José is not having to use one new codeunit everytime we need to “trycatch” a process. This can end up consuming a lot of codeunits in some cases. (Yes, I quoted José and I made some modifications 🙂 ).
Here comes the purpose of my post. I would like to share with you a trick I used to use far away before NAV 2016. In fact, I created a Codeunit to centralize all processes that need a “trycatch”. It’s all based on this simple code (of course):
IF TryCatch.RUN(TempParam) THEN
MESSAGE(‘OK’)
ELSE
MESSAGE(GETLASTERRORTEXT);
“TryCatch” is my Codeunit where all the magic happens thanks to my temporary table “TempParam”. All you need to do; is to implement the function you want to “trycatch” inside the “Try/Catch” Codeunit and use it as I show in the “Try/Catch Example” Codeunit. Enough explanations, I believe the Codeunit is simple to understand. I’ll let you try and see by yourselves, download the objects here (fob and txt are from a NAV 2009 R2 database).
Of course, I’ll be glad to answer your questions if needed.
If “TempParam” trick does not suit your need then create your own solution (share it as comment if you want). You can for example create global variables inside “Try/Catch” Codeunit and initialize them by calling a function “InitMyGlobals” before you call TryCatch.RUN.
I was doing my “daily NAV tour” on Mibuso and NAV Community forums when I spotted the following question:
I have about 300 new reports in my nav database and I need to write down the names of only those that are not ProcessingOnly. Do you know any smart way how to do this quick?
A member suggested an answer. But it applies to NAV new versions only (2015 and later). I could not resist the challenge. Hence my blog post to suggest a solution that applies for all old NAV versions (all versions might be a big word because I tested the code in a 2009 R2 database only 😉 )
Let’s get straight to the point. Here are the variables I used:
Name
DataType
Subtype
Length
TempObject
Record
AllObj
AllObj
Record
AllObj
ObjectMetadata
Record
Object Metadata
XMLDocument
Automation
‘Microsoft XML, v6.0’.DOMDocument60
InStr
InStream
TempFile
File
TempFileName
Text
250
TempString
Text
1024
And the code:
ObjectMetadata.SETRANGE(“Object Type”, ObjectMetadata.”Object Type”::Report);
// Filter On report ID if needed
// ObjectMetadata.SETFILTER(“Object ID”, ‘MyFilter’);
IF ObjectMetadata.FINDSET THEN
REPEAT
ObjectMetadata.CALCFIELDS(Metadata);
IF ObjectMetadata.Metadata.HASVALUE THEN BEGIN
TempFileName := DELCHR(TEMPORARYPATH + FORMAT(CREATEGUID) + ‘.xml’, ‘=’, ‘{}-‘);
ObjectMetadata.Metadata.CREATEINSTREAM(InStr);
InStr.READTEXT(TempString, 1024);
WHILE NOT InStr.EOS DO BEGIN
CLEAR(TempString);
InStr.READTEXT(TempString, 1024);
TempFile.WRITE(TempString);
END;
// 1 is ProcessOnly, 0 Others
IF XMLDocument.selectSingleNode(‘Report/ProcessingOnly’).text = ‘0’ THEN BEGIN
AllObj.GET(ObjectMetadata.”Object Type”, ObjectMetadata.”Object ID”);
TempObject.INIT;
TempObject.TRANSFERFIELDS(AllObj);
TempObject.INSERT;
END;
END;
UNTIL ObjectMetadata.NEXT = 0;
FORM.RUNMODAL(FORM::”All Objects”, TempObject);
And of course, the code adapted for NAV new versions (NAV 2016 in my test) 😉
ObjectMetadata.SETRANGE(“Object Type”, ObjectMetadata.”Object Type”::Report);
// ObjectMetadata.SETFILTER(“Object ID”, ‘3’);
IF ObjectMetadata.FINDSET THEN
REPEAT
ObjectMetadata.CALCFIELDS(Metadata);
IF ObjectMetadata.Metadata.HASVALUE THEN BEGIN
TempBlob.Blob := ObjectMetadata.Metadata;
XMLDOMManagement.LoadXMLDocumentFromText(TempBlob.ReadAsText(”, TEXTENCODING::UTF8), XmlDocument);
IF XMLDOMManagement.FindNodeText(XmlDocument, ‘Report/ProcessingOnly’) = ‘0’ THEN BEGIN
AllObj.GET(ObjectMetadata.”Object Type”, ObjectMetadata.”Object ID”);
TempObject.INIT;
TempObject.TRANSFERFIELDS(AllObj);
TempObject.INSERT;
END;
END;
UNTIL ObjectMetadata.NEXT = 0;