Friday, June 26, 2009

Email from Ax by CLR interop

In my previous post, I talked about the CLR Interop possibilities from Dynamics Ax. As you might know, CLR interop is used to get access to assemblies installed with the .NET Framework, or even the assemblies you create on your own with Visual Studio.

Here's another example. This time, we are going to send an email from Ax with it. (Yes I know, this kind of functionalities are provided with Ax out-of-the-box as well.)

void Email()
{ System.Net.Mail.MailMessage myMailMessage;
System.Net.Mail.SmtpClient myMail;
System.Net.Mail.MailAddress myMailFrom;
System.Net.Mail.MailAddress myMailTo;
System.Net.NetworkCredential myNC;

str mySubject="Mail from Ax 2009";
str myMailBody="The email body goes here";
str myMailFromStr="youremail@yourdomain.com";
str myMailToStr="youremail@yourdomain.com";
str mysmtpServer="yourmailservername";
str mylogin="loginname";
str mypassword="loginpassword";
;

myMailFrom = new System.Net.Mail.MailAddress(myMailFromStr,myMailFromStr);
myMailTo = new System.Net.Mail.MailAddress(myMailToStr,myMailToStr);
myMailMessage = new System.Net.Mail.MailMessage(myMailFrom,myMailTo);
myMailmessage.set_Subject(mySubject);
myMailmessage.set_Body(myMailBody);
myMail = new System.Net.Mail.SmtpClient(mysmtpServer);
myNC= new System.Net.NetworkCredential(mylogin,mypassword);
myMail.set_Credentials(myNC);
myMail.Send(myMailmessage);
}


Supplying of the network credentials is optional. If not specified, the default network credentials will be used. Depending on your email server settings (relay on/off), only emails to the local domain are allowed.


This example can be extended, to include file attachments for example.


Greetingz,



Willy

Network ping command by CLR interop

With the use of CLR interop, there doesn't seem to be a limit to what you can do with Ax. Yes, in the past you could write your own COM wrappers to access those DLL functions. But now, you have much more control. And it's faster. Your basic toolbox just got a LOT bigger. All this .NET components are waiting to be used.

Here's a small example. It demonstrates the well known ping command, to check if a computer is online.
Parameters are the Ip address (string format like 127.0.0.1) and the timeout.

static boolean Ping(str myIpAddressStr,int myTimeOut=4000)
{ System.Net.NetworkInformation.Ping myPing;
System.Net.NetworkInformation.PingReply myPingReply;
System.Net.IPAddress myIPAddress;
System.Net.NetworkInformation.IPStatus myIpStatus;
str myIPStatusStr;
;
if(!myIpAddressStr)

return false;

myIPAddress = System.Net.IPAddress::Parse(myIPAddressStr);
myPing = new System.Net.NetworkInformation.Ping();
myPingReply=myPing.Send(myIPaddress,myTimeOut);
myIpStatus=myPingReply.get_Status();
myIPStatusStr=myIpStatus.ToString();

if(myIPStatusStr=='Success')
return true;

return false;
}



I'll post some more samples later on.

Greetz,

Willy

Wednesday, June 24, 2009

Chart Object: Invalid license

After our upgrade to Ax 2009, one of our forms showed an error message when opening. The error message was:

Invalid License (1000000). Please contact SoftwareFX Support.


The error message got us puzzled for a while.

It was a custom form, where different chart objects were added during runtime.

Other forms with charts worked well. The form Tutorial_Form_Graph worked as well. No license issue. Strange thing: After opening another form with graphics, the error form suddenly started working! Until we restarted the client...
After lots of testing, we came up with a workaround: We added a hidden ActiveX control to the form, class Chart Object. Now our form always runs without errors.
Do you know the correct solution? Let me know!
Greetz,
Willy

Friday, June 19, 2009

Terminate a clien session

I was recently involved in a discussion over at the Microsoft Business Community newsgroups. The subject was the terminating of a client session.

I can suggest two approaches. Use the first job to kill the session of a specified user id. This involves the use of the xSession class, which I blogged of earlier on.

static void TerminateSession(UserId UserId)
{ xSession xSession;
int xSessionId;
;
xSessionId = (select * from SysClientSessions where SysClientSessions.userId==UserId && SysClientSessions.Status==1).SessionId;


xSession = new xSession(xSessionId);
if (xSession)
xSession.terminate(xSession.loginDate(), xSession.loginTime());
}

If you would like to end the current session by code, you can do it like this:

static void ShutDown(Args _args)
{ Info Info = new Info();
;
Info.shutDown(true);
}

If you can think of other means, feel free to post them in the comments.

Saturday, June 13, 2009

Check to see if a user is logged on

In my previous post I talked about the class xSession. The help files for this class in Ax show a nice example for this: Check to see if a specific user id is online.

