August 2011

Volume 26 Number 08

Team Foundation Server and Exchange - Build a Ticketing System Using Exchange and Team Foundation Server

By Mohammad Jalloul | August 2011

Team Foundation Server (TFS) provides a great mechanism for creating and managing tickets via its powerful work item tracking functionality. Such tracking is typically accomplished in one of two ways. In the first, a support representative with access to TFS via its Web interface (known as Team System Web Access, or TSWA) creates a custom work item type for a support ticket, entering the necessary details. In the second method, an interface is created to wrap around the work item functionality and simplify access to it for external users who don’t need to know about TFS. The work item is then typically assigned to a software engineer who tracks and manages the work item from within Visual Studio. The goal of both methods is to move ticket creation from e-mail or proprietary database systems to TFS due to its many advantages—in particular that TFS work items have a workflow that defines the lifecycle of a ticket. Anyone can keep track of a ticket by monitoring changes to the work item and viewing the work item history. Integration with the TFS data warehouse provides an added benefit, as you can leverage the powerful reporting capabilities of SQL Server Reporting Services (SSRS) or Excel Services.

Despite such methods, e-mails often get sent around anyway, to further explain the issue or add more detail. This additional e-mail-thread information is sometimes lost, and other times manually copied into the work item history to keep the context of the work item as complete as possible. This manual intervention defeats the purpose of work items and can kill the productivity that work items were designed to provide.

I’ll present a third method in this article that takes the best of both worlds: e-mail and work items. This approach starts with e-mail—just as support reps have been doing for a long time.

Exchange Web Services

The process I’ll present uses the power of Microsoft Exchange Web Services (EWS) to subscribe to notifications for e-mails sent to an Exchange 2007/2010 distribution list. The listening Web service creates a work item based on any new e-mail received. Any subsequent e-mails related to the same thread are appended to the work item history, using the conversation-tracking capabilities of Microsoft Exchange Server, thus mirroring the e-mail thread in the work item. The work item also maintains a workflow. This way the users—the support representatives—are not changing their habits to adapt to a new technology; instead, the technology is taking their process and automating it.

Figure 1 shows how the process will typically flow.

Process Flow for the Support Ticket Work Item

Figure 1 Process Flow for the Support Ticket Work Item

The following explains the flow in more detail:

  1. The flow starts when a support representative is notified of an issue with a product.
  2. The support rep sends an e-mail describing the issue to a distribution list (DL) in Exchange. The DL includes anyone who needs to know about the issue and can assign it to the appropriate developer to resolve it. The DL also contains a “watcher” e-mail account that exists only for notification purposes. The watcher account is registered with Exchange so that it will receive notifications at a specific Web service address.
  3. Exchange processes the e-mail, routing it to all the members of the DL and sending notifications to any Web services that are registered to receive them for a specified e-mail account.
  4. The support ticket Web service receives a notification from Exchange via its Web service interface.
  5. The Web service processes the notification and requests additional information related to the e-mail address. It then creates a Support Request work item in TFS, which is populated with information extracted from the e-mail message.
  6. The DL members also receive the e-mail and they may respond by asking for more information, which the support rep will send. Because the DL is included in the To or CC fields of the e-mail message, the watcher e-mail account is aware of this and the notifications Web service receives notifications of all the e-mails happening in the thread. TFS updates the Support Request work item with the additional information.
  7. The ticket is assigned to a developer using the Assigned To field of the Support Request work item just created.
  8. The developer starts working on the issue, changing the state of the work item to In Progress. When the code containing the fix is reviewed, tested and completed, it will be checked in. The resulting changeset is associated with the Support Request work item. This work item now tracks both the e-mail conversation and the changeset related to the fix.
  9. If the support rep has access to TFS, the Support Request can be assigned to him for closing. Otherwise, the DL can be notified via e-mail. Typically, project managers and leads will set up TFS Alerts so they’re notified when a Support Request work item has been resolved. This takes place when the work item is changed from In Progress to Done.

