There is an excellent blog post from Taylor Lafrinere on MSDN that deals specifically with retrieving a list of the team project collections from the Team Foundation Server (TFS) 2010 client API. The blog post references the RTC version of the TFS 2010 API and is dated from January of 2010. However, at the time I found it (April of 2012) the example code worked as expected.In his post he explains how everything in TFS is represented as a node in a node hierarchy that can be visualized like this:
Each node in the hierarchy is represented in code as a CatalogNode that is accessible by way of a TfsConfigurationServerFactory. The TfsConfigurationServer instance that is returned by the TfsConfigurationServerFactory.GetConfigurationServer method exposes the property CatalogNode that represents the root node of the hierarchy (the Team Foundation Server). From here you can call the QueryChildren method that will return a ReadOnlyCollection of type CatalogNode that contains the descendants of the queried node.
Getting to the Root
To get started, we need to connect to TFS. This is done by packaging the address of TFS into a URI instance:
// Set the URI of the Team Foundation Server Uri myUri = new Uri(http://mydomain.com:8080/tfs);
Next, we pass the URI to the static GetConfigurationServer method of a TfsConfigurationServerFactory. This will return a TfsConfigurationServer instance that contains the root node of the address we specified in the URI.
// Get a TfsConfigurationServer instance TfsConfigurationServer configServer = tfsConfigurationServerFactory.GetConfigurationServer(myUri); configServer.EnsureAuthenticated(); // Get the CatalogNode that represents the hierarchy root CatalogNode rootNode = configServer.CatalogNode;
There are a couple of gotchas that you might want to be aware of at this point. First, if you don’t have the appropriate permissions on your account when the TfsConfigurationServerFactory parses the URI to instantiate the TfsConfigurationServer then you can expect a TeamFoundationServerUnauthorizedException to be thrown with a message similar to this:
TF50309: The following account does not have sufficient permissions to complete the operation: userName. The following permissions are needed to perform this operation: View collection-level information.
The other speed bump I hit was if you pass an invalid URI to the factory. You have to make sure that the URI is correct or else the factory will throw a TeamFoundationServiceUnavailableException. This makes sense really since the factory isn’t aware of the TFS instance you’re trying to connect to. So by passing an invalid URI you’re essentially telling the factory to connect to a server that doesn’t exist.
Retrieving Team Project Collections
Once we’ve got an instance of the CatalogNode that represents TFS we can query it and get a ReadOnlyCollection of type CatalogNode that contains the Team Project Collections that descend from the root:
// Get the Team Project Collections that descend from the root node ReadOnlyCollection<CatalogNode> teamProjectCollections = rootNode.QueryChildren( new Guid[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None);
Executing this code should yield a ReadOnlyCollection of type CatalogNode that contains a list of all the Team Project Collections that descend from the root node specified by the URI that was passed to the TfsConfigurationServer factory method.
At this point you can poke around the collection and read project collection metadata, extract nodes for individual collections, and things like that. It’s also at this point that Taylor’s blog post wraps up. This really is an excellent article that fills in the gaps of the MSDN documentation very nicely. Even better, we can extend this example to retrieve the list of projects that descend from any given project collection using exactly the same pattern.
Retrieving Team Projects from a Team Project Collection
Calling the indexer of the ReadOnlyCollection that contains the Team Project Collections will return a specific collection from the list. Like the root node, the Team Project Collection is represented as a CatalogNode that we can query for child Team Projects. First, we need to get a CatalogNode for the Team Project Collection:
// Get a Team Project Collection node CatalogNode teamProjectCollection = teamProjectCollections[0];
Then it’s simply a matter of querying the node. The difference is that instead of specifying a Catalog Resource Type of Project Collection, we’re going to tell the query that we want a Team Project:
// Get the Team Projects that belong to the Team Project Collection ReadOnlyCollection<CatalogNode> teamProjects = teamProjectCollection.QueryChildren( new Guid[] { CatalogResourceTypes.TeamProject }, false, CatalogQueryOptions.None);
Just like the earlier query, we should get a ReadOnlyCollection of type CatalogNode. Only this time the nodes represent individual Team Projects. Again, from here you can explore the Team Projects that were returned in the collection and perform other operations.
Thanks goes to Taylor Lafrinere for posting the original article!