Skip to content

Console output from Dynamics AX

Although Dynamics AX offers a whole range of options to call application logic (e.g. Business Connector or WCF), it’s often necessary to use the client (ax32.exe) directly from command line. That applies especially to administration and development – automated configuration, compilation, update of cross references and so on.

Unfortunately ax32.exe doesn’t return any console output, therefore it’s difficult to find out whether everything works or something failed. That’s a problem especially for automated scripts because they can’t look into GUI to learn what’s happening.

One possible approach is to write status information from Dynamics AX to a log (file, EventLog) and analyze them afterwards, but recording to console has many advantages – output is clearly bound to a concrete process and command, it’s not needed to manage access to external logs, console can further process the output easily (including redirection to file) and so on.

Console output can be easily writen to by .NET class System.Console so let’s create an X++ class calling System.Console through a very simplified interface.

class SysConsole
{
    public static void writeLine(str _message)
    {
        ;
        System.Console::WriteLine(_message);
    }
    public static void writeErrorLine(str _message)
    {
        System.IO.TextWriter writer = System.Console::get_Error();
        ;
        writer.WriteLine(_message);
        writer.Close();
    }
}

Then messages may be sent to console output simply be calling these methods, as shown in the following test job:

SysConsole::writeLine("First!");
SysConsole::writeLine("Another message");
SysConsole::writeErrorLine("Something is wrong");

If you start Dynamics AX client from command line and the test job afterwards, unfortunately nothing will happen. It’s necessary to use a bit more complicated approach.

The first problem is that command line doesn’t wait for program output, it just runs the program and continues with subsequent commands. But mere waiting for program to end, as in the following Powershell script, still shows nothing.

Start-Process ax32.exe -Wait

But if you redirect output and error streams to files, they’re written correctly.

Start-Process ax32.exe -Wait -RedirectStandardOutput c:\Temp\out.txt -RedirectStandardError c:\Temp\error.txt

So the output can be obtained and that’s the most important news. In some cases the simple recording to file is suitable (compared with writing directly from AX, this allows the caller to define file names) but it still isn’t “normal” console output.

In the next attempt we’re going to create a process directly by .NET class System.Diagnostics.Process, redirect the output and read it from process properties:

$process = New-Object System.Diagnostics.Process
$process.StartInfo.FileName = 'C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin\ax32.exe'
$process.StartInfo.UseShellExecute = $false
$process.StartInfo.RedirectStandardOutput = $true
$process.StartInfo.RedirectStandardError = $true
 
$process.Start() | Out-Null
$process.WaitForExit()
 
Write-Host $process.StandardOutput.ReadToEnd()
Write-Host $process.StandardError.ReadToEnd() -ForegroundColor Red
 
$process.Close()

That really displays output of our test job in console:

But this solution still has some shortcomings, especially that the output is shown only after the process ended. That’s sufficient to display final results, but not for any indication of progress.

C# offers quite straightforward solution by means of events OutputDataReceived and ErrorDataReceived – see the following simple console application.

class Program
{
    static void Main(string[] args)
    {
        new Program().Run();
    }
 
    void Run()
    {
        string file = @"c:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin\ax32.exe";
 
        using (Process ax = new Process())
        {
            ax.StartInfo.FileName = file;
            ax.StartInfo.UseShellExecute = false;
            ax.StartInfo.RedirectStandardOutput = true;
            ax.StartInfo.RedirectStandardError = true;
            ax.OutputDataReceived += new DataReceivedEventHandler(outputDataReceived);
            ax.ErrorDataReceived += new DataReceivedEventHandler(errorDataReceived);
            ax.Start();
 
            ax.BeginOutputReadLine();
            ax.BeginErrorReadLine();
            ax.WaitForExit();
        }
        Console.ReadLine();
    }
    private void outputDataReceived(object sender, DataReceivedEventArgs e)
    {
        if (!String.IsNullOrEmpty(e.Data))
        {
            Console.WriteLine(e.Data);
        }
    }
    private void errorDataReceived(object sender, DataReceivedEventArgs e)
    {
        if (!String.IsNullOrEmpty(e.Data))
        {
            Console.WriteLine("Error: {0}", e.Data);
        }
    }
}

Although Powershell allows us to handle the same events, I had to choose a slightly more complicated solution.

$process = New-Object System.Diagnostics.Process
$process.StartInfo.FileName = "ax32.exe"
$process.StartInfo.UseShellExecute = $false
$process.StartInfo.RedirectStandardOutput = $true
$process.StartInfo.RedirectStandardError = $true
 
