Tuesday, April 30, 2013

Global File Association on Windows Server 2008 for .axc file extension

In AX 2012 terminal servers (RDSS), users will need to access AX through a .axc file.  By default, windows does not have this file association established to the client executable in the bin folder.  It is unreasonable to have each user go in and manually associate their file when they first go in. 

To avoid this, you would need to globally associate an unknown file extension to program and have that association filter down to all of the users so they can avoid this step.

The below helped me out using group policies.

Social.TechNet.Microsoft.Com: TS 2008 file associations
Applies To: Windows 8, Windows Server 2008 R2, Windows Server 2012
The File Type preference item allows you to create, configure, and delete file name extensions associated with a particular class of files (such as text documents). Additionally, the preference item allows you to associate applications for opening, editing, and other actions as well as icons to file specific file types. Before you create a File Type preference item, you should review the behavior of each type of action possible with the item.

Creating a File Type item

To create a new File Type preference item

  1. Open the Group Policy Management Console . Right-click the Group Policy object (GPO) that should contain the new preference item, and then click Edit .
  2. In the console tree under Computer Configuration , expand the Preferences folder, and then expand the Control Panel Settings folder.
  3. Right-click the Folder Options node, point to New , and select File Type .
  4. In the New File Type Properties dialog box, select an Action for Group Policy to perform. (For more information, see "Actions" in this topic.)
  5. Enter file type settings for Group Policy to configure or remove. (For more information, see "File type settings" in this topic.)
  6. Click the Common tab, configure any options, and then type your comments in the Description box. (For more information, see Configure Common Options.)
  7. Click OK . The new preference item appears in the details pane.

Actions

This type of preference item provides a choice of four actions: Create , Replace , Update , and Delete . The behavior of the preference item varies with the action selected and whether the file type association already

Create  Create a new file type association. If the file name extension in the file type item is registered on the computer, then the new file type association is not created.
Delete Remove an existing file type association. An association exists when the file name extension in the file type item is registered on the computer. No action is performed if the association does not exist.
Replace Delete and recreate the file type association. The net result of the Replace action overwrites all existing settings associated with the file type association. If the file type association does not exist, then the Replace action creates a new file type association.
Update Modify a file type association. The action differs from Replace in that it updates the settings defined within the preference item. All other settings remain as they were previously configured. If the file type association does not exist, then the Update action creates a new file type association.

File type settings

File extension Type the extension of the file to associate with the specified application. Press F3 to display a list of variables from which you can select.
noteNote
You do not need to insert the period before the file name extension.

Associated class Choose from the list of registered classes the one you want to associate with the file type. Press F3 to display a list of variables from which you can select.

Configure class settings

Select Configure class settings to configure advanced class settings.
  • To associate a file icon with the file name extension, type the full path in the Icon file path . Alternatively, you can Browse (…) to the file location. Browsing to the file location automatically populates the Icon Index box.
  • To associate applications for opening, editing, and other actions upon this specific file type, click New . Type the name of the command Windows displays on the shortcut menu and the program Windows launches along with any required specifications. Click OK .

Additional considerations

  • Each subaction configured replaces in full any subaction of the same name that was previously registered under the Associated class. Apart from overwriting a subaction, this item does not support removing subactions, or other items in the Actions list.
  • You can use item-level targeting to change the scope of preference items.
  • Preference items are available only in domain-based GPOs.

Additional references

Friday, April 26, 2013

AX 2012 - How to determine if a hotfix (KB or rollup) is installed on an environment

Sometimes people will ask what hot fixes or roll ups are installed on an AX 2012 machine to determine if an issue can be fixed with a hotfix if its not already installed. 

To check on what all has been applied to the system, in the AX development workspace, navigate to Help and click on 'About Microsoft Dynamics AX'. In the About form, click on 'Show installed models' and check for the hotfix in the form that shows up. For a specific KB, you can filter (Ctrl+G) and run a filter of *KB0023944* or whatever to get that KB. If the KB is part of a roll up, the roll up will show up on here. Check to see if a KB is in a certain rollup, check PartnerSource or CustomerSource for release notes on the hotfix rollups.