The process is actually similar to what usually takes place in real-life scenarios involving support issues—except, in real life, the e-mail thread and ticketing system are typically two completely different and separate systems.

The Support Ticket Notifications Web Service

The Support Ticket Notifications Web service uses the EWS Managed API, which lets managed .NET applications communicate with EWS using documented interfaces via familiar SOAP-based messaging. You’ll find a detailed description of the EWS Managed API at bit.ly/jGKRgG.

EWS is not a typical part of a Microsoft Exchange installation, and in many IT setups, it’s installed on a separate Exchange Client Access server. To be usable, the services have to be installed and configured with Microsoft Exchange. You’ll need to obtain the EWS Web service URL from your Exchange administrators, which will look something like https://hostname/EWS/Exchange.asmx. Note that these Web services are typically set up on an SSL endpoint.

The latest version of the EWS Managed API at the time of this writing is 1.1. This version supports Microsoft Exchange Server 2007 SP1 through Exchange Server 2010 SP1. You can download it from www.microsoft.com/en-us/download/details.aspx?id=35371.

By default, the installer copies the files to [Program Files]\Microsoft\Exchange\Web Services\1.1. The API is packaged into a single assembly named Microsoft.Exchange.WebServices.dll. The installation folder includes two important files you should review before starting to work with the API: Readme.htm file and GettingStarted.doc.

The first step in interacting with EWS is to create a Web service to listen to notifications coming from Exchange. Once this Web service is created, it must be registered with Exchange in order to start receiving notifications.

The Microsoft Exchange Server 2010 SP1 Web Services SDK simplifies the creation of such Web services. You can download the October 2010 release (the latest version at the time of this writing) at bit.ly/kZtjLq.

The SDK makes it much easier to build the first Web service. It contains four samples that explore different areas targeted by the API. You can access the samples after installing the SDK by navigating to the Start menu | All Programs | Exchange Server 2010 SP1 Web Services SDK | October 2010 | Exchange Server 2010 SP1 Web Services SDK Sample Directory. The sample that’s of particular interest is PushNotification, which demonstrates a push notifications Web service that listens to and processes incoming notifications from Exchange. This sample also contains a client application you can use to create a subscription in Exchange for the Web service. Using this sample as a base implementation makes it easy to understand the way EWS works and to verify that all the required pieces are functional.

Subscribing with Exchange

You’ll need an Exchange account to create a notifications subscription with Exchange. The subscription will set up the routing such that any e-mails sent to that account’s mailbox will result in Exchange making a call to the notifications service registered for that account. Note that it’s possible to register more than one notification for any given account. In fact, it’s even possible to create more than one subscription for the same Web service endpoint. From an Exchange and EWS perspective, this is perfectly legitimate.

The only requirement for Web services registered with EWS is that they implement a certain interface, INotificationServiceBinding, which has the following signature:

public interface INotificationServiceBinding {

  SendNotificationResultType SendNotification(

    SendNotificationResponseType sendNotification);

}

The only requirement is that the Web service contains an implementation of the SendNotification method. This is the Web method that will be called by Exchange whenever an e-mail matching the subscription attributes is received.

Going back to the PushNotification sample and, in particular, the PushNotificationSubscriber console application, it becomes clear what a subscription entails. Figure 2 shows the SubscribeForPushNotification method taken from the PushNotificationSubscriber.cs file.

Figure 2 Subscription Code from the PushNotification Sample

public static void SubscribeForPushNotifications()