Register-ObjectEvent -InputObject $process -EventName OutputDataReceived -SourceIdentifier AxOutput
Register-ObjectEvent -InputObject $process -EventName ErrorDataReceived -SourceIdentifier AxError
 
$process.Start() | Out-Null
$process.BeginOutputReadLine()
$process.BeginErrorReadLine()
 
Function GetAxMessages
{
    Get-Event -SourceIdentifier AxOutput -ErrorAction SilentlyContinue | %{
        if ($_.SourceEventArgs.Data)
        {
            $_.SourceEventArgs.Data
        }
        Remove-Event -EventIdentifier $_.EventIdentifier
    }
 
    Get-Event -SourceIdentifier AxError -ErrorAction SilentlyContinue | %{
        if ($_.SourceEventArgs.Data)
        {
            Write-Error $_.SourceEventArgs.Data
        }
        Remove-Event -EventIdentifier $_.EventIdentifier
    }
}
 
while (!$process.WaitForExit(1000))
{
    GetAxMessages
}
 
$process.WaitForExit()
$process.Close()

The scripts starts ax32.exe, subscribe to RedirectStandardOutput and RedirectStandardError events and handle newly added events every second. Maybe it could be written simpler, anyway it does exactly what I need and that’s the main thing. All messages written from AX to output or error stream are caught and – with slight delay – sent to Powershell console. Errors are written by Write-Error so they may be handled in the usual way (e.g. to use -ErrorAction Stop parameter to stop on first error).

The Powershell code mentioned above is surely nothing what you would like to type manually to console. Fortunately I’ve already managed to integrate it to DynamicsAxCommunity module, so the only thing you have to do is to call Start-AXClient with -Wait parameter. (Download the latest version from repository, it’s not yet in any release.)

Console output may be utilized in many different ways – automated scripts can get messages from Dynamics AX, you can show progress of long-running processes (e.g. compilation) or debug messages, anything you like.

You can even send all errors from Dynamics AX to the error stream (i.e. call SysConsole::writeErrorLine() from Info.add()). If an error occurs, the calling scripts get info and can react somehow. Without capturing errors (in console or somehow else), Dynamics AX client would just continue to run or it would (as in the following example) ends without any indication of error.

Just in case – note that Dynamics AX normally doesn’t write anything to console (as far as I know) nor DynamicsAxCommunity contains any such code. Class SysConsole is not part of Dynamics AX as well. To make the example from the previous picture work, you have to implement calls in Dynamics AX yourself.

Quality is a process

One part of my work on all projects since I left my first employer in Dynamics AX world was to improve quality of software products. That’s not by coincidence – it’s because I want to make high-quality software and to help companies to do it.

High quality is good for everybody – it has obvious advantages for users, but it’s good for us as well – we don’t have to waste so much time with support, debugging, bug fix development, deployment and so on and we can concentrate on development of new features (that’s our real job, isn’t it?). And of course, satisfied customers are more likely to give us more work and recommend us to their business partners.

All those companies I worked for felt that quality of their products is not very high, or at least felt that it is good to talk about quality. Whether quality was really their priority would be another story; now I want to point out the overall expectation about how to improve quality. To quote a certain manager:

“You want to change a process? We thought you would just fix something in code.”

This helped me a lot to understand how some people view software quality improvements – “code is bad, go to code, fix the code”.

Try to think about it a while. Quality of our software is low, because we didn’t get requirements right, because we designed suboptimal solution, because our code is not handling many border situations, because our GUI is not intuitive and so on. Sure, all these things can be fixed, in theory – we can redesign features, we can change technical architecture, we can rewrite code. That can be extremely expensive and actually the activities are the same as what we’d done originally – and we failed. Will it be better this time? And if we want just to review code and change it a little, how will we fix what our software does by design?

What we deliver to customers is a mere output of the whole process of making software. All these analysis of requirements, GUI designs, database designs, object modeling etc. are defining the product and their quality will be reflected in the quality of the product. If our software ignores important requirements, it can’t be good. If our developers don’t know how to work with exceptions, the whole product won’t handle exception correctly. And so on.

Can we just look into code and turn such software into a high-quality one? Obviously, it’s impossible. We don’t know what are the omitted requirements by looking into code. It requires a new and better collection of requirements. We also can’t simply add a better exception handling – we need to make better analysis of possible exceptional situations and how to handle them. We should have done it better at first.