Figure 1 - Navigate to Help -> 'About Microsoft Dynamics AX'


Figure 2 - Click on 'Show installed models' and check for hotfix in the form that shows up

Wednesday, April 24, 2013

AX 2012 table not showing all records (aka new feature in AX 2012)

There is a new feature in AX 2012 which only shows records in AX UIs if the current date is between the Valid From and Valid To Date and Time: Valid Time State Tables and Date Effective Data [AX 2012] . It is a property that you can set on a table in the 'ValidTimeStateFieldType'.

This can throw people off coming from previous releases of AX as it will appear some records just flat out don't exist. The records do exist in the SQL DB but the AX kernel filters them out for the user in forms and table browser. If this property doesn't exist for the table you're interested in, you may have bigger issues...

Figure 1 - The 'ValidTimeStateFieldType' table property

Much like the modified and created by/date fields, when this property is set fields are automatically added to the table. In this case, its 'ValidFrom' and 'ValidTo'. These can either be a date alone or UTC if time of day is required.

There is built in validation to make sure that a primary key combination doesn't have any overlapping date and/or time intervals. Basically, there can be multiple records for the primary key with a date/time range which must not have any records overlapping even for a second. This is base and there is nothing the developer can do to override this. If its needed, this should be developed separate and this feature shouldn't be used.

About the properties:
Table Keys: Surrogate, Alternate, Replacement, Primary, and Foreign [AX 2012]
Property Description
AllowDuplicates No means that the combined fields of the index must together make a value in each record which no other record has.
AlternateKey Yes means that other tables can create foreign key relations that reference this key, as an alternative to referencing the primary key.
Indexes with two or more fields cannot have their AlternateKey property value set to Yes.
ValidTimeStateKey A key that is marked as a valid time state key is not a candidate key for child tables to reference in their foreign key relations. Instead, this key is meant for managing date effective data in its own table.
The default is No. This field can be Yes only if the ValidTimeStateFieldType property is Yes on the table. Yes means this key contains the ValidFrom and ValidTo fields.
The ValidTimeStateKey property cannot be set to Yes when the AlternateKey property is set to No.

FYI, in Microsoft Dynamics AX, an AOT node under MyTable > Relations represents a foreign key. For more information, see the previous Relations section in this topic.

Figure 2 - Index properties that need to be set


Sunday, April 21, 2013

AX X++ Break vs Continue actions

In AX X++, there are two keywords that are often confused between one another but do very different things: Break and Continue. Both have their own purpose independent of each other but often people forget. This is a little 101 tutorial.

Break - Breaks out of the loop completely. If there are 10 records to loop over, it will break skip all remaining iterations/records. This is nice when you don't have a need to process the remaining record.

Continue - Forces the next iteration of a loop. The continue statement causes the system to move straight to the next iteration/record of a 'for', 'while', or 'do...while' loop. For 'do' or 'while', the test is executed immediately.

More Info: MSDN: X++ Keywords [AX 2012]

static void daxLoopTest(Args _args)
{
    int i;

    info ("-----BREAK TEST - will attempt to loop 10 times but will hit break on 5");
    for (i=0; i<=10; i++)
    {
        info(strFmt("Loop #%1 - Before", i));

        if (i == 5)
        {
            info (strFmt("Break hit"));
            break;
        }
    }
    
    info ("-----CONTINUE TEST - on odd numbers, continue will be hit");
    for (i=0; i<=10; i++)
    {        
        if (i mod 2)
        {
            info ("Continue Hit");
            continue;   
        }
        
        info(strFmt("Loop #%1 - After", i));
    }
} 

Figure 1 - Infolog from the above code

Friday, April 19, 2013

Get development layer license keys from .axc file

Sometimes you will not be able to access a customer's licenses for their environment for one reason or another. A big thing is attempting to create a new configuration for something like debugging but you will need a layer license. 

As long as you have a working .axc (Axapta Configuration) file going into a layer, you can open that .axc file in notepad and find the license in the 'aolcode' field (see Figure 1 below). The layer can be found in the 'aol' field. 'aol' stands for 'application object layer'.

Figure 1- Inside the .axc with the layer license highlighted

Thursday, April 18, 2013

5 Rules For Rocking The Scruff (Guest blog post by MadeMan.com)

Read the below article and thought it was very good. It's important for people to look their best when they go client site. Used to be that people had to be clean shaving each day wearing at least a tie to work. Times have changed obviously.

You can now wear polos and rock the scruff as long as its done well. Below are some great guidelines for looking sharp. In addition to this, remember the small things like shining your shoes to always put your best foot forward. It's the small things that show someone's attention to detail.

As a reminder, this is my blog to write about things that I think are important that I'd normally put on a OneNote or something for later reference. This blog is an alternative for me to post this stuff publicly so I can reference if later if I accidentally break my computer or point other people to it without having to write an email.

MadeMan.com - 5 Rules For Rocking The Scruff

1. Follow your jaw line
When shaving your neck, be careful not to cut above your jaw line. Instead, use your jaw line as a guide, allowing the hair to wrap underneath it. This will enhance your facial structure and give your stubble a more natural look. Cutting above your jaw line gives the appearance that your cheeks have no beginning or end. Not a good look.
2. Tame your cheeks
If you are going to be consistent with this look, do not allow it to grow wild up the sides of your face. Trim your cheeks down and keep it clean. Imagine a line extending from the sides of your nostrils to your ear lobes. Do not let your stubble grow above that. If you have random black cheek hairs, pluck ’em.
3. Don’t fight your (lack of) follicles
If you’re one of those guys whose facial hair never completely filled in, shave clean. You must have the growth pattern to pull off the scruff, and patches of stubble on your face look unclean and a little creepy. Be honest with yourself if this is a good look for you.
4. Clean up your neck
Unkempt necklines are no good to begin with, but look even more ridiculous if you have manicured facial hair. If you’re going to put all this work into your stubble, make sure you shave your neckline, too.
5. Trim regularly
This is a cool look if you keep it trimmed properly. Wild facial hair becomes a beard, and we are not growing beards here. Every 3 days, trim. The key to this look is to make it look as natural as possible. Ironically, this take a little work, but you’ll realize it’s worth it when you see how good it looks.

Sunday, April 14, 2013

AX 2012 promoting code via XPO when usually doing model store move

Do the below at your own risk. I don't want anyone screwing something up and pointing the finger at me for something I accidentally omitted or something. I've done the process below a ton of times but never just from referencing an article. PRACTICE in a non-PROD environment first...

Occasionally there are small fixes (e.g. hotfixes) that don't need a model store move. It could just be a few lines of code in an existing object like a class or method. If a company usually does a model store move to promote the code, there are usually concerns about changing the usual promotion cadence.

You shouldn't have to worry about this too much as long as the changes will not change any ID values (e.g. creating new tables/fields). I wouldn't do an XPO move when deleting any of those objects either. It shouldn't cause a problem but just to be safe.

From Microsoft TechNet: Models, Layers, and the Model Store [AX 2012]:
"To avoid ID conflicts, we recommend that you do not use xpo export/import to move customizations in environments in which you are primarily relying on importing and exporting models and model stores. "

The above recommendation says to not move an XPO when primarily using model stores but its a very conservative stance. As long as you are confident the XPO move won't change or create any ID values, there should never be an ID conflict.

Steps to promote an XPO code into PROD (very simplistic).
  1. Import the XPO into the code
  2. Save and compile that specific object
  3. Compile the object forward if the object extends and is part of a framework (not doing this could cause your AOS to crash)
  4. Restart all AOS'es
