TFS Server-side event handlers

TFS has had an event system since it’s first version, but prior to TFS 2010 that system consisted of SOAP and SMTP events.  For SOAP events, you need to create your own Web Service, then subscribe it to a TFS event using BisSubscribe.exe. 

TFS 2010 introduced a new concept with Server-side event handlers, which use a Plug-in model that allows custom code to execute upon a TFS event, and run under the TFS context.  So the two big advantages here is that you no longer have to deploy a separate SOAP-based web service, and since you are running under the TFS context, you have direct access to the TFS API with much less hops across different processes. 

The solution consists of a .NET Class that implements the Microsoft.TeamFoundation.Framework.Server. ISubscriber interface:

public interface ISubscriber
{
    string Name { get; }
    SubscriberPriority Priority { get; }

    EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties);
    Type[] SubscribedTypes();
}

You implement your custom logic on the ProcessEvent method.  The SubscribedTypes property is used to notify TFS what events you are subscribed to, this is an array so your code can respond to multiple events.  Here is a good list with all available events: http://blog.hinshelwood.com/tfs-event-handler-for-team-foundation-server-2010/.

The notificationEventArgs parameter contains contextual information about what raised the event.  When responding to a Work Item-related event such as WorkItemChangedEvent, the EventArgs contain Core information about the Work Item, including the full list of changed fields.  When responding to a Source Control event such as CheckinNotification, you get access to the ChangeSet.  If additional information is required the TFS API can be used to gather this data.

All logging should be done through the TeamFoundationApplication class, which has “Log” and “LogException” methods. This is important as it will use the TFS context to log information and use the same logging verbosity that is set for the TFS process.  So I would avoid using EventLog.WriteEntry() as your messages wouldn’t be logged as coming from TFS.

The code:  This shows a sample implementation of code responding to a Check-in event:

 

namespace Sample.SourceControl.Server.PlugIns
{
    public class CodeCheckInEventHandler : ISubscriber
    {
        public string Name
        {
            get { return "CodeCheckInEventHandler"; }
        }

        public SubscriberPriority Priority
        {
            get { return SubscriberPriority.Normal; }
        }

        public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out Microsoft.TeamFoundation.Common.ExceptionPropertyCollection properties)
        {
            statusCode = 0;
            properties = null;
            statusMessage = String.Empty;
            try
            {
                if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent)
                {
                    CheckinNotification ev = notificationEventArgs as CheckinNotification;
                    TeamFoundationApplication.Log(string.Format("New Changeset was checked in by {0}. ID: {1}, comments: {2}", ev.ChangesetOwnerName, ev.Changeset, ev.Comment), 123, System.Diagnostics.EventLogEntryType.Information);
                }
            }
            catch (Exception ex)
            {
                TeamFoundationApplication.LogException("Sample.SourceControl.Server.PlugIns.CodeCheckInEventHandler encountered an exception", ex);
            }
            return EventNotificationStatus.ActionPermitted;
        }

        public Type[] SubscribedTypes()
        {
            return new Type[1] { typeof(CheckinNotification) };
        }
    }
}

Deploying your assemblies is really straight forward, you just have to copy them to “%Program Files%\Microsoft Team Foundation Server 2010\Application Tier\Web Services\bin\Plugins” on your TFS Server.  As soon as you deploy the assemblies there, your Application Tier web application will restart and your plugin code will start getting called, so use caution and ideally deploy this to a local copy of TFS of a Test environment first.

Interested in learning more about TFS Customization?  Checkout my Pluralsight course on Team Foundation Server Customization.

Scroll to Top