TFS Event Handler in .NET 3.5 Part 2 – Handling Team Foundation Server Events

I have decided to have a little go at creating a Team Foundation Server Event Handler in .NET 3.5 that is resilient and scaleable. I will be using as many of the features of Team Suit as I can, but bear with me as there are a few things that are new to me.

TFS Event Handler in .NET 3.5 Articles

  1. TFS Event Handler in .NET 3.5 Part 3 – Passing the events over a Windows Communication Foundation MSMQ (Coming soon)
  2. TFS Event Handler in .NET 3.5 Part 4 – Workflow (Coming soon)

Handling Team Foundation Server Events

Because of the lack of support for Windows Communication Foundation in the Team Edition for Architects I will be replacing all of the auto-generated services with Windows Communication Foundation services. But as it turns out this messes up everything, so I have started from scratch and I will post all of the code for doing this without the Architect bit.

The first thing that you need is the Contract for Team Foundation Server event handling. This is very specific and only works if used accurately:

This code allows you to capture TFS events and we will be using by reference only. If you have been having trouble handling the events then look know further than here for Windows Communication Foundation as this has been tried and tested.

The real trick for handling TFS events in Windows Communication Foundation is that all the events come into the same routine. It would be nice if SubscriptionInfo listed what event it was, but alas it does not. So you may be thinking that you need to parse the XML and find out what type of event it is. Well you can if you want, but I find it easer to have more than one endpoint for the same service. You can then parse the URL for the event type, which is way easier than the XML as the events are all different.

The first thing you need to do is create a project to hold the code. In the spirit of expedition, I have created a “Windows Communication Foundation Service Application” to hold all of the Notification service code. But in the real world you would keep the Contract and Implementation classes in different assemblies.

image

Now we have the project, you can add the INotification class and the Notification service. I like to keep all of my services in a “v1.0” so that I can add other services in new versions without affecting the current version.

image

Once you have your INotification class looking like the code extract above we will add a default implementation and test the service. The default implementation should look like:

This class just implements the INotification contract (interface) and has an empty Sub for the notify method that will be called when an event is fired in TFS.

The config file will contain a definition of the service as well as two endpoints for the same interface. The services and behaviours occur within the <system.serviceModel> tags.

This is the really important part of getting the service working, and goes between the <services> tags. The first part of the service configuration contains the service definition. Here we define the name of the service, which should be the same as full namespace and class name of out implementation, the behavior configuration name (we will look at this is a bit) and the endpoints.

In a service hosted within IIS there is no need to set a base address as the location of the .svc file sets this for us. In this case it is http://localhost:[port]/v1.0/Notification.svc. The “mex” endpoint allows other application to discover the capabilities of the service.

The other two endpoint point at the same contract and are in fact implemented by the same method in the service implementation. These two endpoints have different addressed so that we can tell team server to send events to different URL’s but use the same code to process the events. You could add any of the TFS events in to this list of end points, but it is best to keep the names the same as the event being fired as we will detect it later. We are using the wsHttpBinding as the most advanced that TFS will support.

You only need to set two options on the service behavior, the httpGetEnabled needs to be set to true for the WSDL and the meta data to work. This allows the discoverability of you services. The includeExceptionDetailInFaults option allows the diagnosis of faults when we test the service.

The service behaviors go between the <behaviors> tags and are named the same as the services behaviorConfiguration attribute.

We now have a working service and can test it by starting a new instance of the web application and going to the URL of the .svc file. You will see a page like:

image

This shows you how you can connect to the service, but as this will only be connected to by TFS it is not a requirement for just now. What is important is to see the URL’s for the two endpoints that we have created. If you click the WSDL URL (“http://localhost:65469/v1.0/Notification.svc?wsdl“) you will see the generated meta data for the service.

I am not going to display the full WSDL here as it is huge, but here is the important section for what we need to look at:

This section of the WSDL highlights the service definition and the two endpoints that exist. We are now able to get TFS to send events to this service. To do this you need to add the URL’s of the end points to the notification system within TFS. This is done by using a command line utility on the server, or by calling parts of the TFS API. For ease we will call the command line, but a future version should probably have a user interface to allow the administration of which TFS servers you want to handle events for.

To subscribe to the events you will need to use the BisSubscribe utility which you can find out how to use here, or you can use the API and provide an interface to add and remove subscriptions.

If you call:

BisSubscribe.exe /userId TFSEventHandler /eventType WorkItemChangedEvent /deliveryType Soap /address http://localhost:65469/v1.0/Notification.svc/WorkItemChanged

Using the untility you will subscribe to events using SOAP, or if you call:

Using a API helper class similar to the one below:

I may write an article in the future on this, but all the code is part of the current TFSEventHandler application.

We now want to determine what sort of event has been raised in the Service implementation. To do this we need to parse the URL of the endpoint that has been raised and retrieve the event type.

As you can see it is just a case of parsing the URL to get the last bit after the final “/” and then converting it to an enumerator.

The enumerator lists all of the events that are possible in TFS, but be warned that not all of the events fire effectively. Once you have the event it can be converted into an object. I use code from for the event objects and Larry Steinle’s CustomXmlSerializer code to convert the XML to Howard’s objects resulting in the following code:

All of the objects are now ready to pass over MSMQ to the TFS Event Processor, which will be the subject of the next article in this series…