Showing posts with label Tool. Show all posts
Showing posts with label Tool. Show all posts

Friday, October 20, 2017

Validate Email Address in NAV using RegEx

business-man-1002781_1920

Last week I was working on a shipment notification project where I need to send Email Notification of the shipment and one thing we need to check is the email address is valid or not. In Standard NAV the SMTP mail codeunit or Mail Management codeunit has a function to checkValidEmailAddress but it does a very basic validation and it did not meet our needs so I have written a new function to validate the email address.

I have used  RegEx( Regular Expression) and According to Wikipedia

“A regular expression, regex or regexp[1] (sometimes called a rational expression)[2][3] is, in theoretical computer science and formal language theory, a sequence of characters that define a search pattern. Usually this pattern is then used by string searching algorithms for "find" or "find and replace" operations on strings.”

Since we have the access the functions of RegEx function using DotNet, I went a ahead and wrote the following function to validate the email address using RegEx.

In our case we could store multiple email addresses in a field, so I have used String Array to parse and validate the email address.

PROCEDURE ValidateEmailAddresses@1000000008(EmailAddresses@1000000000 : Text);
     VAR
       RegEx@1000000004 : DotNet "'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Text.RegularExpressions.Regex";
       DotNetString@1000000003 : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.String";
       EmailAddrArray@1000000002 : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Array";
       Convert@1000000001 : DotNet "'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Convert";
       I@1000000005 : Integer;
       EmailAddress@1000000006 : Text;
     BEGIN
       EmailAddresses := CONVERTSTR(EmailAddresses,',',';');
       EmailAddresses := DELCHR(EmailAddresses,'<>');
       EmailAddrArray := RegEx.Split(EmailAddresses,';');
       FOR I := 1 TO EmailAddrArray.GetLength(0) DO BEGIN
         EmailAddress := EmailAddrArray.GetValue(I-1);
         IF NOT RegEx.IsMatch
               (EmailAddress,'^[\w!#$%&*+\-/=?\^_`{|}~]+(\.[\w!#$%&*+\-/=?\^_`{|}~]+)*@((([\-\w]+\.)+[a-zA-Z]{2,4})|(([0-9]{1,3}\.){3}[0-9]{1,3}))$') THEN
           ERROR(Text106);
       END;
     END;
I got the above email address regular expression pattern from the below link, so please visit the below to know what validation it does.
https://www.rhyous.com/2010/06/15/regular-expressions-in-cincluding-a-new-comprehensive-email-pattern/

If you have any other tips or suggestions , please do share them in the comments below.


Share:

Wednesday, October 18, 2017

How to Schedule NAV Services to Restart

clock-2174116_1920

Recently I was asked if there is a way to schedule a NAV service to restart at a specific time, and for that I have used a small PowerShell script which I have scheduled using windows task scheduler.

Below is the script and steps for that

This example is based on NAV 2013 but the same code can be used for other versions

The below  PowerShell script is used to restart NAV Services, since in our case there are more then one NAV instance on the server, I have used a for loop to find all the available/running instances and then filter those instances using like statement, in this case I am only restarting NAV Instances with the word “Test” in their name. You can replace this with any other word or remove that condition.

Import-Module 'C:\Program Files\Microsoft Dynamics NAV\70\Service\NavAdminTool.ps1' -WarningAction SilentlyContinue | Out-Null
$Instances = Get-NAVServerInstance
for ($i = 0; $i -le $Instances.Count - 1; $i++) {    
     if ($Instances[$i].State -eq 'Running' -And $Instances[$i].Name -like '*Test*') {       
         Restart-Service $Instances[$i].Name
         #Write-Output $Instances[$i].Name
     }
}

Save the above script in a file and store in a location then we need to create a Task Scheduler to execute the above script.

Create a new task using the option shown in Fig 1, then choose the name, and Trigger when you want to run, under the Actions tab choose Start a Program  (Fig 2) and for the program use Powerhsell.exe and specify the ExecutionPolicy ByPass and path for the script in arguments

image

Fig 1


image

Fig 2

image

Fig 3


This will create a task in windows scheduler to restart the services, you can also export the task as .xml and import into another server.

If you have any other tips or suggestions, please do share them in the comments below.

Share:

Thursday, February 16, 2017

NAV Development Tool Update–February

