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.

About esteban

Esteban is the Founder and Chief Technologist at Nebbia Technology, an ALM consulting and Azure-powered technology company. He is a software developer with a passion for ALM, TFS, Azure, and software development best practices. Esteban is a Microsoft Visual Studio ALM MVP and ALM Ranger, Pluralsight author, and the president of ONETUG (Orlando .NET User Group).

4 thoughts on “TFS 2010 Dashboards with SharePoint 2010 (MOSS)

  1. Jose Medero

    Hi Esteban, i am working on integrating my company’s TFS 2010 with a SharePoint 2010 portal. I have been looking that several blogs shows that when the configuration is done they get several dashboards. In my case the only dashboard that was created was “My Dashboard”. Wath do I need to get other dashboards like the ones mentioned in your article.

    I am working on a sharepoint 2010 farm single server test enviroment with my production TFS 2010. My configuration goes as follows:
    – TFS 2010 Standard
    – SharePoint 2010 Enterprise
    – Sql 2008 r2 Enterprise with Report Server in Integrated Mode.
    – SP has been integrated with reporting services.

  2. Esteban Garcia

    Jose,
    Do you see any errors in the Team Project creation log? I seem to remember running into this before, and I think it had to do with permissions during the creation of the Team Project, but I may be mistaken. Can you take a look at your log file and let me know?

  3. Bob Cronin

    I know this is an old post Esteban, but it saved me today. Thanks for publishing!

  4. Anurag Jain

    Hi Esteban, Thanks for this nice explanation, But i do have some other requirement.
    Lest say if we have WorkItemLinkFilters LinkType=”System.LinkTypes.Hierarchy” then WorkItemTypeFilters should be “Task” and if we have WorkItemLinkFilters LinkType=”System.LinkTypes.Hierarchy” then WorkItemTypeFilters should be “child” only. Is it possible to achieve ?


Leave a Reply

Your email address will not be published. Required fields are marked *

Are you human? *