server static boolean isUserOnline(userId userId)
{ xSession session;
int counter;
int maxSessions = Info::licensedUsersTotal();
;

if (!userId)
{
return false;
}

for(counter = 1; counter < session =" new">

This example is a nice illustration for the use of the xSession class.
I came up with an alternative, shorter version for the example above:

server static boolean isUserOnline(userId userId)
{ ;
return (select count(recid) from SysClientSessions where SysClientSessions.userId==UserId && SysClientSessions.Status==1).RecId;
}

So, both functions give you an easy way of checking if a specific user is online in Axapta.

Current session id

You can retrieve the current client session id by using the following function: SessionId().

So, for example in a job, to show the current session id

static void ClientSessionJob(Args _args)
{ ;
info(strfmt('This client session id is %1',int2str(SessionId())));
}

You can use this function together with the class xSession to collect more info.
The class xSession is responsible for retrieving various session information. Like the logon date and time:

static void LogonDateTime(Args _args)
{ xSession xSession;
;
xSession = new xSession(SessionId());
info(strfmt('The logon date and time were %1',DateTimeUtil::toStr(xSession.loginDateTime())));
}

Or the current AOS server name you're logged onto:

static void CurAOSServerName(Args _args)
{ xSession xSession;
;
xSession = new xSession();
info(strfmt('Current AOS server name logged onto is %1',xSession.AOSName()));
}

Instantiate the class xSession without a session id to get info for the current session.

The user id used to create the session is also available. But there is an alternative for this one:

static void ClientUserId(Args _args)
{ ;
info(strfmt('Current logged on user id %1',curUserId()));
}


Try out for yourself!

Thursday, June 11, 2009

Gartner Magic Quadrant in ERP

Gartner recently released a new version of its report on midmarket ERP systems. One of the featured products is Microsoft Dynamics Ax.


Not only does it get a good review, it's also the only product to be in the leader quadrant. Nice!

Gartner sees some trends in the ERP market, like

  • industry-specific functionality or verticalization
  • globalization, no longer being exclusive for large enterprises
  • consolidation in the market of ERP vendors

For both point 1 and 2, you can see Ax has grown the past few years. Offering a wealth of vertical solutions, certified and all. Microsoft also worked on the stability and performance of the product, making Ax even more suited to global operating companies, enterprise size or not. (fe Unicode support, multiple-time zones)

Some points why Ax scored so well in the report:

  • the user interface is considered to be very intuitive and easy to learn and use + it's role tailored
  • broad range of functionality, both horizontal and vertical
  • strong worldwide partner channel, certified
  • completeness of vision from Microsoft
  • scalable product, easy to customize for both enhancements and proces changes

All in all, a very good report. Nice to know for companies who have invested or are planning to invest in this offering.


You can read more of the report, which includes reviews of products from Oracle, SAP and Microsoft (with Dynamics NAV as well) over here.


Edit:
The report scores well with the press guys at Microsoft. But over the internet, a lot of criticism can be heard. Like on zdnet, cio.com, and The Enterprise System Spectator. They score some good arguments to question the outcome of the report (like no SaaS vendors included).

What can be learned from that? Don't use the Magic Quadrant as a buying guide for products. After all, if the solution you have an eye on has a perfect fit for your functional requirements, what do you care if the vendor has no worldwide presence if your a local operating company? Use the outcome of the report (pro and contra's) and verify them with your own findings/requirements. What are YOU looking for in an ERP suite and how is this evaluated by Gartner?

Wednesday, June 3, 2009

Checking table access from code

If you need to check if the current user has access to a certain table in Ax, this little job will help you out:


boolean CheckSecurityTable(TableId myTableId)

{ SysDictTable SysDictTable;
;
SysDictTable = new SysDictTable(myTableId);
if(SysDictTable.rights()<AccessType::View)

return false;


return true;
}


If you like your code a little more condensed, you could always use the built-in function hastableaccess. For example:

if(hastableaccess(tablenum(SalesLine),AccessType::View))
return true;


Something similar, but now with a menuitem:


boolean CheckSecurityMenu(MenuName myMenuName)

{ SysDictMenu SysDictMenu;
;
SysDictMenu = SysDictMenu::newMenuItem(myMenuName,MenuItemType::Display);
if(SysDictMenu.rights()<AccessType::View)

return false;


return true;
}



Greetz,


Willy

Tuesday, June 2, 2009

Colors in Ax

When using Ax, sooner or later you gonna use your own colors. But different functions in Ax (and extensions) require different definitions of these colors.

There are different coding system for colors. Some functions require the hexadecimal format, others expect an integer and so on.
Luckily, Ax comes with some built in functions to do the necessary conversions for you. Like this one:

WinApi::RGB2int() - Convert the red, green and blue values to an integer.
WinApi::RGBCon2int() - Dito, but with a container input
WinApi::RGBInt2con() - The opposite, converting from an integer to separate red, green and blue values

Or create your own functions, like this one for example:

static str int2RGBhex(int color)
{ container colorcon;
str colorhex;
;
colorcon=WinApi::RGBint2Con(color);
colorhex=Global::int2Hex(conpeek(colorcon,1),2);

colorhex+=Global::int2Hex(conpeek(colorcon,2),2);
colorhex+=Global::int2Hex(conpeek(colorcon,3),2);

return colorhex;
}

This function will convert an integer color value to a hexadecimal one.

Happy coding,


Willy