Thumbnail image

Read Team Foundation Server Items from Microsoft Dynamics AX 2012 (ALM-V)

!
Warning: This post is over 365 days old. The information may be out of date.

I am briefly returning to one of the longest series of posts on this blog so far: AX 2012 integration with Team Foundation Server, not only for source code control but also as a tool to manage the team’s work. In previous chapters we already saw how to install and configure TFS (this changes between versions, and we also saw that nothing needs to be installed when using the cloud version), and how we can create TFS WorkItems to manage work from that tool.

When performing a code check-in from Microsoft Dynamics AX 2012, AX offers the option to associate that check-in with TFS work items. This is almost mandatory if we want a strong audit trail for why each change is being made, but the tool AX offers is fairly limited. Thanks to the TFS API, however, we can extend it and even build our own tools and reports in AX 2012 by retrieving data from the TFS server itself (yes, also from Visual Studio Online).

One very useful feature that can save a lot of development time is the ability to execute, from AX 2012, queries already stored and used in TFS. This gives us the same views in both environments and makes daily work easier. I will go deeper into this in future posts on the topic, but here is a sample that shows how to do it.

NOTE: For these examples to work, the Visual Studio SDK matching the TFS version we are using must be installed. In my case I use the 2013 SDK because I am working with Visual Studio Online, but this may vary from one environment to another. You can download it here:

After installing the SDK, add the required references into the AOT so AX 2012 can use them:

Now the code:

static void JAEE_TFSPROXY_EjecutarQueryTFS(Args _args)
{
    System.Uri tfsUri = new System.Uri("https:///DefaultCollection");
    str tfsProject = "Libro AX2012";
    str tfsFolder = "My Queries";
    str tfsQuery = "Todas Features";

    Microsoft.TeamFoundation.Client.TfsTeamProjectCollection teamProjectCollection;
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore workItemStore;
    Microsoft.TeamFoundation.WorkItemTracking.Client.ProjectCollection projectCollection;
    Microsoft.TeamFoundation.WorkItemTracking.Client.Project project;
    Microsoft.TeamFoundation.WorkItemTracking.Client.QueryHierarchy projectQueryHierarchy;
    Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder queryFolder;
    Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition queryDefinition;
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemCollection workItemCollection;
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem;
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType workItemType;

    System.Exception ex;
    System.Type workItemStoreType;
    ClrObject parameters;
    ClrObject enumerator;
    str title, state, type;

    setPrefix(strFmt("%1 > %2 > %3", tfsProject, tfsFolder, tfsQuery));

    try
    {
        // Collection
        teamProjectCollection = new Microsoft.TeamFoundation.Client.TfsTeamProjectCollection(tfsUri);
        workItemStoreType = CLRInterop::getType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore');
        workItemStore = teamProjectCollection.GetService(workItemStoreType);
        projectCollection = workItemStore.get_Projects();

        // Project
        project = projectCollection.get_Item(tfsProject);
        projectQueryHierarchy = project.get_QueryHierarchy();

        // Query
        queryFolder = projectQueryHierarchy.get_Item(tfsFolder);
        queryDefinition = queryFolder.get_Item(tfsQuery);

        // Query @Parameters
        parameters = new ClrObject("System.Collections.Generic.Dictionary`2[System.String,System.String]");
        parameters.Add('project', tfsProject);
        
        // Run Query
        workItemCollection = workItemStore.Query(queryDefinition.get_QueryText(), parameters);

        enumerator = workItemCollection.GetEnumerator();
        while (enumerator.MoveNext())
        {
            workItem = enumerator.get_Current();
            workItemType = workItem.get_Type();
            type = workItemType.get_Name();
            title = workItem.get_Title();
            state = workItem.get_State();

            info(strFmt("[%1 > %2] %3", type, state, title));
        }
    }
    catch (Exception::CLRError)
    {
        ex = ClrInterop::getLastException();
        if (ex != null)
        {
            ex = ex.get_InnerException();
            if (ex != null)
                error(ex.ToString());
        }
    }
}

The result looks like this:

Execute TFS stored query from AX

In the following chapters we will continue covering the advantages of using TFS, how to interact with it from AX 2012, and how to keep improving our integration toolset from X++. This code is simplified as much as possible to keep it easy to follow, but there is a lot of useful information here that can be reused for many other tasks. :)

Posts in this series

Related Posts