How to connect to TFS from C#

7 Aug

At one point in time I needed some reports from TFS related to the work items that were handled during some sprints. Even though this is possible from Excel (there is a nice integration between these two) my developer ego was hurt by this ideea and I’ve decided to create a little app in C# that connects to TFS. I’ve searched high and I’ve seached low but did not find any full tutorial or at least a working one so the next step is to share with you how you can achieve this.

Step 1 – create a new Visual Studio project

First thing, first thing first, create a new project inside VS (I used VS 2013 since 2015 was not yet released). Initially, for POC purposes, the application was created as desktop application with all the relevant code in it. After few successful tests I’ve moved the code handling TFS communication into a BL and added a new ASP.Net project which acts as the GUI. The Desktop app still works but I’m not planning of using it anymore.

Step 2 – Create the main UI

For the GUI part I’ve decided to use the ASP.Net project type since I’m very familiar with it and because it provides all the tools to create a simple web application very fast (in my humble opinion). After cleaning all the junk that Visual Studio creates (authentications, authorizations, account managing pages, etc.) the only files that remained were default.aspx, global.asax, web.config and Site.Master.

Step 3 – Create a framework for generating reports

Since the reports will be either seen on a web page or sent by email and because theoretically the reports can also be generated by a desktop application, I’ve chosen to put the logic of generating the reports in the ReportingBL and generate them using Razor. Since Razor was designed to work with Web thingies and because the ReportingBL could be used by multiple clients without Web thingies I’ve downloaded a small set of classes from http://www.getcodesamples.com/src/EF734693 which handle the runtime compiling of my templates.

There could be a package you can download from somewhere but I did not bother to find it. This little gem of classes let’s you write code as below but I’m sure you already know about how, why, etc. If not, read here.

Step 4 – Connect to TFS from your app

This is done using the following snippet (I’m not including the variable definition because you can find them easily)

Connect to TFS from C#
  1. public SprintDocumentation(string server, string project, string templatesPath)
  2. {
  3.     tfsServer = new TfsTeamProjectCollection(new Uri(server));
  4.     tfsStore = (WorkItemStore)tfsServer.GetService(typeof(WorkItemStore));
  5.     tfsSProject = tfsStore.Projects[project];
  6.     hyperLinkService = tfsServer.GetService<TswaClientHyperlinkService>();
  7.     teamService = tfsServer.GetService<TfsTeamService>();
  8.     this.templatesPath = templatesPath;
  9. }

 

You will need to add reference

  • Microsoft.TeamFoundation.Client
  • Microsoft.TeamFoundation.Common
  • Microsoft.TeamFoundation.ProjectManagement
  • Microsoft.TeamFoundation.VersionControl.Client
  • Microsoft.TeamFoundation.WorkItemTracking.Client

and the following namespaces imported into you class

Namespaces
  1. using Microsoft.TeamFoundation.Client;
  2. using Microsoft.TeamFoundation.Framework.Client;
  3. using Microsoft.TeamFoundation.Framework.Common;
  4. using Microsoft.TeamFoundation.ProcessConfiguration.Client;
  5. using Microsoft.TeamFoundation.Server;
  6. using Microsoft.TeamFoundation.WorkItemTracking.Client;

 

Step 5 – Get all iterations from TFS

This is done using the following snippet

Get all iterations from TFS
  1. public ProjectIterations GetAllIterations()
  2. {
  3.     ProjectIterations result = new ProjectIterations();
  4.     var configSvc = tfsServer.GetService<TeamSettingsConfigurationService>();
  5.     var configs = configSvc.GetTeamConfigurationsForUser(new[] { tfsSProject.Uri.ToString() });
  6.     ICommonStructureService4 css = tfsServer.GetService<ICommonStructureService4>();
  7.     NodeInfo[] structures = css.ListStructures(tfsSProject.Uri.ToString());
  8.     NodeInfo iterations = structures[0];
  9.     XmlElement iterationTree = css.GetNodesXml(new[] { iterations.Uri }, true);
  10.     BuildIterations(iterationTree.ChildNodes, css, ref result);
  11.     result.Sort((x, y) => y.StartDate.Value.CompareTo(x.StartDate.Value));
  12.     return result;
  13. }
  14. private void BuildIterations(XmlNodeList iterationsTree, ICommonStructureService4 css, ref ProjectIterations iterations)
  15. {
  16.     foreach (XmlNode item in iterationsTree)
  17.     {
  18.         if (item.OuterXml.Contains(„YOUR_TEAM_NAME”))
  19.         {
  20.             var nodeId = GetNodeID(item.OuterXml);
  21.             var nodeInfo = css.GetNode(nodeId);
  22.             if (nodeInfo.StartDate != null && nodeInfo.FinishDate != null)
  23.             {
  24.                 ProjectIteration pi = new ProjectIteration();
  25.                 pi.Name = nodeInfo.Name;
  26.                 pi.StartDate = nodeInfo.StartDate;
  27.                 pi.EndDate = nodeInfo.FinishDate;
  28.                 pi.IterationPath = nodeInfo.Path.Replace(„\\Iteration”, „”).TrimStart(‘\\’);
  29.                 iterations.Add(pi);
  30.             }
  31.             if (item.ChildNodes.Count > 0)
  32.             {
  33.                 BuildIterations(item.ChildNodes, css, ref iterations);
  34.             }
  35.         }
  36.     }
  37. }
  38. private string GetNodeID(string xml)
  39. {
  40.     var first = „NodeID=\””;
  41.     var start = xml.IndexOf(first) + first.Length;
  42.     var end = xml.IndexOf(„\””, start);
  43.     return xml.Substring(start, (end – start));
  44. }

 

There is another way (not parsing an XML) but that method does not return the EndDate which I needed.

Step 6 – Getting the work items by iteration

Getting the work items by iteration
  1. private WorkItemCollection GetWorkItemInfoListForIteration(string iterationPath)
  2. {
  3.     string select = String.Format(„SELECT System.ID FROM workitems WHERE [Iteration Path] = ‘” + iterationPath + „‘”);
  4.     return tfsStore.Query(select);
  5. }

 

The method above return a list of work items which you can transform into your own collection depending on the fields you need.

For the complete code listing of the class that handles TFS connection visit this page. If it helps, say thanks. If not, contact me for more details.

Nu fi egoist, dă mai departe să ajungă la tot poporul

Lasă un răspuns

Acest sit folosește Akismet pentru a reduce spamul. Află cum sunt procesate datele comentariilor tale.