Team Members – Customize your IM Address

Last week Brian Harry announced the availability of the TFS 2010 Power tools in one of his blog posts. I had the pleasure to work on the Team Members power tool enhancements for this release which are:

  • Customized Instant Messaging settings – Now Team Members can work even if Active Directory doesn’t have email addresses or, as is the case for many at Microsoft, your IM address is different than your email address.  We added a tab to allow users to customize their Instant Messaging username and address. This enables greater flexibility for integrating with your preferred IM profiles and tools.
  • The ability to launch communicator by double clicking on the identity
  • More async operations (save settings)
  • Improved error handling (now in the output window).

In this blog post, I will explain how did we utilize the TFS Properties Service (a new service that shipped in TFS 2010) to enrich the Team Members power tool and make the “Customized Instant Messaging Settings” feature possible. I will start with a quick overview of the feature in TFS 2010 Power tools compared to TFS 2008 Power tools. I will then give a quick over view of how this feature works under the hood in TFS 2010 and how was this feature enriched using TFS Properties Service.

This is how the team members node look like in team explorer. The team members node basically lists the users you have in the contributor group by default (this can be changed and customized). If you have Office Communicator or MSN Messenger installed on the machine, team members will automatically integrate with your IM to enable you to send IM message from inside VS (by double clicking on the node in 2010 or right click –> send instant message in 2008).

image

In TFS 2008 team members power tool pulled out the IM user name of each node (user) from the information stored in TFS that are synced from Active Directory email addresses. This imposed a limitation on the tool and made it only usable in an environment where your IM address is the same as the email address stored in Active Directory. The IM features of the tool were not enabled other wise. This blocked users that have different IM and Email address.

In TFS 2010 team members power tool we wanted to give the user the ability to publish a custom IM address so that his/her peers can automatically communicate with him via the IM address of preference. To make this possible we needed a centralized repository to store the custom IM address of the user. The centralized repository needed to be accessible by all users. TFS 2010 shipped a new service called the “PropertyService” that can be used by VS or any other third party tools to write generic, queryable data that will be stored in the server DB. The property service allows you to store a key value list of data per artifact (I will show a more detailed example below).

imageIn the 2010 release of the power tool, the user can customize his/her IM address from the personal settings dialog shown above. We used the Property Service to store the custom IM address specified by the user on the server. This custom IM address is stored in the TFS DB using the Property Service and is retrieved by other users when needed. The Property Service enabled us to store custom data out of the box without the need to do any modifications to the server.

TFS Property Service

The Property Service basically provide the capability to store and retrieve a name/value list for each artifact. An artifact can be anything you want to associate data with and is identified by an artifact spec. An artifact spec is composed of three main identifiers (1) Artifact kind (2) Artifact Id or Moniker (3) Version number. TFS 2010 ships with the following artifact kinds out of the box:

Framework : (1) Generic (Can be accessed by methods in Microsoft.TeamFoundation.Framework.Client.IPropertyService)

Version Control : (1) Changeset (2) Versioned Item (3) Pending Change (4) Annotation (Can be accessed by methods in Microsoft.TeamFoundation.VersionControl.Client)

There is a couple of things that you need to decide before making use of the Property Service in any third party tool you are designing:

1- Which artifact kind to use ? For the team members power tool we used the generic artifact kind since the data we are storing were is not related to any of the version control kinds.

2- What is the best moniker ? The moniker is a string value that acts as the identifier of your artifact. First, you need to make sure that the name you chose is unique and will not conflict with a name that can be chosen by someone else later. Second, you need to design your moniker in such a way that you will be able to retrieve all of your custom data in a single server call using wild cards e.g. ToolName_ArtifactName. This will enable you to retrieve all the properties your tool stored on the server by querying “ToolName_*” using a single server call instead of calling the server for every artifact you stored e.g. Artifact1 , Artifact2 etc.

3- Where are you going to store your properties on the instance level or collection level ? The Property Service exists on the instance level and on the collection level, you need to decide where you want to store your data. For team members the data was not related to a specific collection so we stored it on the instance level so that our power tool can access it no matter which collection you are connected to.

Setting TFS Properties

The code snippet below shows how to set a single property on the instance level.

   1: string serverName = @"http://server:8080/tfs/DefaultCollection";
   2:  
   3: TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(new Uri(serverName));
   4:  
   5: // You also need to decide whether you want to store the properties 
   6: // on the Instance level e.g. tfs.ConfigurationServer.GetService<IPropertyService>();
   7: // or on the collection level. 
   8: IPropertyService ps = tfs.GetService<IPropertyService>();
   9:  
  10: // Need to check whether the property service is supported or not 
  11: // because it is not available on older servers
  12:  
  13: ArtifactSpec artifactSpec = new ArtifactSpec(ArtifactKinds.Generic, "TeamMembers_User_General_User1Id", 0);
  14:  
  15: ps.SetProperty(artifactSpec, "TeamMemberPowerToolProperties.InstantMessagingId", "CustomIm@hotmail.com");

Getting TFS Properties

This code snippet shows how to retrieve all properties that match a specific pattern from the server using a single server call.

   1: string serverName = @"http://server:8080/tfs/DefaultCollection";
   2:  
   3: TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(new Uri(serverName));
   4:  
   5: // You also need to decide whether you want to store the properties 
   6: // on the Instance level e.g. tfs.ConfigurationServer.GetService<IPropertyService>();
   7: // or on the collection level. 
   8: IPropertyService ps = tfs.GetService<IPropertyService>();
   9:  
  10: // Need to check whether the property service is supported or not 
  11: // because it is not available on older servers
  12:  
  13: ArtifactSpec artifactSpec = new ArtifactSpec(ArtifactKinds.Generic, "TeamMembers_User_General_*", 0);
  14:  
  15: ArtifactPropertyValue[] values = ps.GetProperties(artifactSpec, null);

I hope this blog post was a good introduction to the Property Service and how can it be utilized to enrich your tools.