Extending Visual Studio Team System
I had to spend some time figuring out some of the Team System extensibility points recently for a presentation to some customers; it’s something I’ve been meaning to play with a while. You will need to download the Team Suite Extensibility kit which includes some basic documentation and a few samples, it’s not great but it’s the best thing we’ve got right now.
The scenario that I wanted to demonstrate was detecting “Source Control Policy Violations”, these allow you to enforce that developers perform certain tasks before checking in code such as Selecting a Work Item to link the Checkin to, writing a unit test, running static code analysis (FxCop), ensuring it builds, etc. A developer can choose to override such policies which might be handy at 2 in the morning when your trying to get a fix out but you wouldn’t want developers doing it all the time.
Fortunately Team Foundation has an extensive event driven framework and events are raised for just about everything, checkins, Work Items being created or updated, etc. You can register to receive these events via a Managed API or a Web Service hosted on the Team Foundation server which can then deliver these events to you by sending an email to an address that you specify or calling a Web Service your provide that adheres to a fixed “interface”. You can even define your own events and fire them manually using the API – enabling you to supply more information and cater for different scenarios.
You can find the Event Web Service on your Team Foundation box at the following location: http://YOURMACHINE:8080/bisserver/eventservice.asmx, the Managed API is located in the Microsoft.VisualStudio.TeamSystem.ELead.Server.Core assembly.
If you add a Web Reference to the Web Service you can use the following code to subscribe to an event, in this case it’s the CheckIn event and we supply a custom Web Service endpoint as the Web Service that should be called by Team Foundation. Note that “CheckinEvent” is case sensitive, any errors will result in the subscription being added successfully but it never gets fired L (I spent a few hours pulling my hair out when I was using “CheckInEvent” instead of “CheckinEvent”.
vstsb2.EventService EventService = new VSTSListener.vstsb2.EventService();
EventService.Credentials = System.Net.CredentialCache.DefaultCredentials;
vstsb2.DeliveryPreference DeliveryPreference = new VSTSListener.vstsb2.DeliveryPreference();
DeliveryPreference.Type = vstsb2.DeliveryType.Soap;
DeliveryPreference.Schedule = vstsb2.DeliverySchedule.Immediate;
DeliveryPreference.Address = "http://vstsb2:8080/CheckInNotification/service.asmx";
int SubscriptionID = EventService.Subscribe(@"ADVENTUREWORKS\Darren", "CheckinEvent", "", DeliveryPreference);
Now we don’t seem to have great documentation around all of the events that are “in the box” with Team Foundation, probably because they are in a bit of flux and things might change between now and release. The only way I could find out what events were available was to look at the schemas in this directory on the Team Foundation Server:
C:\Program Files\Microsoft Visual Studio 2005 Enterprise Server\BISIISDIR\bisserver\events\EventSchemas
Here is a selection on what you can get at right now: AclChangedEvent, BranchMovedEvent, BuildCompletionEvent, BuildStatusChangeEvent, IdentityChangedEvent, MembershipChangedEvent, NodeCreatedEvent, ProjectCreatedEvent, ProjectDeletedEvent, WorkItemChangedEvent, CheckInEvent
The Web Service that Team Foundation will call is again pretty straight forward, it’s an un-typed Web Service as it has to cater for all types of Notifications and the Web Service must have the following signature (note the case of variable names, etc.)
[SoapDocumentMethod(Action = "http://Microsoft.VisualStudio.Bis/Notify", RequestNamespace = "http://Microsoft.VisualStudio.Bis")]
public void Notify(string eventXml)
When this Web Service is called you end up with a blob of XML which is not particularly helpful especially when you see the complexity of a Notification such as a Checkin or Work Item Type change, I always like to take the schema of the XML and run XSD.EXE /C past it to generate a serializable class which makes life a lot easier. Again, the schemas of the notifications aren’t documented that well but after a bit of trail and error I found the CheckinEvent schema in this directory on the Team Foundation Server: C:\Program Files\Microsoft Visual Studio 2005 Enterprise Server\HATIISDIR\public\schemas
Then using the XMLSerializer I can get hold of the CheckinEvent information
XmlSerializer xs = new XmlSerializer(typeof(CheckinEvent));
StringReader sr = new StringReader(eventXml);
CheckinEvent CheckIn = xs.Deserialize(sr) as CheckinEvent;
if (CheckIn != null)
// Were there any Policy Failures during this checkin?
if (CheckIn.PolicyFailures.Length > 0)
That’s it! The event subscription will last until you explicitly unsubscribe (using the EventID returned from the Subscribe method), the Web Service has a few other methods as well so you can retrieve all subscriptions for a given user, etc. For this scenario of detecting policy violations you would probably send an email to the project administrator or perhaps send a IM message.
Another scenario that I wanted to demonstrate was the “Continuous Integration” feature that lots of customers would like Team System to do but we don’t support this out of the box. Continuous Integration as I understand it is kicking off a build every time a source control checkin occurs; a popular version seems to be Cruise Control.
You can achieve this by hooking the Checkin Event as above and then calling the “Big Build” Web Service on the Team Foundation server at the following location: http://YourMachine:8080/TeamBuild/BuildController.asmx. This Web Service has a StartBuild method that can be used to asynchronously kick a build off – the build must have been defined using Visual Studio 2005 Team Suite previously.
Some sample code to kick off a build is shown below.
localhost.BuildController bc = new localhost.BuildController();
bc.Url = "http://vstsb2:8080/TeamBuild/BuildController.asmx";
bc.Credentials = System.Net.CredentialCache.DefaultCredentials;
localhost.BuildStartParams bparams = new localhost.BuildStartParams();
// Your Team Project
bparams.PortfolioProject = "Test";
// Your Team Build Type as defined under Team Builds in Team Explorer
bparams.ConfigName = "MyTeamBuildType";
bparams.BuildDirectory = "c:\\build";
bparams.BuildType = "OnDemand";
bparams.BuildMachine = "VSTSB2";
There’s plenty of other extensibility points which are documented in the extensibility kit, expect this to improve over time and change a fair bit as well so watch out for any breaking changes!