Thursday, December 03, 2009

Correct KernelFunctions xpo

Hey, guys.

Just a small update on my previous post on Kernel Functions for those interested.
I have now corrected the link to point to the right xpo.
It was previously pointing to a parser class I used to get some of the functions in.

Sorry about that :)
The uploaded xpo is compatible with AX 2009

Wednesday, November 25, 2009

Kernel functions exposed through BC.NET

BC.NET is a great feature of Dynamics AX. It allows to access the AX application from any external application that supports .NET, and provides a rather rich functionality out of the box.
But one feature that is missing in BC.NET is the ability to call AX kernel functions, like fieldId2Name, num2str, decRound, etc.

I needed to use these functions in my code recently, and in order to access them, I created a class in X++, that simply wraps the useful functions in static methods, kinda like the ones that exist in class Global.

Download Class_KernelFunctions.xpo

You need to import it into AX before using, of course. This can be automated, if you don't want to include this XPO as part of the package you deliver to your customers.

Now you can call it through the Business Connector the following way:

Axapta ax = new Axapta();
ax.Logon("ext", null, "localhost", null);
// num2str(123.45, -1, 2, 1, 1);
Convert.ToDouble(ax.CallStaticClassMethod("KernelFunctions", "num2str", 123.45m, -1, 2, 1, 1));

Tuesday, November 24, 2009

SysCompilerTarget - compiling X++ code without showing the compilation window

I have been posed with a question about how to avoid showing the compilation window during compilation of some X++ code (When doing compilation from code, naturally).

So I decided to post a possible solution for this question, re-using one of my previous posts about ClassBuild class.

Basically, AOTcompile method on TreeNode class supports an optional flag, controlling the compilation output:
An integer that indicates whether output should be sent to the message box. If the value 1 is passed, no output is sent to the message box. The default value is 0. This parameter is optional.


So all we need to do now is change the compilation output target to Message Window. Looking at the SysCompilerSetup form code, it's rather easy to come up with the following code:


static void SysCompilerTargetExample(Args _args)
{
ClassBuild classBuild;
DictClass dictClass;
SysCompilerTarget targetOrig;
;
// Setting Compilation Target = Message Window
targetOrig = SysUserInfo::compilerTarget();
SysUserInfo::compilerTarget(SysCompilerTarget::MessageWindow);
SysCompilerOutput::setCompilerTarget(SysCompilerTarget::MessageWindow);
SysCompilerOutput::updateParm();

// Building the class with 1 method
classBuild = new ClassBuild("TRN_ClassBuild", false);
classBuild.addMethod("test", 'void test()\n{\n}');
classBuild.addSourceToMethod("test", @"
;
info('We created a Class and can call its methods');");

// The actual compilation. Note the _flag argument == 1
classBuild.classNode().AOTcompile(1);

// Call the class method to show that we are done and the code is compiled
dictClass = new DictClass(className2Id(classBuild.name()));
dictClass.callObject('test', dictClass.makeObject());

// Restoring Compilation Target to its original value
SysUserInfo::compilerTarget(targetOrig);
SysCompilerOutput::setCompilerTarget(targetOrig);
SysCompilerOutput::updateParm();
}


Don't forget to restore the original settings after the compilation is complete, as shown above.

Friday, November 06, 2009

How to quickly set up Application Integration Framework (AIF) for testing Axd documents

Purpose of this post
Part of the test effort on our team at MDCC goes for verifying the Axd documents shipped with the Dynamics AX application.

As many people find it hard to setup AIF, I have tried to help them by creating an automated way of doing the initial setup, which can be used for testing the documents using a 1-box setup and FileSystem transport adapter.

Download link
From the following link, you will be able to download an X++ class that initializes all the entities required for AIF to work, like the endpoints, transport adapters and channels, services, their actions and action policies.
Note, that since I am working on the Inventory team, I am filtering out the services accordingly. You can easily extend/modify this to suite your specific needs by changing the filter or adding new ones in classDeclaration and method main

Download xpo

Example from the standard application
To give a specific example, I encourage you to try sending a selected item electronically in form of an XML file right after executing the job.
To do that, navigate to Inventory Management\Common forms\Item details and press Send electronically button. Fill in the values for endpoint, filter on a specific item(s), and press OK.

Your screen should look similar to this:


Processing the document
The document is successfully placed into the queue for processing and sending through the gateway. If you have a batch job for processing AIF services up and running, you will soon see a file in the outbound files folder setup on the outbound channel.
If you would like to learn, how to set up the batch jobs for this, follow the below link: Start and stop the asynchronous AIF services

In order to avoid having to set the batch jobs up, I have added 2 extra methods to the class for starting the processing of inbound and outbound messages.

public static void ProcessOutboundDocuments()
{
    new AifOutboundProcessingService().run();
    new AifGatewaySendService().run();
}
public static void ProcessInboundDocuments()
{
    new AifGatewayReceiveService().run();
    new AifInboundProcessingService().run();
}


Just call the DEV_AifInitialSetup::ProcessOutboundDocuments method from a job, and the document will be automatically processed and sent on its way to the outbound documents folder.

Output
The resulting XML file for the item should look similar to the following:

Monday, October 26, 2009

Mock objects implementation for AX

As you might now, I am working as a Software Development Engineer in Test at Microsoft Development Center in Denmark.

But the only real test framework that comes with AX is the SysTest framework (you can read more about it here).

Below you will find another framework for Dynamics AX, that was written by one of the members on my test team and allows to implement and use mock objects for testing the AX application.

More information and download link

It would be great if you could try it out and provide your feedback here or directly on the author's blog.

Thursday, October 22, 2009

Running a class from AOT or "How to assign a class to an action menu item?"

OK, so this might seem as a very simple question for many of you.

But, in reality, I still now and then meet people who have worked with AX for quite some time, but don't know this very basic concept.

Therefore, I just want to briefly describe it here to refresh everyone's memory

Apart from allowing to run the class from AOT, this will allow to assign it to a menu item (according to Best Practices, it should be a menu item of type Action), and run the class using this menu item.

Below is the correct syntax of the main method:


public static void main(Args _args)
{
//Your code here
}


Please also note, that there is an editor script that contains the template for the main method. You can invoke it from Scripts->template->method->main

Monday, September 28, 2009

New AX blog in da house

Most of you probably don't know Denis Fedotenko, but he is a well-respected member of the Russian AX community with multiple incredibly detailed articles about SCM functional areas.

He has recently started translating them to English and posting on his web-site, http://fedotenko.info/.

I highly recommend all of you to visit the link above and read the articles already posted there.

Tuesday, August 25, 2009

“Go to main table” on a RunBase dialog control

In one of my blog posts, I have been posed with the following question:

“how to achieve go to main table on dialog field.
for example a dialog is having a field of lookup custAccount, now what i need to have a go to main table functionality on the same.”

So, the short answer is: It is not possible to override jumpRef method directly on the dialog control. This is due to the fact that in order to show the “Go to Main table” link in the context menu of a control, you need to actually override that method on the form, which is later used to draw the context menu.

There are 3 possible ways that you can achieve the same functionality though, that I would like to briefly discuss here:

  1. Recommended Don’t bother with the dialog. Simply create a form, and override the jumpRef method on the needed control on the form. To demonstrate this behavior, you can use the Tutorial_RunBaseForm class and form. Override the jumpRef method, put the code to call the main form there. And you are done. Simple, and does not require a lot of coding. There is a lot of confusion, where junior AX developers think it will require a lot of code changes to replace a dialog with a form. This is not entirely that hard, as RunBase classes can use a regular AOT form instead of the regular dialog.
  2. Use controlMethodOverload approach, and create the controlName_context() method, which is executed when you try to open the context menu on the specified control. Inside this method, build the context menu from scratch. This way, only the items you want to be shown will be present in the context menu. Note: this means, that standard context menu items, like Setup, will not be shown in the menu (unless you add and handle them).
  3. Use controlMethodOverload approach, as in the previous example, but instead of overriding context() method, override the showContextMenu method. This will allow you to add your custom context menu items to the standard context menu. This does not seem to work on Axapta 3.0 though, and I did not try to figure out why. Note you need to uncomment some code in order to enable this approach (I left a TODO comment for that).

I have made the necessary changes, demonstrating the latter 2 approaches, using the class located under Classes\Tutorial_RunBaseBatch. You can download the xpo here (it contains only the USR layer changes).

The class used for drawing the context menu in the example is called PopupMenu. A good example of how this class can be used in the application is available in AOT under Forms\Tutorial_PopupMenu. Some information, along with another example, is available on MSDN.

A while ago, I have suggested some minor changes to the Dialog framework classes, which allow to simplify the process of overriding control event methods on the dialog. The original post can be found through this link: http://kashperuk.blogspot.com/2007/06/3-dialog-extensions.html

Let me know if any of this requires more clarification.

Monday, August 24, 2009

Inside Dynamics AX 2009 – Russian Translation

As you all know, Microsoft has recently released another book on development in Dynamics AX, called Inside Dynamics AX 2009.

For the past 2.5 months, I have been working on the Russian translation of this book, and now I am glad to say that the translation is over and will soon hit the shelves of online-stores. I guess it will also be available directly from Microsoft Russia, similar to the 4.0 version.

The book has gained a lot in weight :) and content. With more than 200 new pages, as well as many changes and updates of the existing chapters, the book is definitely a good investment. New “hot” features of Dynamics AX, like SSRS reports, Workflow, Role centers, etc., are described in the book from a developer point-of-view.

I really hope that my effort will not go in vain, and the book will be helpful to people working with Microsoft Dynamics AX 2009.

Thanks

Wednesday, May 20, 2009

Moving RSS from FeedBurner

Hi, subscribers. This is a small notification message.

Just wanted to let you know that I will be moving the RSS feed away from FeedBurner over the weekend, as it does not seem to work correctly with one of the MSDN pages, where my blog is being displayed.

So, instead of the following feed:
http://feeds.feedburner.com/KashperukIvan
you should use the one exposed on the blog:
http://kashperuk.blogspot.com/feeds/posts/default?alt=rss

If the problems with the MSDN page are solved, I will switch back to FeedBurner, but this won't effect you all, if you are using the latter feed link (as it is redirected automatically)

Thanks

Sunday, April 26, 2009

Lookup methods tutorial + custom list lookup implementation

One of the great features available in Dynamics AX is the support of lookup forms that provide a user-friendly interface for selecting a value for a field from a list, and are highly customizable, allowing the developer great flexibility in meeting user needs.

Recently, I was posed a question of how to present a user with a list of custom-defined values in a lookup form.

The simple (and suggested) approach here is to create a new BaseEnum, containing all the specified values, and add a ComboBox control for this enumeration to the form. If the values are to be displayed conditionally (only a subset is shown each time), you can build a superset of all values in AOT, and use SysFormEnumComboBox class to limit the actual output at runtime.

But, this would not work in my case, because the values in the list were dependent on other data in the form plus the current date. Using a temporary table for this scenario seemed like an overkill (but possible). So i decided to investigate the system class SysLookup for hints on how this can be done with minimum effort. The implementation of this method is provided below.

As part of posting this implementation, I decided to also briefly describe some of the other lookup method options available to an AX developer, turning this post into a small tutorial on lookup methods.

Tutorial_LookupMethods_Screenshot

1. The approach used most in the application is the implicit lookup based on table fields. As you can see from the control properties, DataSource and DataField specify which table field the control is based on. In my example, it is based on SalesTable.CustAccount, which uses the ExtendedDataType CustAccount, which has a relation to CustTable.AccountNum. Therefore, any time you add this field to a form, it will automatically provide a lookup button to select one of the customers.

Relations being specified on EDTs is at times confusing to people, who are used to seeing the relations between tables on the tables themselves. Technically speaking, such definitions on EDTs are incorrect. But no worries, AX supports the “correct” scenario out of the box as well. The relation to CustTable could have been specified on the table just as well.

2. 2nd most used approach is to specify the ExtendedDataType on the control directly. This is used to allow the user to specify a value to filter the records on directly from the form, for example (without the need to go to Extended Query form). It is also indirectly used on all RunBase dialogs in the system (when creating a DialogField, we specify the EDT to be used, which is transfered to the ExtendedDataType property on the corresponding control). In the tutorial, it is again the CustAccount EDT that is specified in the properties.

3. The 2 above examples both used metadata to define what lookup is to be displayed. The 3rd most used approach is relying on SysTableLookup class and builds the lookup at runtime. The code is relatively straightforward, and is described in more detail on MSDN. Using this approach, the developer can specify the query to filter the data being displayed in the lookup form. Note, that SysTableLookup only allows to have data from one table in the lookup form (+ display methods on this table). SysMultiTableLookup is an extension I have created a while ago, that adds this and other useful functionality to SysTableLookup class.

4. The remaining 2 standard approaches are rarely used in the application. Lookup based on ExtendedDataType is very similar to approach described under #2, but is executed from code at runtime. This way, you can change the lookup data displayed dynamically, based on some conditions (For example, on Ledger Journal lines, the offset account lookup shows vendors, customers, banks, etc. based on the offset account type specified on the line).

5. BaseEnum values are usually represented as a ComboBox (and, in special cases, CheckBox or RadioButton) control on forms in Dynamics AX. The lookup is provided by the kernel automatically for this type of control. But, sometimes, it is required to show the values of an enumeration in a string control – most common scenario is providing filter capabilities based on enums, where multiple values can be specified at once, similar to extended query form filters. In fact, this approach is actually used on SysQueryForm for enum fields. As you can see from the code, the lookup call is also very simple in this case.

