Thursday, November 1, 2012

Querying TFS using Roslyn

Roslyn is an ambitious new project by Microsoft. It is the fully written in .Net replacement of the old compilers used in Visual Studio and should be shipped in a future version of the IDE. The current compilers csc.exe and vbc.exe were first shipped in version 1.0 of .Net more than 10 years ago.

Roslyn offers a lot of new possibilities. As of today Roslyn in still is in CTP and the latest release was in September 2012. For this first post on Roslyn I want to explore the new C# Interactive window (you will need to download and install the CTP for that).

For this demonstration I'll use one of my previous query for LinqPad, Searching in all work items.

First we need to open the C# Interactive window (from menu VIEW -> Other Windows -> C# Interactive)



Then we start by referencing the required libraries using the special #r instruction
> #r "Microsoft.TeamFoundation.Client"
> #r "Microsoft.TeamFoundation.Common"
> #r "Microsoft.TeamFoundation.VersionControl.Client"
> #r "Microsoft.TeamFoundation.WorkItemTracking.Client"

Next we need to import the namespaces we are going to use with the using statement like this
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

Now we are ready to write some real code. I'll be using my online Team Foundation Service account for this. You can register for a free account here.
> var uri = new Uri("https://my.visualstudio.com/DefaultCollection/");

> var tfs = TfsTeamProjectCollectionFactory
    .GetTeamProjectCollection(uri);

> tfs.EnsureAuthenticated();

> var workItemStore = tfs.GetService<WorkItemStore>();

> var title = "phone";

> var query = string.Format(@"
    Select [Id], [Work Item Type], [Title], [State]
    Where [Title] Contains '{0}'
    From WorkItems",
    title);

> var results = workItemStore.Query(query).Cast<WorkItem>()
    .Select(wi => new
    {
        wi.Id,
        wi.AreaPath,
        Type = wi.Type.Name,
        wi.Title,
        wi.State
    })
    .OrderBy(wi => wi.AreaPath).ThenBy(wi => wi.Type).ThenBy(wi => wi.Title);

Of course we don't have access to LinqPad's Dump function so we have to print the results ourself.
> foreach (var r in results)
{
    Console.WriteLine("{0} - {1} [{2}] {3} <{4}>", 
        r.Id, r.AreaPath, r.Type, r.Title, r.State);
}
2 - Project1 [Bug] Bug #1 - Fix the phone number on the Contact page <New>

I think using LinqPad is still easier for this kind of work but those who don't have a paid version of LinqPad will like the facts that Roslyn is free, offers a way to write queries using Intellisense and also a more interactive way to work and find the data you are looking for.