Getting Up and Running with the TFS 2010 Object Model

Editor's Note: The Following is a guest post by Visual Studio ALM MVP Jeff Bramwell

For those of you familiar with Team Foundation Server (TFS), you are no doubt aware that it ships with a great deal of functionality right out of the box.  From work item tracking, to version control, reporting and everything else in between, TFS can handle almost any software development lifecycle (SDLC) methodology.  As extensive as TFS is, you will still, no doubt, run into scenarios that are not inherently covered.  To address these unhandled scenarios, Microsoft has provided broad extensibility throughout the product.  The extensibility points in TFS include the process templates, reports, build automation, and, at a more granular level, the TFS Object Model.  It is the TFS Object Model that we will be digging into in this article.

If you are new to the TFS object model, there are three basic steps that you must take to utilize the TFS object model:

  1. Connect to a TFS configuration server (i.e. a specific TFS instance) or Team Project Collection (TPC).
  2. Determine which TFS services you want to interact with and reference the appropriate assemblies.
  3. Obtain a reference to one or more of these services and write custom code to interact with the services.

Let’s take a look at each of these steps in more detail.

Connecting to TFS

Before connecting to TFS, you must first decide if you need to interact with a specific TPC or with a TFS configuration server (which manages multiple TPCs).  If, for example, you want to modify security settings for a TFS server instance, then you will need to connect to a TFS configuration server.  If you want to retrieve a specific changeset from version control for a specific TPC, then you must first connect to the desired TPC.

The TFS object model provides classes for handling both of these scenarios.  In fact, the methods and functionality provided by these classes are very similar because of a common class hierarchy.  The following diagram illustrates the classes typically used to connect to a TFS configuration server or TPC.

The TfsConnection class provides common methods that apply to TFS configuration servers as well as TPCs such as the ability to get access to the various services provided by TFS.  However, TfsConnection is an abstract class and therefore must be inherited from before it can be used.  TfsConfigurationServer and TfsTeamProjectCollection both inherit from TfsConnection providing concrete classes which can be used to establish a connection to TFS.  TfsConfigurationServer provides specific methods for connecting to a TFS configuration server (as the name implies) whereas TfsTeamProjectCollection provides methods for connecting to and managing a TPC.  We will go into more detail in the examples below.

TFS Services

Once you have made your initial connection to TFS, whether it’s to a TFS configuration server or a TPC, all interaction is handled via the many services provided by the TFS object model.  Some of the services are specific to the type of connection you have whereas others will work with either.  Here is a list of the services provided by TFS 2010 and the type of connection(s) that can be used with them:

For example, if you want to query for a specific work item, you would need to utilize the WorkItemStore service.  Notice that the WorkItemStore service is not available for an instance of TFS since work items are specific to a TPC.  If you want to programmatically manage security, you can use either class since security can be applied at both the configuration server level as well as the TPC level.

Writing the Code

Now that you know about the different types of connections you can make to TFS and the types of services offered, let’s put it all together.

The first step when creating any type of utility that is going to interact with the TFS object model is establishing a connection with TFS (whether it’s with a configuration server or TPC).  With this being such an important step, there are myriad methods and helper classes that can be used to connect to TFS.

A connection to TFS is typically established when creating a new instance of either TfsConfigurationServer or TfsTeamProjectCollection (there are alternatives which are not covered in this article).  As such, the constructors for each of these classes have multiple overloads allowing for various ways to establish a connection.  There are also various helper classes that provide alternative mechanisms for making a connection, some of which provide visual user interfaces.

For example, you can:

  • Connect to TFS simply by providing a uniform resource identifier (URI) to the TFS configuration server or TPC to connect to, depending upon the type of object being instantiated.
  • Connect to TFS by providing an instance of RegisteredConfigurationServer.
  • Use either of the above methods passing in custom network credentials – or prompting the user for their network credentials.
  • Use either of the first two methods above and connect on behalf of another user allowing you to perform actions on their behalf.
  • Connect to TFS using the TfsConfigurationServerFactory.
  • Provide a dialog to the user, via the TeamProjectPicker, allowing them to select which TFS server they want to work with as well as one or more TPCs (depending on how you configure the dialog).

We won’t cover all of these approaches in this article.  However, once you learn one variation it’s fairly simple to implement another variation.

Our First Example

Before writing any code, you must first add the necessary references to our Visual Studio project.  The references you add will directly depend upon the types of services you plan on interacting with.  Most of the required assemblies that you will need to reference are located in the following folder:

32-bit à C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0

64-bit à C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0

To illustrate the process for setting up a connection, let’s create a simple application that will connect to a TFS configuration server as well as a specific TPC.  Follow these steps to get started:

  1. Create a new Visual Studio Windows Forms or WPF application.
  2. Add a reference to Microsoft.TeamFoundation.Client (found in the folder location shown above).
  3. Add a button to your form and double-click it to create the associated Click event handler.
  4. Add the following using statement at the top of your class file:

using Microsoft.TeamFoundation.Client;

5. In the Click event handler, write the following code, replacing the provided URIs with ones specific to your TFS   configuration:

// Connect to an instance of TFS

var tfs = new TfsConfigurationServer(new Uri("https://tfsserver:8080/tfs"));

 

// Connect to a specific TPC

var tpc = new TfsTeamProjectCollection(new Uri(

"https:// tfsserver:8080/tfs/DefaultCollection"));

In these two simple lines you have established a connection to your TFS configuration server as well as a specific TPC (in the example above, the default TPC is used).

Extending the Example

To obtain a reference to one of the many services provided by TFS, call the GetService<T> method provided by the TfsConnection base class where T is the data type for the type of service to retrieve.  Let’s take the above example a step further and do something a little more useful such as querying the work item store.  As you might have guessed, to query the work item store, you will need to make use of the WorkItemStore service.  The following example illustrates the steps necessary to obtain a reference to the work item store reference and how to use that reference to query against the store.

To query the work item store follow these steps:

  1. Add a reference to Microsoft.TeamFoundation.WorkItemTracking.Client (found in the folder location shown above).
  2. Add the following using statement at the top of your class file: using Microsoft.TeamFoundation.WorkItemTracking.Client;
  3. In the same event handler created above, add the following code:

// Line 1: Get a reference to the work item store for the current TPC

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

 

// Line 2: Build our query

var wiql = "SELECT [System.Id], [System.Title] FROM WorkItems WHERE

([System.TeamProject] = 'Demo') ORDER BY [System.Id]";

 

// Line 3: Query the work item store

var workItems = workItemStore.Query(wiql);

 

// Line 4: Display the results

foreach (WorkItem workItem in workItems)

{

Console.WriteLine("{0} - {1}", workItem.Id, workItem.Title);

}

Let’s take a look at this example line-by-line.

Line 1:  Here, we are obtaining a reference to the work item store service provided by TFS.  Specifically, this service only works with TPC references (see Table 1 above).  Once you have obtained this reference, you can interact with the TPC’s work item store performing actions such as querying the stored work items, retrieving a specific work item, deleting work items, and more.

Line 2: For our example to work you must provide a string containing the WIQL (work item query language) query that you wish to execute against the TPC’s work item store.  WIQL is similar in concept to SQL queries that you might run against relational databases such as Microsoft SQL Server.  You use WIQL to specify the work item fields you wish to return, the fields (and conditions) you wish to filter against, and the sort order.  Our example above provides a simple WIQL string that returns two fields (Id and Title) for all work items belonging to the Team Project “Demo” ordering the results by Id.

Line 3: This line is simply invoking the Query method of the WorkItemStore service to execute the provided WIQL query.  This method will return an instance of WorkItemCollection which can be iterated through to retrieve the selected fields for each work item located.

Line 4: This section of code is simply iterating through each of the work items in the results displaying the work item’s ID and Title.  A more elaborate example would most likely be returning more fields and have a more complex filter.

What Next?

This article has only looked at one of the services provided by TFS and has exercised a fraction of that service’s capabilities.  Covering all of the services and their respective features is out of the scope of this article so spend some time exploring the remaining services thinking about how they might apply to everyday scenarios in your development shop.  Although the specifics for each of the services can differ greatly, the basic steps are the same – connect to TFS (a TFS configuration server or TPC), obtain references to the desired service(s), and write the code needed to solve the problem at hand.  Keep in mind that Microsoft’s MSDN forums, documentation and various blogs are your key allies when writing code against any of the services provided by TFS. Check these resources out first when you start coding against a specific
service for the first time.  With a little work, you can extend TFS to achieve results that may not have even been thought about when the product was first conceived or delivered.

Happy coding!

Author's Bio

Jeff Bramwell has over 20 years of software development experience and is currently employed as an Enterprise Applications Architect by Farm Credit Services of America. He has been working with .NET technologies since the early pre-release days (mid 2000) and taught C# at a local university for three years. Having focused on Visual Studio and Team Foundation Server for the past few years, Jeff leads the Omaha Team System User Group and has presented on Visual Studio and Team Foundation Server at the Omaha .NET User Group, the Heartland Developers Conference, Tulsa TechFest, VSLive!, and
others. Jeff is a Microsoft Visual Studio ALM MVP and, as time permits, answers Visual Studio and Team Foundation Server questions in the MSDN forums and makes every attempt to post useful information on his blog at https://devmatter.blogspot.com/. You can follow Jeff on twitter at twitter.com/jbramwell.