So last week I attended Convergence 2011 in Atlanta to prepare for Dynamics AX 2012.  I attended a few interactive discussions and met some folks that made some rather wild claims that I knew for a fact were wrong.  I advised them that they were probably missing something or there was a problem with their installation / database / or code.

The claim was that there is a 2 or more second authentication delay when logging on to Dynamics Ax from the AIF (and others claimed from the Business Connector as well).  Someone stated that it took them 5 hours to import 30,000 sales orders via the BC.  I import a heck of a lot more data then that on a routine basis and I am confident I could import 30k sales order in less than 2 mins.

The proof that they are wrong.

To prove this I wrote an application that logs on to AX and then off of AX and times the process with the Stopwatch class.  The system running AX is a Dynamics AX 2009 SP1 installation on a Dell i7 920 with 12G of RAM.  AOS, App files, and DB (SQL 2008R2 with 4GB of ram allocated to SQL) all run on the same machine.  So this is a basic low end developer workstation running everything.  Your production servers should run circles around the performance of my test machine.

Here are the results:

I ran the loop to logon and logoff 100 times.  You will see the first call takes 220ms and each subsequent call is at about 14ms.  This is a far cry from the 2,000+ ms claims from the interactive discussion at Convergence.

Start time: 0
sessionId: 5
Stop time: 220
Elapsed time: 220

Start time: 220
sessionId: 6
Stop time: 237
Elapsed time: 17

Start time: 237
sessionId: 7
Stop time: 256
Elapsed time: 19

Start time: 256
sessionId: 8
Stop time: 270
Elapsed time: 14

Start time: 270
sessionId: 9
Stop time: 284
Elapsed time: 14

Start time: 1629
sessionId: 103
Stop time: 1643
Elapsed time: 14

Start time: 1644
sessionId: 104
Stop time: 1658
Elapsed time: 14

What I suspect is that the code these folks are using is very poorly written.  Potentially executing a Refresh() call for each session that is constructed.  If you are running into a performance problem with your AIF or Business Connector code feel free to contact me to help you track it down.  My consulting rates are reasonable :)

The code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Dynamics.BusinessConnectorNet;
using log4net;
 
namespace AxConsoleForTests
{
    class Program
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(Program));
 
        static void Main(string[] args)
        {
            
 
            using (Axapta ax = new Axapta())
            {
                string aosConnString = string.Format("{0}@{1}:{2}",
                    "ceu",
                    "devsql-s-06",
                    "2713");
 
                log.InfoFormat("MyMethodName - Connecting to AX Server: {0}", aosConnString);
                System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                sw.Start();
                long startTime = 0, stopTime = 0;
 
                for (int i = 0; i < 100; i++)
                {
                    try
                    {
                        startTime = sw.ElapsedMilliseconds;
                        Console.WriteLine("Start time: {0}", startTime);
 
                        ax.LogonAs("axTestUser", "",
                            new System.Net.NetworkCredentials
                              ("axTestUser", "password", "devsql.local")
                            ,
                            "ceu", "", aosConnString, "");
 
                        Console.WriteLine("sessionId: {0}", ax.Session());
 
                    }
                    catch (Exception ex)
                    {
                        log.ErrorFormat("MyMethodName - Failure: {0}\r\n{1}", ex.Message, ex);
                        throw ex;
                    }
                    finally
                    {
                        ax.Logoff();
                        stopTime = sw.ElapsedMilliseconds;
 
                        Console.WriteLine("Stop time: {0}", stopTime);
                        Console.WriteLine("Elapsed time: {0}\r\n", stopTime - startTime);
                    }
                }
 
                sw.Stop();
            }
            
            Console.WriteLine("Done");
            Console.ReadLine();
        }
    }
}

In order to thwart any comments that I cheated by placing my loop inside a using statement, I looped outside of it as well and the results are the same.