{

  System.Net.ServicePointManager.ServerCertificateValidationCallback =

    delegate(Object obj, X509Certificate certificate, X509Chain chain,

    SslPolicyErrors errors)

  {

      // Replace this line with code to validate server certificate.

      return true; 

  };



  // Create the bindings and set the credentials.

  ExchangeServiceBinding esb = new ExchangeServiceBinding();

  esb.Url = "https://CAS01.contoso.com/EWS/exchange.asmx";

  esb.Credentials = new NetworkCredential("username", "password", "domain");



  // Create a new subscription.

  SubscribeType subscribeRequest = new SubscribeType();

  PushSubscriptionRequestType pushSubscription = 

    new PushSubscriptionRequestType();



  // Subscribe to events in the inbox folder.

  BaseFolderIdType[] folders = new BaseFolderIdType[1];

  DistinguishedFolderIdType folderId = new DistinguishedFolderIdType();

  folderId.Id = DistinguishedFolderIdNameType.inbox;

  folders[0] = folderId;

  pushSubscription.FolderIds = folders;



  // Subscribe to all events.

  NotificationEventTypeType[] eventTypes = 

    new NotificationEventTypeType[6];

  eventTypes[0] = NotificationEventTypeType.NewMailEvent;

  eventTypes[1] = NotificationEventTypeType.CopiedEvent;

  eventTypes[2] = NotificationEventTypeType.CreatedEvent;

  eventTypes[3] = NotificationEventTypeType.DeletedEvent;

  eventTypes[4] = NotificationEventTypeType.ModifiedEvent;

  eventTypes[5] = NotificationEventTypeType.MovedEvent;

  pushSubscription.EventTypes = eventTypes;



  // Receive push notifications every 1 minutes.

  pushSubscription.StatusFrequency = 1;



  // Identify the location of the client Web service.

  pushSubscription.URL = "http://clientWebService/Service.asmx";



  // Form the subscribe request.

  subscribeRequest.Item = pushSubscription;



  // Send the subscribe request and get the response.

  SubscribeResponseType subscribeResponse = 

    esb.Subscribe(subscribeRequest);



  // Check the result.

  if (subscribeResponse.ResponseMessages.Items.Length > 0 &&

    subscribeResponse.ResponseMessages.Items[0].ResponseClass ==

      ResponseClassType.Success)

  {

    SubscribeResponseMessageType subscribeResponseMessage =

      subscribeResponse.ResponseMessages.Items[0] as   

        SubscribeResponseMessageType;



      using (StreamWriter sw = new StreamWriter("MailboxEventLog.txt"))

      {

        sw.WriteLine("Subscribed for Push notifications: {0}", 

          subscribeResponseMessage.SubscriptionId);

      }

  }



  CreateXmlMessageTextFile(subscribeRequest, subscribeResponse);



}

I’ve included the code in Figure 2 here because it illustrates the key features available when registering a subscription. In particular, notice how the sample assigns the first piece of information, the Client Access server URL:

esb.Url = "https://CAS01.contoso.com/EWS/exchange.asmx";

It then uses the credentials of the e-mail account to authenticate with EWS:

esb.Credentials = new NetworkCredential("username", "password", "domain");

Notice also that once you’ve created a subscription object, you can configure it so that it only subscribes to certain events (new mail, copying, moving, deleting, modifying and so on) or to specific mail folders. This provides great flexibility, as you can delegate the filtering to Exchange rather than subscribing to all events and filtering in the application later.

Finally, note the StatusFrequency property. This is a numeric value that defines, in minutes, how often Exchange sends heartbeat calls to the Web service to make sure that the registered endpoint is alive. This helps Exchange cancel subscriptions to endpoints that are no longer valid, such as for a Web service that’s moved to a new host and hence has a new URL. If you forget to unsubscribe before moving the Web service, the subscription can last indefinitely, and Exchange would keep sending notifications unnecessarily to a nonexistent endpoint.

Now let’s look at the customized implementation to support the creation of Support Request TFS work items. The best way to present the functionality is to start with a demo of the Web service and then dive into the implementation.

Deploying the Web Service

The code project that accompanies this article contains only a Web service and several other supporting artifacts. There’s no separate console application to take care of the registration because it’s built into the Web service.

Once built, the Web service can be deployed either from Visual Studio 2010 or by copying the resulting precompiled Web site to a host. You’ll need to manually create the Web application and a corresponding application pool. Set the identity of the application pool to the watcher user account. This is important because the Web service can impersonate the identity of the app pool and use that to perform the subscription. This has two benefits:

  1. The credentials won’t have to be re-entered every time the Web service needs to be reregistered.
  2. The credentials won’t need to be stored where they might be accessible in order to use them to resubscribe.

