Rashed Amini

The ara3n weblog

Archive for the 'DotNet' Category

Using Enumerators in C/AL to iterate through files in a folder

26th March 2013

Enumerators in .NET allow you to iterate through arrays and collections in your class. You can see this used for example in FOREACH Loop. Here is an example.

DirectoryInfo di = new DirectoryInfo("c:\\temp");
FileInfo[] files = di.GetFiles("*.pdf”);
foreach (FileInfo fileInfo in files)
{
Console.WriteLine(FileInfo.Name)
}

There is no way to translate FOREACH loop in C/AL, but there is a workaround using List class.
In the above example, DirectoryInfo returns an array of FileInfo . In FOREACH loop we are looping through each file and printing it to console screen.

So the first line in NAV is initializing DirectoryInfo with constructor

DirectoryInfo := DirectoryInfo.DirectoryInfo('C:\temp\');

The second line is where we are changing and assigning it to a List. The CAL Compiler should error out but it is not. It looks like it’s not doing any type checking. At runtime it is determining the object type returned. DirectoryInfo.GetFiles().ToList() ;


List := DirectoryInfo.GetFiles('*.txt');
enumerator := List.GetEnumerator();

Once we have a list of enumerator class then we can loop through each object

WHILE enumerator.MoveNext DO BEGIN
FileInfo:= enumerator.Current();
MESSAGE('%1',FileInfo.Name);

END;

Here is the whole Code with Variable type

DirectoryInfo DotNet System.IO.DirectoryInfo.’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
FileInfo DotNet System.IO.FileInfo.’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
List DotNet System.Collections.Generic.List`1.’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
enumerator DotNet System.Collections.IEnumerator.’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′

DirectoryInfo := DirectoryInfo.DirectoryInfo('C:\temp\');

List := DirectoryInfo.GetFiles('*.txt');

enumerator := List.GetEnumerator();

WHILE enumerator.MoveNext DO BEGIN
FileInfo:= enumerator.Current();
MESSAGE('%1',FileInfo.Name);

END;

Posted in DotNet, Dynamics NAV 2013 | Comments Off

Integrating with MSMQ using dotNET data types in NAV 2009 R2

2nd April 2011

With the release of NAV 2009 R2, we can now use dotNET data types. This allows CAL programmers to access .NET framework within CAL. There are many benefits on using dotNET data types as opposed to Automation data types. First is distribution of your CAL code. You simply send the fob to the client. If you are referencing any .NET framework class, then by default it’s installed on the box with NAV RTC. Second reason is performance. dotNET data types will perform better than COM Automations. Third, the code is available to see and edit in CAL.

Over the past several years I’ve integrated with many other systems using Microsoft Message Queue (MSMQ). The other systems were for example; BizTalk, websites, 3rd party Manufacturing systems, or handheld units. I’ve used the Automation provided by MS “Navision MS-Message Queue Bus Adapter”. It had many limitations and in certain integration I had to use “Microsoft Message Queue 3.0 Object Library”. I’ve decided to rewrite the solution using dotNET.

The solution below allows sending and receiving MSMQ messages using dotNET variables. It consists of two code units. Code unit 50010 “Send MSMQ” sends an xml file. Code unit 50011 “Receive MSMQ” reads the xml files and stores them on c drive. You can off course change this based on your requirement.

Here is a screenshot of Send MSMQ
MSMQ1

Here is a screenshot of Receive MSMQ
MSMQ2

The code is simple, but it took me a while to get it to work. The main reason is the MessageFormatter. In dotNET you need to specify the formatter for your messages. By default MSMQ uses XmlMessageFormatter but I could not make it work in CAL.
The C# code looks like this.
q.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });

So instead I am using
Q.Formatter := QActiveXFormatter.ActiveXMessageFormatter;

ActiveXFormatter is used for backward compatibility. You could also send Binary message format. You code would look like this.

Q.Formatter := QBinaryFormatter.BinaryMessageFormatter;

The reason is that there is no equivalent of typeof in CAL. If you find a workaround, post a response. If you have any solution using Automation, it is worth to take a look at implementing it in dotNET. If you are still using classic client, you can run this code using web service on service tier. Here is the link the objects in fob and text format MSMQ.zip.

Posted in DotNet, Dynamics NAV | No Comments »

Using ADO on RTC in NAV

10th January 2011

On one of my recent projects I had to build a solution to update a NAV table with quantity on hand by location. Writing a processing report to maintain update and maintain the table would have taken less than an hour. But for this project performance of a NAV report would have not worked. The client has about 1000 locations and about 80,000 Items. Worst case scenario, you could end up with 80 million records in this table. The solution I provided uses ADO to connect to SQL server and issue a SQL statement on Item Ledger Entry Indexed view.
My solution was based on Waldo’s post

This worked fine on classic client, but when I tried to run this on Role Tailored Client (RTC), I was getting the following error.

The expression Variant cannot be type-converted to a String value.

The error was from the following line.
lADOCommand.ActiveConnection := lvarActiveConnection;

This basically means that you cannot use ‘Microsoft ActiveX Data Objects 2.8 Library’ in RTC. So what other option are available? You could build an external dll file that wraps the active x DLL file. But that creates many headaches with registering and maintaining the dll file on every workstation. The other solution that I’m going to talk about is that in NAV 2009 R2, Microsoft released a new data type called DotNet. With this data type, you can access the .Net framework and reference the classes in NAV. So the code for accessing NAV using DotNet datatype looks like this.


ServerName := 'VIRTUALXP-51168';
NavDb := 'Demo Database NAV 6R2';

ConnectionString := 'Data Source='+ServerName+';'
+ 'Initial Catalog='+NavDb+';'
+ 'Trusted_Connection=True;';

SQLConnection := SQLConnection.SqlConnection(ConnectionString);

SQLConnection.Open;
SQLCommand := SQLConnection.CreateCommand();
SQLCommand.CommandText := 'select * From Session';
SQLReader := SQLCommand.ExecuteReader;

WHILE SQLReader.Read() DO BEGIN
MESSAGE( 'Reading %1 , %2 ',SQLReader.GetInt32(0), SQLReader.GetString(1));
END;

SQLConnection.Close;

CLEAR(SQLReader);
CLEAR(SQLCommand);
CLEAR(SQLConnection);

In the example above I’m simply reading the session table and printing the “Connection ID” and “User ID”. In addition you can assign to SQLCommand.CommandText sql statement that are greater than 1024 characters.
Here are the DotNet data types for the above code.

Name DataType Subtype
SQLConnection DotNet ‘System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.System.Data.SqlClient.SqlConnection
SQLCommand DotNet ‘System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.System.Data.SqlClient.SqlCommand
SQLReader DotNet ‘System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.System.Data.SqlClient.SqlDataReader

If you are on older version of NAV, you have to do executable upgrade to Dynamics NAV 2009 R2 to be able to use DotNet object types.

Posted in DotNet, Dynamics NAV | 1 Comment »