Developing and debugging Server Side Event Handlers in TFS 2010


Update 2012-01-23: Added note about .NET framework

Martin Hinshelwood wrote an excellent post recently  http://nakedalm.com/team-foundation-server-2010-event-handling-with-subscribers/ ) about a new type of integration
available in TFS 2010, namely server side event handlers, that is executed within the TFS context. I wasn’t aware of this new feature and as Martin notes, there doesn’t seem to be any material/documentation of it at all.

Previously, when you wanted some custom action to be executed when some event occurs in TFS (check-in, build completed…) you wrote a web/WCF service with a predefined signature and subscribed to the event using bissubscribe.exe.
Usually you want to get more information from TFS than what is available in the event itself so you would have to use the TFS client object model to make new requests back to TFS to get that information.
The deployment of these web services is always a bit of a hassle, especially around security. Also there is no way to affect the event itself, e.g. to stop the event from finishing depending on some condition. This can be done using
server side events.

The deployment of a server side event handler couldn’t be simpler, just drop the assembly containing the event handlers into the Plugins folder of TFS, which is located at 
C:Program FilesMicrosoft Team Foundation Server 2010Application TierWeb ServicesbinPlugins. TFS monitors this directory from any change and will restart itself automatically, so the latest version will
always be executed.

In this first post on this subject, I will describe how to set up your development environment to make it easy to both deploy and debug your event handler. 

  1. Install TFS 2010
    I recommend that you install a local copy of TFS 2010 on your development machine. For this scenario, you only need the Basic version which is a breeze to install. It took me about 10-15 minutes to install and configure it the last time I did it.
    This will make your TFS development and customization much more efficient than using a share remote server, and you can pretty much assault it as much as you want since it is your private server! Ler
  2. Run Visual Studio 2010 as admin
    To be able to deploy your event handler automatically (see next step), you need to run Visual Studio in administration mode
  3. Create the Event Handler project
    To setup the project, create a standard C# class library.
    Note that the project must be .NET 3.5 (or lower), NOT .NET 4.0 since TFS is running on .NET 2.0 it can’t load a .NET 4.0 assembly in the same app domain.

    Martin has written about what you need to reference in his post. Since he was using VB.NET in his sample, I thought that I include a C# version of a minimal WorkItemChanged event handler:

    using System; using System.Diagnostics; using Microsoft.TeamFoundation.Common; using Microsoft.TeamFoundation.Framework.Server; using Microsoft.TeamFoundation.WorkItemTracking.Server; namespace TFSServerEventHandler { public class WorkItemChangedEventHandler : ISubscriber { public Type[] SubscribedTypes() { return new Type[1]{typeof(WorkItemChangedEvent)}; } public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties) { statusCode = 0; properties = null; statusMessage = String.Empty; try { if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent) { WorkItemChangedEvent ev = notificationEventArgs as WorkItemChangedEvent; EventLog.WriteEntry("WorkItemChangedEventHandler", "WorkItem " + ev.WorkItemTitle + " was modified"); } } catch (Exception) { } return EventNotificationStatus.ActionPermitted; } public string Name { get { return "WorkItemChangedEventHandler"; } } public SubscriberPriority Priority { get { return SubscriberPriority.Normal; } } } }

    This event handler doesn’t do enything interesting, but just logs information about the modified work item in the event log.

  4. Deploy your event handler

    Open the project properties and go to the Build tab. Modify the Output Path by browsing to the Plugins directory (see above). This will result in a new

    deployment of your event handler every time you build. Neat! 🙂

    If you look in the Event log after you compile your project, you will see entries from TFS Services that looks like this:

     image


    As you can see, TFS has noticed that a new version of the event handler has been dropped in the plugins folder and therefor it is performing a restart. You will notice that TFS becomes temporarily unavailable while this happens.

    Try modifying a work item and verify that information about it is written in the event log. (Note: You will need to create a event source called “WorkItemChangedEventHandler”, otherwise the EventLog.WriteEntry call will fail.

  5. Debug the event handler

    Since these types of events aren’t very well documented it’s useful to debug the event handlers just to find out how your handler is called and what the parameters contain.

    To do this, to to the Debug menu och select Attach to Process. Check both Show processes from all users and Show processes in all sessions and locate the w3wp process that hosts TFS.

    image

    Select Attach to start the debugging session. Set a break point in the ProcessEvent method and then modify a work item in TFS. This should cause your event handler to be executed immediately:

     

    image

Merging Work Items in TFS 2010

In TFS 2010, branching and merging have been greatly improved with support for branch visualization and tracking of changesets and work items across branches. A simple example of this looks like this:

image       image

Here we track Work Item nr 3 which was originally resovled in the Test branch (with changeset 35). We can also see that the work item has been merged into the Production branch (as changeset 37), back to Main (62) and finally to FeatureC (140).
If we switch to the Timeline view, we get a nice view of the order of these merges, together with the dates.

 

Unfortunately, this does not solve one of the bigger problems when it comes to branches and work items. When you merge your changes into another branch, you must remember to asociated the corresponding work item again, otherwise that information is lost and the work item will not show up in the build report from the builds running off the target branches. A typical example is that we have 3 bugs in the Test branch, and we perform (at least) 3 changesets and each changeset is associated to the corresponding work item. When it is time to merge the bug fixes to the Production branch, we must manually associated the merge with the work item again. If we peform one merge operation that brings all changes from Test to Main, we must associate all 3 work items. There is really no support for “merging” work items across branches in TFS, only changesets can be merged.

What you really want is to have the tool automatically assign the work items that were associated with the changesets that you are merging. One way to implement this is with a checkin policy, which we have done at our company. The reason for choosing a checkin policy as the tool of choice is because it is executed on the client at the time of the checkin, and we can display the work items to the developers before they check in.

So, how does it work? Lets look at an example:

In my development branch, I have 3 bugs (Bug1, Bug2 and Bug3) that I need to fix. I fix each one in a changeset that gets checked in and associated with the corresponding work item. Then it is time to merge the fixes to the Main branch (trunk).
I perform a merge by just using the normal Merge operation from source control. This leaves me with the following pending merge:

clip_image002

 

Now, I would normally go to the Work Items tab and link to the work items that I know were resolved by the changes that I am currently merging. But now I don’t need to do this but instead I just click on the Check In button. This will evaluate all checkin policies, and one of them is the Merge Work Items policy that pops up the following dialog:

clip_image002[5]

This dialog shows me a list of the work items that were associated with the changesets that I am currently merging in. The checkin policy uses the TFS Version Control API to locate the merge sources of each pending merge item and basically shows the union of these work items (several changesets can be associated with the same work item). If I check in now, the changeset will automatically be associated with these 3 work items! The beauty of this comes when running the builds off the Main branch, the build summary show me that these 3 work items have been resolved in this build:

 

image

In another post I will show the interesteing parts of the implementation

Why can’t I see test results in the TFS 2010 Build Report?

In TFS 2010, I have been asked this question several times: I have a build setup with tests and (possibly) code coverage, but in the build summary report it only shows No Test Results and No Code Coverage Results

What’s more interesting is that when I log in and view the build, I can see the test results!

This does of course imply that it is a one of those annoying security issues, and of course it is.
To be able to see test results you must have the View Test Runs permission, which can be assigned/revoked at the security group level per team project:

image

 

So make sure that you set this permission for your developers, if you want them to be able to see the test results (tip: you want that!)