The Web service needs to have write permissions to two folders: the folder to which it writes logs and the folder it uses as the TFS cache. In addition, you’ll need to configure the following settings in web.config, as they depend on the particular environment where the Web service is used:

  • EWSServiceUrl: The Exchange Service URL; get this URL from the Exchange administrators.
  • TeamFoundationServerUrl: The URL of the TFS project collection where the work items are deployed (for example: http://<servername>:8080/tfs/).
  • WorkItemTeamProject: The name of the TFS Team Project that contains the support ticket work item type (for example: SupportWorkFlow).
  • WorkItemType: The actual name of the support ticket work item type (for example: Support Request). If the work item is renamed or if the Web service is used to support some other work item type (as I’ll show later in this article), you can use this to set the name of the new work item.
  • RequestSupportTeamName: The work item contains a “Request Support Team” field for directing different teams to different support tasks. This is driven by a global list called Teams in the work item definition. To use this feature, keep the field definition and create the global list (instructions are included in the next section of this article, “Configuring the Work Item”) and assign one of the values of the global list to the RequestSupportTeamName configuration key (for example: Customer Service). If not, remove the global list for the field and the “Required” constraint from the work item and leave the value of the RequestSupportTeamName key blank.

At this point the Web service is ready to be used. You can verify it’s set up correctly using IIS Manager on the Web server to navigate to the Web application folder (remember to click on the Content View tab at the bottom if using IIS 7 or later). Then right-click on the Service.asmx file and click on Browse, as shown in Figure 3. You should see a Web page identical to the one shown in Figure 4.

Browsing to the ASMX Page

Figure 3 Browsing to the ASMX Page

Default Web Service URL with localhost as the Host

Figure 4 Default Web Service URL with localhost as the Host

Before you can start using the Web service, you’ll need to import the work item into TFS. This article assumes you’re using TFS 2010, but the same work item and Web service can be used with TFS 2008.

Configuring the Work Item

The sample code for this article (which you can download at code.msdn.microsoft.com/mag201108TFS) contains a sample support ticket work item type called Support Request. In order to view the work item type definition, workflow and layout prior to importing into TFS, you need to install TFS Power Tools, available at bit.ly/hyUNqo. When you install TFS Power Tools, a new menu called Process Editor is added to the Visual Studio IDE under the Tools menu. Double-click on Support Request.xml (located under the Work Item folder in the sample solution). The Work Item Editor window will be loaded with three tabs: Fields, Layout and Workflow, as shown in Figure 5.

Workflow for the Support Ticket Work Item
(click to zoom)

Figure 5 Workflow for the Support Ticket Work Item

The work item Workflow shows the different states that the work item supports: New, when the work item is first created; In Progress, when the issue documented in the work item is actually being worked on; and Done, when work on the issue concludes.

If you decide to configure the Request Support Team field, as discussed earlier, locate the Request Support Team field under the Fields tab, double-click it to open the Field Definition dialog, and then click on the Rules tab. If you don’t plan on using this field, just delete the two rules listed (ALLOWEDVALUES and REQUIRED). If you do want to use the field but would like to configure it to use a different global list, double-click on the ALLOWEDVALUES rule and then on the only entry present: GLOBALLIST: Teams. In the List Item Edit dialog, pick a global list and click OK.

If you don’t have a global list set up yet, you can create one (you’ll need to have TFS Administrator permissions):

  1. In the Visual Studio IDE, go to Tools | Process Editor | Global List and then click on Open Global List from Server.
  2. You’ll be presented with a dialog. Select the Team Project Collection and click on Connect.
  3. In the Global List dialog, right-click on any item and then click on New Global List.
  4. Enter a name for the global list. You can keep the same name as in the work item: Teams.
  5. Right-click the new global list and click on New Item. Repeat this step for as many times as needed to enter the team names.
  6. Click OK to save the new global list.

Note that if you’ve given the new global list a different name, you’ll need to edit the work item and update its definition with the global list name.

At this point, all that’s left is to import the work item into TFS, like so:

  1. In the Visual Studio IDE, go to Tools | Process Editor | Work Item Types and then click on Import WIT (WIT stands for Work Item Type).
  2. Click the Browse button and navigate to the location of the Support Request.xml file.
  3. In the Project to Import to list, click on the name of the TFS Team Project into which you want to import the work item and then click OK.

You can verify that the work item was successfully imported into TFS by right-clicking on the Work Items node for that Team Project from within Team Explorer and then expanding the New Work Item window. You should see Support Request as one of the available options. If you don’t see it there, right-click the Work Items node and then click on Refresh.

Creating a Subscription

As shown in Figure 4, the Web service has three methods: Check Status, SendNotification and Subscribe. The Subscribe Web method is used to create the notification subscriptions.

The subscription process will create a subscription for the user account that’s set as the identity of the Web service App Pool. To use the notifications effectively, that account—the watcher account—should be part of a DL that is to be monitored, as shown in Figure 6.

Adding the Watcher E-mail Account to a Distribution List

Figure 6 Adding the Watcher E-mail Account to a Distribution List

To create a subscription, click on the Subscribe link on the Web page shown in Figure 4. Then click on the Invoke button on the resulting Web page. Upon success, you’ll see a subscription ID. This is also logged into the logs folder defined in the web.config file.

The details of the subscription are logged into two files. The first logs the request sent to EWS to perform the subscription and has the form SubscribeType-<timestamp>.xml. The second file logs the response received from EWS to confirm the subscription, and has the form SubscribeResponseType-<timestamp>.xml. A third file named SubscriberEventLog.txt logs all the events received by the Web service from Exchange, including a heartbeat status event every minute and New Mail events whenever they’re triggered.

The status of the subscription can be verified at any point by calling the CheckStatus Web method, which produces a result similar to that shown in Figure 7, which shows the time the last heartbeat event was received and the status of the Web service subscription. If there’s an active subscription, you’ll see “Status: Subscribed,” as shown in the figure.

Sample Output from the CheckStatus Web Method

Figure 7 Sample Output from the CheckStatus Web Method

The overall process is depicted in the sequence diagram in Figure 8.

The Subscription and Notification Process

Figure 8 The Subscription and Notification Process

Using the Ticketing System

The easiest way to start using the ticketing system is to mimic a real scenario and send an e-mail to the DL that contains the watcher account. Figure 9 shows a sample e-mail to the DL shown in Figure 6, and Figure 10 shows the Support Request work item that’s generated as a result of the notification sent from Exchange to the notifications Web service.

The First E-mail in a Mail Thread

Figure 9 The First E-mail in a Mail Thread

The Work Item Generated as a Result of the First E-mail
(click to zoom)

Figure 10 The Work Item Generated as a Result of the First E-mail

Figure 11 shows the result of sending other e-mails as part of the same e-mail thread and how that’s translated into the work item history. The first thread gets a distinct color for its header. The rest of the threads get another distinct color (yellow in this case, but the colors can be configured in web.config).

The Work Item After a Second E-mail
(click to zoom)

Figure 11 The Work Item After a Second E-mail

Customizing the Code

Now let’s take a look at the different pieces of code that make the system operate. The sample code for this article contains a Visual Studio 2010 solution called Email2Workitem.sln. When you load this solution in Visual Studio, you’ll see that the structure is divided into four solution folders: Diagrams, Subscription Library, Web Service and Work Item.

For the most part, the Web service is based on the PushNotification SDK sample. However, I made some changes in order to keep the solution generic and easy to use. I’ll go over the changes and customizations I made to turn the sample into a ticketing solution.

The first major change is the functionality that lets the subscription process be integrated into the Web service. This is crucial because it allows the Web service to subscribe without having to manage the account credentials. Sometimes the subscription needs to be renewed, such as when the server hosting the Web service undergoes some maintenance activities, for example. When that happens, the App Pools are typically stopped and Exchange cancels the subscriptions because the heartbeat event gets no response. The auto-renewal of the subscription is achieved by calling the InitializeTimer method in the Web service constructor. InitializeTimer, shown in Figure 12, creates a timer with an interval specified in web.config. This timer is responsible for renewing a subscription after service interruptions, for example.

Figure 12 The InitializeTimer Method

private void InitializeTimer()

{

  int autoSubscribeTimeoutThresholdInMinutes = Convert.ToInt32(

    ConfigurationManager.AppSettings["AutoSubscribeTimeoutThresholdInMinutes"]);

 

    lock (_pollingTimerSyncLock)

    {

      if (autoSubscribeTimeoutThresholdInMinutes > 0)

      {

        // Seed the timer with the polling interval specified in config.

        if (_pollingTimer == null)

        {

          TimerCallback timerCallback = OnTimedEvent;

          _pollingTimer = new Threading.Timer(timerCallback, null, 0, 

          _pollingIntervalInMilliseconds); // Enable the timer.

        }

      }

      else

      {

        // Dispose of the timer.

        if (_pollingTimer != null)

        {

          _pollingTimer.Dispose();

          _pollingTimer = null;

        }

      }

    }

}

The second important change has to do with inspecting the incoming message to determine whether it’s the first e-mail in a thread. Figure 13 shows this functionality.

Figure 13 Determining the First E-mail in a Thread

// Get either the folder or item identifier for a 

// create/delete/new mail event.

if (bocet.Item is ItemIdType)

{

  // Get the item identifier.

  ItemIdType itemId = bocet.Item as ItemIdType;

 

  //

  // Get the message using the ItemIdType.

  //

 

  // From web.config

  string ewsServiceUrl = 

    ConfigurationManager.AppSettings["EWSServiceUrl"];

 

  ExchangeService esb = 

    new ExchangeService(ExchangeVersion.Exchange2010);

  esb.Url = new Uri(ewsServiceUrl);

  // From Web service App Pool identity.

  esb.UseDefaultCredentials = true;

 

  EmailMessage message = EmailMessage.Bind(esb, new ItemId(itemId.Id));

  ConvertEmailToRequestItem(message);

}

Notice how the code leverages the fact that the Web service App Pool identity is that of the mail account, which means that Web calls to retrieve the e-mail message details can be done without having to enter any credentials.

The ConvertEmailToRequestItem method does the bulk of the work. To determine whether an e-mail is the first e-mail or part of a thread, it makes use of the ConversationIndex property of the EmailMessage instance. The length of the ConversationIndex 
byte array is 22 when it’s the first e-mail. Subsequent e-mails in a thread get further bytes added to the ConversationIndex. 
ConvertEmailToRequestItem uses this to determine whether to treat the e-mail as a new message and create a new work item for it, or as part of an existing thread, in which case it looks up the existing work item and appends the thread-specific part of the mail message to the work item revision history. Exchange exposes the part of an e-mail that’s specific to the current e-mail in the thread via the EmailMessage UniqueBody property. To get the complete thread, the Body property can be used. This is quite powerful, as it allows building the e-mail thread in the work item revision history, as shown in Figure 11.

One special case that’s worth mentioning is when an e-mail arrives that’s part of a thread but with no corresponding work item available to update. This typically happens if the thread was started before the ticketing system was put in place. In that case, a new work item is created.

In order for the Web service to determine whether an e-mail already exists as a work item, it relies on a piece of information it stores in the work item when the work item is first created: ConversationIndex. The Web service queries work items based on that value to find out whether the work item exists. The querying is performed using the TFS work item query language (WIQL), as in the following code:

private const string QUERY_BY_CONVERSATION_INDEX_WIQL =

  "SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = '{0}'  AND

    [System.WorkItemType] = 'Support Request' AND

    [MsdnMag.SupportTicket.ConversationIndex] = '{1}' ORDER BY [System.Id] desc";

WIQL gives you an easy yet powerful way to query a work item without having to load objects and enumerate through collections.

The Web service also provides a way to easily track it in the TFS activity logs. The TFS activity logs are stored in two SQL Server tables (tbl_Command and tbl_Parameter) in the database for the team project collection. Inspecting the UserAgent column in tbl_Command lets TFS administrators figure out the source of requests.

The notification Web service customizes the user agent data in order to clearly identify it by using the following statement:

TfsConnection.ApplicationName = string.Format(

  TFS_APPLICATIONNAME_TEMPLATE, WindowsIdentity.GetCurrent().Name);

In this particular case, the user agent will look something like “MsdnMagSubscribeSvc – Contoso\JDoe.”

Another potentially useful feature of ConvertEmailToRequestItem is its ability to filter e-mails according to a certain prefix in the subject line, as in the following code:

// First check if prefix-based filtering is turned on, and if so, 

// if the e-mail subject line matches the defined prefix.

string subjectPrefix = 

  ConfigurationManager.AppSettings["SubjectPrefix"];

if (!string.IsNullOrWhiteSpace(subjectPrefix))

{

  if (!title.StartsWith(subjectPrefix, 

    StringComparison.InvariantCultureIgnoreCase))

  {

    WriteEventToLog(

      string.Format(SUBJECT_DOES_NOT_MATCH_PREFIX_TEMPLATE,

      subjectPrefix, title));

 

    return;

  }

}

You can use this feature to restrict the service’s functionality to only certain e-mails; for example, to code review e-mails where the prefix can be defined as “Code Review.”

Other Use Cases: Code Reviews

The use case presented here is a support ticket. However, the flexibility of the approach presented in this article makes it easy to apply the same techniques to other use cases, such as tracking code reviews. The process flow for the code review use case is depicted in Figure 14.

Process Flow for the Code Review Work Item

Figure 14 Process Flow for the Code Review Work Item

Development organizations tend to conduct code reviews via e-mail. There have been many attempts to integrate code reviews into TFS by creating code review work items and building add-ins to allow managing the code review process from within Visual Studio. However, the same technique employed for support tickets can provide an easy way to integrate code review e-mail threads into the TFS work item tracking system. The following steps outline a suggested process for using the notifications infrastructure with code reviews:

  • Start by creating a Code Review work item similar to the Support Request work item.
  • Set up a watcher account in a DL to monitor e-mails sent to the DL.
  • Use the SubjectPrefix feature presented earlier to define a prefix that distinguishes e-mails as code review e-mails. Code review requests sent via e-mail often have the subject line follow this pattern: “Code Review: My-Shelveset-Name.”

As shown in Figure 14, associating the actual check-in of the shelveset contents with the work item provides traceability into the lifetime of the code from when the code was done, when it was sent for code review, when it was approved for check-in and, finally, to when it was checked in. This association is a powerful feature of TFS that provides great visibility into any code that gets checked in via source control. It’s an especially useful asset for organizations that require traceability for audit reasons.

What Next

The key goal of this article was to demonstrate one of the many possibilities for using TFS and Exchange together to increase both productivity and efficiency. One of the great things about work items, especially in TFS 2010, is how they’re integrated inside TFS. Work items can be linked to changesets. They can represent and track test plans. They can be easily reported on, using Excel or SSRS, and they can also be synchronized with Microsoft Project.

Armed with the use case and techniques presented in this article, you should be able to leverage the notifications Web service and the work item customizations in many other scenarios that are particular to your own environment.     


Mohammad Jalloul is a software engineer at Myspace Inc., a social entertainment Web site where he’s responsible for integrating TFS into the different business processes and leveraging it to increase efficiency and productivity. Prior to that, he worked in Redmond in the Developer Division at Microsoft on an internal tool called Gibraltar.

Thanks to the following technical expert for reviewing this article: Bill Heys