If people say that quality of their software is low, it automatically means that quality of their procedures is low. Their process generates low-quality software. Unless the broken part(s) is fixed, the process will continue to generate similar results.

What development teams really need is not somebody coming and fixing their bad code. They need to think about how they work and whether all procedures are good enough. They need to identify sources of their problems and try to change procedures to avoid repeating the same problem again. They must realize that it’s not just about coding, and think about quality of requirements, designs etc. Without all these things, people can’t expect any real change in quality.

By the way, this is one of things where iterative procedures really excel – you go through all project phases every iteration, so you see whether functional designs are good enough for development, whether it’s easy to add new features to the code base, what people think about GUI… And if something seems to go wrong, you can adjust the process and see whether it’s better in the immediate iteration.

Included columns in Dynamics AX 2012

Included columns is a feature of SQL Server (since version 2005) related to indices.Thanks to it you can attach additional fields to an index that are not used for searching (so they don’t have to be maintained so expensively) but that can be used by database server to return data. If all columns being returned by a query are included in an index, database server can directly return data and it doesn’t have to touch the table itself (and that saves time, of course).

Included columns also have additional advantages:

  • can be added to a unique index without influencing uniqueness
  • support even (some) types that can’t be used in normal indices
  • don’t count to the limit of number of index columns  (16)
  • don’t count to the limit of index size (900 bytes)

The following (logical) restriction apply:

  • are always at the end of index
  • the index must contain at least one “normal” (key) column
  • can’t be used in clustered indices

Of course, even included columns have impact to index size so they can slow donw operations with the index and consume disk space.

Support in Dynamics AX 2012

Creating an included column in AX2012 is very simple. Add a field to an index in the same way as usual and then change IncludedColumns property of the index column to Yes.

The image shows a concrete example in AX2012 – index TransIdIx on table CustInvoiceTrans. It has three “normal” fields useful for searching and two additional fields (Qty a QtyPhysical) to cover some queries for these fields.

In the similar way you can extend even unique indices, including primary keys. For example, you can create an index with a unique field Id and attach a field Name that you often ask for. Such an index can be still assigned as primary (it couldn’t be, if the second field was not an included column), nevertheless you can’t use it as ClusterIndex.

Although AX allows you to switch IncludedColumn property on any field, any invalid configuration is naturally refused by SQL Server during synchronization.

Reflection

You may also benefit from support for included columns for reflection. You might want, for example, to list details of all indices in your module. You can use the following methods in DictIndex class:

  • int numberOfIncludedColumns()
  • FieldId includedColumns(int _inclColumnIdx)

I’ve found a problem here with the automatically generated RecId index. It’s also visible in the following image – AX returns correct number of included columns for other indices (1 and 0), but 35888 included columns in RecId index is palpable nonsense. Moreover every run returns different value – it looks like if AX reads a wrong memory address – but who knows?

Included columns are surely worth using – without them, you either have to do without covering some queries, or to make full-blown (and expensively maintained) indices. Sometimes included columns can help you to even reduce the number of needed indices.

But is doesn’t mean that you can begin to mindlessly add columns to indices – maintenance of included columns has its costs too.

Team Foundation Build – Process template

As I mentioned in Slight introduction to Team Foundation Build 2010, individual build actions and their sequence are defined in a process template. That’s based on Windows Workflow Foundation 4.0, so it’s basically a text-based XAML file. But primarily there is a visual designer integrated to Visual Studio allowing you to define a process by simple dragging actions to the editor and setting some parameters.

Functionality related to builds, including process templates, is accessible from Team Explorer (node Builds in a team project). A new build definition can be launched by the New Build Definition option.

It opens a dialog where many useful parameters can be set, but in this moment the relevant thing is the Process tab and the Default process template section in its top part.


After Show details was clicked, you’ll see a combo box with a selection from existing templates and (among other things) the New button for creating a new template and a path to a template file.


You can see here that templates are saved to version control – Team Foundation Build can easily access them there.

After clicking the New button, a dialog is shown where you can choose the base template for the newly created one, the name of a new template and so on.


A new template file is created in background and set as the default in the the build definition dialog. By clicking the link you’re navigated to the template file in Source Control Explorer:

Doubleclick on the file opens the template in a designer integrated to Visual Studio. Because we built our template upon an existing one, the editor already shows a process definition.

Existing actions can be configured – simply click an action and adjust its properties in the Properties window:

or in some cases directly in the designer.


As you can see, many places allow you to write code (VB.NET) so you’re not limited by some predefined set of actions and operators. (We will look at variables in some future post.)

New actions can be simply dragged from Toolbox – either to a space reserved in some activity, e.g. in a conditional block:

or onto one of small triangles that are in many places in the default template:

These triangles are in fact a part of activity Sequence. Sequence is important, because for instance in the previous example, you can assign only a single action to If. If you need more actions, e.g. to create a folder and download files, you have to first drag Sequence to If and only then additional activities.

There are many activities and control structures available (and you can even define your own), just few of them for an illustration:

  • ForEach – iterates though a collection and runs an action for each element
  • TryCatch – error handling by the classic Try/Catch/Finally pattern
  • LabelWorkspace – create a label in version control
  • InvokeProcess – runs a command in command line

The description of predefine activities is available on MSDN.

Slight introduction to Team Foundation Build 2010

Team Foundation Build is part of Team Foundation Server used to automatedly build applications. Typically, such a build gets latest versions of source code and all referenced components, compiles the application, runs tests, creates an installer and so on. It’s also able to log and report build results, assign build number to work items included in the build and much more. Builds can be run manually, as night builds, after every modification and the like.

The purpose of builds is obvious – it verifies that all parts fit together and prepares the application to an executable form so it could be tested or distributed. And because applications are composed of many components (often made by different teams or even companies), the build of all parts in right versions is not a trivial task. It often requires many steps and a lot of time.

Here is the meaning of automation – as soon as the process is automated (and tested), the complicated and error-prone manual work is not needed any more. Time-intensiveness is not a significant problem either, because when automated, a build costs you computing time only while people can engage in work that really calls for a human effort. And without automation, you would never reach sufficiently frequent builds so you may not identify problems soon enough

Because this blog is mostly about Dynamics AX, imagine that you want to prepare a test environment of Dynamics AX. You have to obtain current version of X++ code and (code of) any other components (e.g. external DLL libraries), deploy it (and, depending on AX version, also handle labels, indexes etc.), compile the application, synchronize database, update reports etc. etc. Many steps, a lot of room for mistakes, duration – at least one hour. Automation solves it all and Team Foundation Build provides an ideal infrastructure, although it’s not prepared explicitly for Dynamics AX.

Deployment of Team Foundation Build 2010

Simply put, Team Foundation Build is composed of a build controller that controls the building process and one or more build agents that carry out individual operations. You need at least one build controller and one build agent.

Team Foundation Build can be installed from Team Foundation Server installation medium. If default configuration (one agent, all on a single machine etc.) suits you, it’s enough just to assign a TFS project collection. In a real deployment, you would probably want to do more planning ragarding performance, security, software available to individual build agents and so on.

Build definition is composed of a process template and concrete parameters. The template is based on Windows Workflow Foundation 4.0 – that allows you to easily define the process flow including conditional blocks, loops, parallel processing and so on. Moreover, you can use the graphical editor (see the picture below) and several ways how to create your own building blocks.

Build Template Editor

Default templates are – understandably – prepared for classic .NET applications – for Dynamics AX or other atypical scenarios, you have to modify a template. Fortunately, that’s something Team Foundation Build count with and possibilities of configuration and extending are very wide.

Usage

Functions related to builds are accessible directly from Team Explorer:

Team Explorer - Build context menu

In build definition, you can set basic parameters, e.g. automatic start of builds.

Build definition - Triggers

Build Explorer shows planned and executed builds:

Build Explorer

You can also display detailed information about each build:

Failed build details

Results can be sent to you by e-mail, you can use prepared reports, a failed build can automatically create a work item for fixing etc. The integration with work items also allows you to track in which build a bug was found or fixed, to analyze which tests should be run for a build, to document content of a build (work items, files) and so on and so on.

Conclusion

Thanks to Team Foundation Build, a build process can be much simpler, more unified and more scalable than if using ad hoc scripts. Process templates based on Windows Workflow Foundation allow to easily modify the whole process and the integration with other parts of TFS offers a range of unique opportunities.

It’s understandable that while adopting Team Foundation Server, emphasis is put on work item tracking and source code management. Even so I find Team Foundation Build rather unfairly neglected. At the same time, development teams waste time with manual builds, writing up changed objects, searching for “where the bug was fixed” and so on, often with rather dismal quality. Team Foundation Build is one of ways how to improve quality and spare time (and money) in the same time.