6. This approach does not currently exist in the application, and the goals for its implementation were already described above. The lookup method code in this case looks rather straightforward, here it is:

public void lookup()
{
Counter yearCount;
List valueList = new List(Types::String);

for (yearCount = 0; yearCount < 5; yearCount++)
{
valueList.addEnd(strFmt("Year %1", year(SystemDateGet()) - yearCount));
}

SysLookup::lookupList(this, valueList, "List of years");
}

As you can see, the data displayed in this lookup depends on current system state (date) and other data (yearCount). It uses the class List to hold the values to be displayed.

You can download the project (Compatible with Axapta 3.0 – Dynamics AX 2009) with the tutorial and custom list lookup implementation by following the link below:

Note: The xpo contains changes to SysLookup class/form (only usr layer has been exported, for your convenience). Be careful when importing those, and don’t import them into the production environment.

Thursday, April 23, 2009

Be careful with join clauses when writing complex queries

Join clause evaluation is dependent on its position in the sql statement. In SQL Management Studio, if you try to specify the conditions incorrectly, you will receive the following error message:

SQLstatement

In X++, you will not receive any compilation errors, nor any runtime errors. In complex scenarios with a lot of queries, this might go unnoticed, and will be extremely hard to weed out at a later stage, when data inconsistencies crawl in.

Take, as an example, the following job. At first glance, the 2 methods look exactly the same, and it seems as if they should work just fine. But in reality, the second method will return incorrect results, because inventSum.InventDimId will be treated as a constant (empty string as the default value) and not as a table field used in the same select statement.

QueryBuild classes have a major advantage in this situation, as you cannot easily add join clauses (links) unless adding to the child (joined) queryBuildDataSource.

static void JoinClauseWarningJob(Args _args)
{
#define.ItemId("ESB-005")

void testCorrectJoin()
{
InventTable inventTable;
InventSum inventSum;
InventDim inventDim;

select inventTable
where inventTable.ItemId == #ItemId
join inventSum
where inventSum.ItemId == inventTable.ItemId
join inventDim
where inventDim.inventDimId == inventSum.InventDimId;

info(strfmt("Correct join where clause: %1", inventSum.AvailPhysical));
}

void testIncorrectJoin()
{
InventTable inventTable;
InventSum inventSum;
InventDim inventDim;

select inventTable
where inventTable.ItemId == #ItemId
join inventDim
where inventDim.inventDimId == inventSum.InventDimId
join inventSum
where inventSum.ItemId == inventTable.ItemId;

info(strfmt("Incorrect join where clause: %1", inventSum.AvailPhysical));
}
// Actually execute the code
testCorrectJoin();
testIncorrectJoin();
}

So, the suggestion is simple: Use QueryBuild classes (or AOT queries) whenever possible, and pay attention to the order of tables and join clauses in the select statements that you write.

Thursday, January 22, 2009

Microsoft Dynamics Convergence 2009 New Orleans

Well, I cannot start with any statement other than a quote by Steve Ballmer as of today. Of course, most of you have already read this one place or the other:

In light of the further deterioration of global economic conditions, Microsoft announced additional steps to manage costs, including the reduction of headcount-related expenses, vendors and contingent staff, facilities, capital expenditures and marketing. As part of this plan, Microsoft will eliminate up to 5,000 jobs in R&D, marketing, sales, finance, legal, HR, and IT over the next 18 months, including 1,400 jobs today. These initiatives will reduce the company’s annual operating expense run rate by approximately $1.5 billion and reduce fiscal year 2009 capital expenditures by $700 million. ...


Nevertheless, Microsoft Dynamics product line continues to grow, expand the feature set and customer base, and I am very confident it will have great success on the market in the future as well, even in the largest economy recession in many years.

Therefore, I would like to invite all of you to Convergence 2009, taking place March 10-13 in New Orleans, Louisiana, USA.
Microsoft Dynamics Convergence is one of the most exciting events in our business. It is an opportunity to listen to Microsoft plans for Microsoft Dynamics and related products, learn about all the possibilities your company can gain with these products, as well as meet with other business decision makers, Microsoft employees, and industry experts to gain knowledge, increase their understanding of Microsoft Dynamics business management solutions, as well as get some business insights how to thrive in the challenging economy.

Here are some links to get you started:

The
session catalog (containing 225 sessions) is now live on the Convergence marketing site.

The Complete Guide to Convergence for Partners (PartnerSource access is required to access this link) is a valuable planning resource on PartnerSource. There are tips, tools and templates to help partners create the most worthwhile Convergence experience for their company and their customers’ companies.

I hope that many of you will be able to attend, and have a fun time there.