I'll usually recommend doing more when doing a prod promotion like manually merge in the code via the compare tool, backing up the objects being moved, functionally test things afterwards, etc but the above are just the basic essentials.

Friday, April 12, 2013

Compare AX X++ conIns function vs += for container insert

Below is a proof of concept (POC) comparing the 'conIns' function to the '+=' function for inserting records into a container. I know there are a few variables which would make this test not 100% but for a simple POC, this works great to illustrate my point. I made sure to intersperse the two functions between each other to counteract any kind of system load which could possibly kick in which would skew the data.

Use conIns when you need to insert data into a very specific part of the container (e.g. not at the end). If inserting at the end, just use +=.

Note: If you choose to do this on your own, make sure you don't have any breakpoints in or it will screw with the ticks and times will be off thus invalid results.

Results:
Looking at the infolog in Figure 1 below, it took ~2.35 seconds to insert 14,677 records using 'conIns' while it took ~1.67 seconds using '+='.  I've highlighted the outliers in the data that don't seem to conform to any pattern so I believe those were affected by some other process.

From: MSDN: Containers [AX 2012] 

Performance of containers

A container is best suited for processes that do not involve excessive modification to the size or contents of the container. When a container undergoes excessive additions of data, overall system performance can be decreased by the need to repeatedly copy container data and allocate new space.

+= is Faster Than conIns

When you want to build a new container by appending new data, you can use either the += operator or the conIns function. The += operator is the faster alternative. Use the conIns function only when you want to add new data before the last index of the original data.

static void daxTestConInsSpeed(Args _args)
{
    int         i;
    int         j;
    int         tickBegin; 
    int         tickEnd;
    int         totalTicks;
    int         runTestQty = 10;   
    CustTrans   custTrans;
    container   custTransCont;        
    str         conInsertMethod;
    
    for (j=1; j <= runTestQty; j++)
    {       
        // Grab the current 'tick' count in AX
        tickBegin = WinAPIServer::getTickCount();

        // delete the elements in the container
        custTransCont = conDel(custTransCont, 1, i);
        
        // reset the record counter
        i = 0;
        
        // Build the container with data depending on the function we are testing                                
        while select RecId from custTrans           
        {                        
            i++;
            
            if (j mod 2)
            {
                conInsertMethod = '+=';
                custTransCont += custTrans.RecId;
            }
            else
            {
                conInsertMethod = 'conIns';
                custTransCont = conIns(custTransCont, i, custTrans.RecId);
            }                
        }        
    
        // Grab the current 'tick' count
        tickEnd = WinAPIServer::getTickCount();
    
        totalTicks = tickEnd - tickBegin;
        
        info (strFmt("%1 took %2 seconds to process and insert %3 records", conInsertMethod, totalTicks/1000, conLen(custTransCont)));
    }
}

Figure 1 - The infolog from running the code above with highlighted outliers





Wednesday, April 10, 2013

How to: Time how long AX code takes to run in X++ (Performance metrics)

If you need to time some code to see how long something ran and you don't want to use the code profiler, you can do the below using the WinAPIServer::getTickCount();

Pretty simple...

int ticksBegin;
int ticksEnd;
int totalTicks;

int seconds;
int minutes;
int hours;

// Grab the current 'tick' count in AX
ticksBegin = WinAPIServer::getTickCount();
...
ticksEnd = WinAPIServer::getTickCount(); 
   
totalTicks = ticksEnd - ticksBegin;    

// Find the seconds
seconds = totalTicks/1000;
info (strFmt("%1 seconds", seconds));

// Find the minutes
minutes = seconds/60;
info (strFmt("%1 minutes", minutes));

// Find the hours
hours = minutes/60;
info (strFmt("%1 hours", hours));

// This will show the time in hh:mm:ss format except there may be only one value (e.g. hh:m:ss)
info (strFmt("%1:%2:%3", hours, minutes mod 60, seconds mod 60)); 