Welcome to the February update for the Developer Preview. As in the last two updates, we’ve fixed bugs reported by you on our GitHub issues list (https://github.com/Microsoft/AL/issues) and made other improvements.

You can see a list of what’s new below.

– Finishing your design work in the client now offers two options on saving, allowing you to save the changes to the tenant for all users, or to save the changes to a file that you can work on later in VS Code. Performance of the designer has improved and is snappier.

inclient_2

– To guide users towards a better page design, we’ve been adding a few rules in the in-client designer. For example, you can only drop media fields onto card part pages. Also, you cannot drop a field under a repeater control, because this is not the design that list pages were intended for.

– Getting started in VS Code has been streamlined. Once you’ve installed the visx file, just enter AL: Go! in the command palette (Ctrl+Shift+P) and you’ll be offered a new folder to build a solution in. The preset values are configured for your Azure Gallery instance and if you’re missing the symbols for the project, VS Code will offer to download them for you. Note, we’ve introduced a shortcut for this too – Alt+A, Alt+L. Enjoy!

algo

– We’ve made improvements in IntelliSense with contextual support for keywords in all objects – and we’ve added autocompletion and IntelliSense for setting values for the CalcFormula and TableRelation properties.

– You can now reference Query objects from the base application. This gives you the ability to declare variables of the type Query and call AL functions on them.

– References by symbols have been implemented meaning that you can find all references in an inline editor. Pressing Shift+F12 on top of a symbol will open a view that lets you jump to all instances of that symbol. Furthermore, selecting a symbol and pressing F2 allows you to rename all instances of that symbol. Note, that symbolic rename is cleverer than text matching and will only change the current symbol. For example, it will replace all instances of variable Foo, but not rename function Foo.

– Two AL variables have been introduced mapping to the HTTP Client and JSON types. Using HttpClient, HttpResponseMessage, JsonObject, JsonToken, and JsonValue will allow you to access Azure functions and other Web services.

– Miscellaneous bugs reported from GitHub have been fixed.

Just like in the last update, we’ve already updated the Azure Gallery so new images will include the update. Again, we’ve designed for compatibility with your existing files so any .al projects you have already will work with the AL Language extension for VS Code. Having said that, changes may need to be introduced at some time so save your work independently as you go.

We have big ambitions for the next month so stay with us. Thanks again for the bugs – keep them coming and we’ll fix them as fast as we can.

Share:

Tuesday, December 27, 2016

How to download FTP files using .NET Interop

download-1459071_1920_thumb

Recently i have worked on a project where the requirement was to upload and download the files from a FTP.  In this blog i will be explaining how to download the files using .NET Interop. There are several other blogs which have explained, how to download the files using ScriptingHost or .net interop but i have not found an example to download all the files from a particular folder.

These are couple of blogs i found, related to this.

http://www.archerpoint.com/blog/Posts/automating-command-line-functions-nav-rtc-transmit-ftp

http://www.dynamics.is/?p=583

Below is the code that downloads all the files from a particular FTP Folder to your local download folder. The GetFTPSetup is just another function to retrieve the setup values.

I have used two functions to download the files, the first function DownloadFilesFromFTP will find all the files and add to the list, then we will loop through the list to download the file using the second function.


PROCEDURE DownloadFilesFromFTP@1240060028();
     VAR
       FTPWebRequest@1240060000 : DotNet &quot;'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Net.FtpWebRequest&quot;;
       FTPWebResponse@1240060001 : DotNet &quot;'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Net.FtpWebResponse&quot;;
       NetworkCredential@1240060002 : DotNet &quot;'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Net.NetworkCredential&quot;;
       WebRequestMethods@1240060003 : DotNet &quot;'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Net.WebRequestMethods+File&quot;;
       UTF8Encoding@1240060004 : DotNet &quot;'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Text.UTF8Encoding&quot;;
       ResponseStream@1240060005 : InStream;
       FileStream@1240060006 : DotNet &quot;'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.IO.FileStream&quot;;
       TempBlob@1240060008 : TEMPORARY Record 99008535;
       FileName@1240060007 : Text;
       OutStream@1240060009 : OutStream;
       StreamReader@1240060010 : DotNet &quot;'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.IO.StreamReader&quot;;
       List@1240060012 : DotNet &quot;'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Collections.Generic.List`1&quot;;
       i@1240060011 : Integer;
       PathHelper@1240060013 : DotNet &quot;'mscorlib'.System.IO.Path&quot;;
       FileAttributes@1240060014 : DotNet &quot;'mscorlib'.System.IO.FileAttributes&quot;;
       DotNetFile@1240060015 : DotNet &quot;'mscorlib'.System.IO.File&quot;;
     BEGIN
       GetFTPSetup;
       FTPWebRequest := FTPWebRequest.Create(FTPSetup.&quot;FTP Download FilePath&quot;);
       FTPWebRequest.Credentials := NetworkCredential.NetworkCredential(FTPSetup.&quot;FTP UserName&quot;,FTPSetup.&quot;FTP Password&quot;);
       FTPWebRequest.UseBinary := TRUE;
       FTPWebRequest.UsePassive := TRUE;
       FTPWebRequest.KeepAlive := TRUE;
       FTPWebRequest.Method := 'NLST';
       FTPWebResponse := FTPWebRequest.GetResponse();
       StreamReader := StreamReader.StreamReader(FTPWebResponse.GetResponseStream());
       List := List.List();
       FileName := StreamReader.ReadLine();
       WHILE FileName &lt;&gt; '' DO BEGIN
         List.Add(FileName);
         FileName := StreamReader.ReadLine();
       END;
       FOR i:=1 TO List.Count DO BEGIN

        IF FORMAT(List.Item(i-1)) &lt;&gt; 'archive' THEN BEGIN
           DownloadFileFromFTP(FORMAT(List.Item(i-1)));
         END;
         
       END;
     END;

    [TryFunction]
     LOCAL PROCEDURE DownloadFileFromFTP@1240060029(FileToDownload@1240060010 : Text);
     VAR
       FTPWebRequest@1240060000 : DotNet &quot;'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Net.FtpWebRequest&quot;;
       FTPWebResponse@1240060001 : DotNet &quot;'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Net.FtpWebResponse&quot;;
       NetworkCredential@1240060002 : DotNet &quot;'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Net.NetworkCredential&quot;;
       WebRequestMethods@1240060003 : DotNet &quot;'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Net.WebRequestMethods+File&quot;;
       UTF8Encoding@1240060004 : DotNet &quot;'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Text.UTF8Encoding&quot;;
       ResponseStream@1240060005 : InStream;
       FileStream@1240060006 : DotNet &quot;'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.IO.FileStream&quot;;
       TempBlob@1240060008 : TEMPORARY Record 99008535;
       FileName@1240060007 : Text;
       OutStream@1240060009 : OutStream;
     BEGIN
       GetFTPSetup;
       FTPWebRequest := FTPWebRequest.Create(FTPSetup.&quot;FTP Download FilePath&quot; + FileToDownload);
       FTPWebRequest.Credentials := NetworkCredential.NetworkCredential(FTPSetup.&quot;FTP UserName&quot;,FTPSetup.&quot;FTP Password&quot;);
       FTPWebRequest.UseBinary := TRUE;
       FTPWebRequest.UsePassive := TRUE;
       FTPWebRequest.KeepAlive := TRUE;
       FTPWebRequest.Method := 'RETR';
       FTPWebResponse := FTPWebRequest.GetResponse();
       ResponseStream := FTPWebResponse.GetResponseStream();
       TempBlob.Blob.CREATEOUTSTREAM(OutStream);
       COPYSTREAM(OutStream,ResponseStream);
       FileName := FTPSetup.&quot;FTP Local Download FilePath&quot; + FileToDownload; // 'download' + FORMAT(CURRENTDATETIME,0,'&lt;Year4&gt;&lt;Month,2&gt;&lt;Day,2&gt;&lt;Hours24&gt;&lt;Minutes,2&gt;&lt;Seconds,2&gt;') +'.txt';
       TempBlob.Blob.EXPORT(FileName);
     END;

Please leave your comments, feedback or any suggestions you have for me to improve my blog and also if you have any questions, feel free to post.


Share:

Tuesday, November 10, 2015

How to Read/Write Notes in Navision using C/AL

question-686336_1920

In this post I will discuss how to read the notes and how to create the notes programmatically. When you create a note where the data is saved in the Navision ? I have seen this question being asked several times in the community forum. The answer is the notes are saved in binary format in a blob field (Note) in the Record Link table (2000000068) and the way it maps to the record is using Record ID.

Read Notes:

To read notes you need to find the “Record ID” of the record using Record Reference and then use that to filter the Record Link table and then convert value in the blob field (Note) into readable text.

In the below example the ReadNotes function takes SalesHeader as parameters and displays the first note associated with it.

Write Notes:

To create note once we again need to get the “Record ID” of the record which can be retrieved using Record Reference, and we also need to convert the text into bytes to store in the “Note” Blob Field. Since the Record Link primary key Link ID is set to Auto Increment we don’t need to find the next available “Link ID”, as INSERT statement will take care of retrieving it and assigning it.

There are two helper functions below SetText and HtmlEncode, you need these functions to write notes.

PROCEDURE ReadNotes@1240060000(SalesHeader@1240060003 : Record 36);
    VAR
      RecordLink@1240060000 : Record 2000000068;
      NoteText@1240060001 : BigText;
      Stream@1240060002 : InStream;
      RecRef@1240060004 : RecordRef;
    BEGIN
      RecRef.GETTABLE(SalesHeader);
      RecordLink.SETRANGE("Record ID",RecRef.RECORDID);
      IF RecordLink.FINDFIRST THEN BEGIN
        REPEAT
          RecordLink.CALCFIELDS(Note);
          IF RecordLink.Note.HASVALUE THEN BEGIN
            CLEAR(NoteText);
            RecordLink.Note.CREATEINSTREAM(Stream);
            NoteText.READ(Stream);
            NoteText.GETSUBTEXT(NoteText, 2);
            MESSAGE(FORMAT(NoteText));
          END;
       UNTIL RecordLink.NEXT = 0;
      END;
    END;

    PROCEDURE WriteNote@1240060001();
    VAR
      LinkID@1240060000 : Integer;
      Customer@1240060001 : Record 18;
      RecRef@1240060002 : RecordRef;
      RecordLink@1240060003 : Record 2000000068;
    BEGIN
      Customer.GET('10000');
      RecRef.GETTABLE(Customer);
      RecordLink.INIT;
      RecordLink."Link ID" := 0;
      RecordLink."Record ID" := RecRef.RECORDID;
      RecordLink.URL1 := GETURL(CLIENTTYPE::Current, COMPANYNAME, OBJECTTYPE::Page, PAGE::"Customer Card");
      RecordLink.Type := RecordLink.Type::Note;
      RecordLink.Created := CURRENTDATETIME;
      RecordLink."User ID":=USERID;
      RecordLink.Company:=COMPANYNAME;
      RecordLink.Notify := TRUE;
      SetText('Test Note For the Customer 10000',RecordLink);
      RecordLink.INSERT;
    END;

    LOCAL PROCEDURE SetText@4(NoteText@1001 : Text;VAR RecordLink@1000 : Record 2000000068);
    VAR
      SystemUTF8Encoder@1011 : DotNet "'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Text.UTF8Encoding";
      SystemByteArray@1010 : DotNet "'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Array";
      OStr@1008 : OutStream;
      s@1007 : Text;
      lf@1006 : Text;
      c1@1005 : Char;
      c2@1004 : Char;
      x@1003 : Integer;
      y@1002 : Integer;
      i@1009 : Integer;
    BEGIN
      s := NoteText;
      SystemUTF8Encoder := SystemUTF8Encoder.UTF8Encoding;
      SystemByteArray := SystemUTF8Encoder.GetBytes(s);

      RecordLink.Note.CREATEOUTSTREAM(OStr);
      x := SystemByteArray.Length DIV 128;
      IF x > 1 THEN
        y := SystemByteArray.Length - 128 * (x - 1)
      ELSE
        y := SystemByteArray.Length;
      c1 := y;
      OStr.WRITE(c1);
      IF x > 0 THEN BEGIN
        c2 := x;
        OStr.WRITE(c2);
      END;
      FOR i := 0 TO SystemByteArray.Length - 1 DO BEGIN
        c1 := SystemByteArray.GetValue(i);
        OStr.WRITE(c1);
      END;
    END;

    LOCAL PROCEDURE HtmlEncode@20(InText@1000 : Text[1024]) : Text[1024];
    VAR
      SystemWebHttpUtility@1001 : DotNet "'System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.System.Web.HttpUtility";
    BEGIN
      SystemWebHttpUtility := SystemWebHttpUtility.HttpUtility;
      EXIT(SystemWebHttpUtility.HtmlEncode(InText));
    END;






The two above functions SetText and HtmlEncode are copied from the standard Navision Codeunit (454 Job Queue - Send Notification)


Download the object from this link Notes Management


Please leave your comments, feedback or any suggestions you have for me to improve my blog and also if you have any questions, feel free to post.

Share:

Tuesday, October 13, 2015

Simple Tool to clear the data from the field in Navision

tool-78016_1280

It is quite often during the implementation or re-implementation projects that there is a need to change a field data type or delete the field after it was added. The issue is if that field has the data, then in order to change the data type or to delete the field we have to clear the field value otherwise you will get the error. Below is an example of such error

image

If you have multiple companies in the database then you to have to clear the data in all the companies before you make the change, normally I create a process report to clear the data and run that in each company but it is a tedious task if you have many companies. I have come across this situation many times, so I have created a simple tool called Clear Fields, this is a process report with option to filter on the table and the field you want to clear, it also has the option to clear the data in all the companies, so you don’t have to change company and run this in each company.

image

As of now this is only designed to clear one field at a time and it handles any field type, in the future I plan to extend this and add more options to it. I have uploaded the .fob and .txt objects in the below location, it also has a word document which will explain the above the request page options

Download Objects: http://1drv.ms/1Mwrzum

Please leave your comments, feedback or any suggestions you have for me to improve me my blog and also if you have any questions, feel free to post..

Share: