Monday, March 8, 2010

Changing the “Original” Server Configuration

After installing the Dynamics AX client on my machine, having set it to connect to a development AOS, I needed to eventually connect the client to the testing AOS. During installation, I was prompted to enter the AOS name, however changing this later was not immediately clear. At first, I assumed this could be done in the AX client, however, after a little bit of digging, I found that changing the AOS connection must be performed via the “Microsoft Dynamics AX Configuration Utility” (Start > Control Panel > Administrative Tools > Microsoft Dynamics AX Configuration).

If you are like me however, you may be curious to know exactly where these settings reside behind the scenes. Using the utility, you cannot change the “Original” configuration, but rather, are expected to create a new configuration which you can then apply and later edit as often as you desire. This serves the purpose well, and I cannot foresee a reason to ever need to modify the original configuration. However, in my industry there are usually exceptions, and obscure needs tend to be required more often than not. So what if for some unknown reason, you need to change the server in the original configuration? This can actually be done quite easily, as the server name is explicitly defined in the following series of registry keys:

HKEY_CURRENT_USER\Software\Microsoft\Dynamics\5.0\Configuration\Original (installed configuration)\

Keys:
- aos2
- internet

HKEY_CURRENT_USER\Software\Microsoft\Dynamics\5.0\Configuration\Original (installed configuration)\SetupProperties

Keys:
- AOS2
- CLIENTAOSSERVER

HKEY_LOCAL_MACHINE\Software\Microsoft\Dynamics\5.0\Configuration\Original (installed configuration)\

Keys:
- aos2
- internet

HKEY_LOCAL_MACHINE\Software\Microsoft\Dynamics\5.0\Configuration\Original (installed configuration)\SetupProperties

Keys:
- AOS2
- CLIENTAOSSERVER


Friday, March 5, 2010

The Basics: Using X++ to throw a user-friendly message on an invalid table insert

Let’s say your customer needs a custom table called VisitorTable, which has an integer field called VisitorCount, and a date field called VisitDate. Duplicate dates are not allowed in the table, and once a record is entered into the system, only the VisitorCount field can be edited. Setting all of this up is rather simple in the AOT strictly using MorphX.

However, in addition, the customer has stated that they need a more user friendly error message displayed when an attempt is made to insert a record with a duplicate date. Performing this task is not quite as straight forward, and requires a little X++. One of any number possible solutions could work, one for example, is as follows:

To accomplish such functionality, you could override the aosValidateInsert () method on the VisitorTable with the following code:

public boolean aosValidateInsert()
{
boolean ret;
VisitorTable vt;
;

select vt
where vt.VisitDate == this.VisitDate;

if (vt.RecId)
{
ret = false;
throw error("The date already exists, you must specify a different date");
}
else
{
ret = super();
}

return ret;
}


This method is executed prior to an insert on the table. “this” is an object reference representing the record that is going to be inserted, thus we use the VisitDate value of “this” as the lookup in our query. If a record is returned matching that date, which is flagged by the existence of a RecId, then we can throw a more user friendly error alerting the user of this issue, otherwise, continue.

CLR Interop in X++ Example 2: Sending Email with an Attachment

Continuing from my first post, “CLR Interop in X++ Example 1: Obtaining a Screen Shot”, the next step in my error reporting routine would be to send the newly created PNG file in an email. Once again, for the .NET Developer, it is easy to first create and test the function in .NET, and use it as a basis for translation into X++. Below is a rather simple C#.NET function which sends an email message with one attachment. The parameters of the function are self-explanatory:

bool SendEmail(string ToAddress, string FromAddress, string SMTPServer, string Username, string Password, string Subject, string Body, string FileToAttach)
{
bool success = true;

try
{
MailMessage mail = new MailMessage(FromAddress, ToAddress);
if (FileToAttach.Length > 0)
{
mail.Attachments.Add(new Attachment(FileToAttach));
}

mail.Subject = Subject;
mail.Body = Body;

SmtpClient smtp = new SmtpClient(SMTPServer);

NetworkCredential networkCred = new NetworkCredential(Username, Password);
smtp.UseDefaultCredentials = false;
smtp.Credentials = networkCred;

smtp.Send(mail);
}
catch
{
success = false;
}

return success;
}


The next snippet is the X++ translation:

boolean SendEmail(str ToAddress, str FromAddress, str SMTPServer, str Username, str Password, str Subject, str Body, str FileToAttach)
{
System.Net.Mail.MailMessage mail;
System.Net.Mail.Attachment attach;
System.Net.Mail.AttachmentCollection ac;
System.Net.Mail.SmtpClient smtp;
System.Net.NetworkCredential networkCred;
boolean success;
;

success = true;

try
{
mail = new System.Net.Mail.MailMessage(FromAddress, ToAddress);
if (strlen(FileToAttach) > 0)
{
attach = new System.Net.Mail.Attachment(FileToAttach);
ac = mail.get_Attachments();
ac.Add(attach);
}

mail.set_Subject(Subject);
mail.set_Body(Body);

smtp = new System.Net.Mail.SmtpClient(SMTPServer);

networkCred = new System.Net.NetworkCredential(Username,Password);
smtp.set_UseDefaultCredentials(false);
smtp.set_Credentials(networkCred);

smtp.Send(mail);
}
catch(Exception::CLRError)
{
success = false;
}

return success;
}

Thursday, March 4, 2010

CLR Interop in X++ Example 1: Obtaining a Screen Shot

As part of a custom error handling routine, I came up with the idea of taking an automatic screen shot of the AX environment at the moment an error occured, which could then be emailed along with other error details to the development team. Whether or not such functionality is actually useful in a production environment is not the point of this entry. This idea rather, was more or less a proof of concept, and my first attempt at utilizing CLR Interop in X++.

The following simple code snippet is a function in C#.NET which simply takes a screen shot of the primary screen, and saves it to a specified location as a PNG file.

bool CaptureScreen(string SaveToFileName)
{
bool success = true;

try
{
Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(bitmap as Image);
graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
bitmap.Save(SaveToFileName, ImageFormat.Png);
}
catch
{
success = false;
}

return success;

}

The second code snippet is my translation of the code from C# to X++

boolean CaptureScreen(str SaveToFileName)
{
System.Drawing.Bitmap bitmap;
System.Drawing.Graphics graphics;
System.Windows.Forms.Screen primaryScreen;
System.Drawing.Rectangle bounds;
boolean success;
;

success = true;

try
{
primaryScreen = System.Windows.Forms.Screen::get_PrimaryScreen();
bounds = primaryScreen.get_Bounds();

bitmap = new System.Drawing.Bitmap(bounds.get_Width(), bounds.get_Height());
graphics = System.Drawing.Graphics::FromImage(bitmap);

graphics.CopyFromScreen(0,0,0,0, bitmap.get_Size());

bitmap.Save(SaveToFileName, System.Drawing.Imaging.ImageFormat::get_Png());
}
catch
{
success = false;
}

return success;
}



The benefit of first writing a routine in .NET, whether it be in C# or VB.NET, is that you can use the rich GUI of Visual Studio to help you more easily create a CLR based X++ method. Simply by moving the mouse over a given object in your .NET code, you will be able to retrieve the exact namespace of the objects that will need to be explicitly defined in your X++ code. Coming soon, Example 2, which will feature the C# and X++ functions to send the saved PNG in an email...