Sunday, April 7, 2013

How To: Clear or Delete data from an AX container

Using the conDel Function [AX 2012], a user can delete certain elements from a container. When these elements are removed, the numbering in the container will adjust accordingly so that the numbers will always be sequential

There are three parameters container conDel(container container, int start, int number):
  1. container container
    1. the container that the user wishes to have the data deleted from
  2. int start
    1. the spot in the container to start deleting values
      1. If this number is 0, it will not delete anything
      2. The number given will actually be deleted (e.g. 2 will actually include element 2 in the deletion)
  3. int number
    1. the number of elements to delete in the container
      1. If this number is larger than the container, it will delete everything from the start value on
static void daxTestDelContainer(Args _args)
{
    container   test = ['a','b','c','d','e','f','g','h','i']; 
    container   testManip = test;
    int         i; 

       
    info ("BEGIN TEST - the container data in full");
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }        

      
    info ("TEST conDel(testManip, 0, 3) - Remove 3 at spot 0");
    testManip = conDel(testManip, 0, 3);
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }    

    
    info ("TEST conDel(testManip, 1, 3) - Remove 3 at spot 1");    
    testManip = conDel(testManip, 1, 3);
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }

    
    // Reset the container
    testManip = test;    

    
    info ("TEST conDel(testManip, 2, 3) - Remove 3 at spot 2");
    testManip = conDel(testManip, 2, 3);          
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }

    
    // Reset the container
    testManip = test;

    
    info ("TEST conDel(testManip, 3, 5) - Remove 5 at spot 3");
    testManip = conDel(testManip, 3, 5);          
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }

    
    // Reset the container
    testManip = test;

    
    info ("TEST conDel(testManip, 3, 50) - Remove 50 (more than container has) at spot 2");
    testManip = conDel(testManip, 3, 50);          
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }
}
 
Figure 1 - Infolog from the above code
 
 

Thursday, April 4, 2013

C# error: 'Unable to activate Windows Store app... The activation request failed with error 'This app failed to launch because of an issue with its license.'

When building a windows store app in Visual Studio 2012 for Windows 8, I was getting the error 'Unable to activate Windows Store app... The activation request failed with error 'This app failed to launch becuase of an issue with its license. Please try again in a moment. See help for advice on troubleshooting the issue.' (see Figure 1 below)

Resolution: Just a guess but the issue with this seemed to be that while an app is in the development cycle, the licensing will eventually run out on the installed instance. In order to get past this error, you will need to check a box that will uninstall the original project and reinstall it. Do this by right clicking on the project, selecting 'Properties', going to the 'Debug' tab, and selecting the 'Uninstall and then re-install my package. All information about the application state is deleted.' check box (see Figure 2 below).

This fixed the issue for me.

Figure 1 - The error 'This app failed to launch because of an issue with its license'

Figure 2 - The 'Uninstall and then re-install my package' check box

Monday, April 1, 2013

Cycle through container in AX

The below code shows how to cycle though a container in X++ for AX 2012.

Yes I know that the below can be done different. I'm doing things a certain way out of concept and writing it on a plane without a compiler. Also, you could use an array instead of a container since this is a single data type but I'm trying to show containers, not arrays.

I would suggest not using conIns for inserting elements at the end of the container as these inserts seem to get slower the larger the container being inserted into becomes. That's why I use the '+=' seen below.

    int         i;
    CustTrans   custTrans;
    container   custTransCont;    
    

    // Build the container with data
    while select custTrans
       where custTrans.AccountNum == 'CUS00001141'
    {
       // The += is faster than the conIns() function
       //i++;
       //custTransCont = conIns(custTransCont, i, custTrans.RecId);
       custTransCont += custTrans.RecId;
    }

    // Cycle (iterate) through the container
    for (i=1; i <= conlen(custTransCont); i++)
    {
       info(strFmt("%1 - CustTrans RecId: %2", i, conpeek(custTransCont, i)));
    }