Like water through a sieve. Word on how to implement ITeamFoundationRequestFilter


How this came up – The problem with Work Item Process Editor 


If you’ve worked a fair time with TFS you know it surely has its pitfalls and issues. One thing that upset me a lot before is validating work items. You never know what kinds of requirements people can come up with, and with such a limited interface there isn’t much you can do.

WorkItemRules

It’s quite intuitive and straightforward if we need to set up simple validations. But it gets messy quickly, specially with those WHEN and WHEN NOT functions that forwardly nests more and more rules. Those rules get more and more complex, maintenance gets even harder.

Then we hit a wall.


Enter ITeamFoundationRequestFilter


After lots of google and caffeine, I’ve found out how to create a plugin implementing the ITeamFoundationRequestFilter interface, which gets executed BEFORE or AFTER the Team Foundation Server receives and processes the request. In this post I’ll just explain how this interface works.

public interface ITeamFoundationRequestFilter
{
    void BeginRequest(TeamFoundationRequestContext requestContext);
    void EndRequest(TeamFoundationRequestContext requestContext);
    void EnterMethod(TeamFoundationRequestContext requestContext);
    void LeaveMethod(TeamFoundationRequestContext requestContext);
    void RequestReady(TeamFoundationRequestContext requestContext);
}

I’ll leave the other methods alone and for now I’ll focus on BeginRequest and RequestReady.

By digging up Microsoft.TeamFoundation.Framework.Server.dll, I’ve found out where exactly these two methods are called.

BeginRequest happens after the initial identification of the request, but before authorization. Some validations take place here as well, such as applying ssl restrictions, checking access mappings and such.

RequestReady happens after authentication. It contains the authenticated user information. We’ll choose this one because it’s the last possible point in time in which we could prevent the request from happening. (We can’t do this with EnterMethod, we’re going to see that later). But I’m fairly sure that you could also use BeginRequest.

If you check MSDN, it says “An ITeamFoundationRequestFilter can throw a RequestFilterException in EnterMethod to cause the request to be completed early and an error message to be returned to the caller”. However, it doesn’t really stop further execution, and I didn’t dig down enough to know the reason why. So let’s stick with RequestReady.

Create a class library with a class implementing this interface. Then copy the generated dll to the tfs plugin folder. It’s usually this one:

C:\Program Files\Microsoft Team Foundation Server 12.0\Application Tier\Web Services\bin\Plugins

But it may vary depending on where TFS is installed. If you want to make sure, access IIS Manager (inetmgr.exe) and check where the TFS application is:

TfsApplicationLocation

The Microsoft.TeamFoundation.Framework.Server.dll assembly is also located in the bin folder of the “tfs” application. You can get it from there.

It’s all possible because TFS has a service-oriented architecture, and thus any Work Item you query, any build you queue, and whether you’re using Visual Studio or the Web Access, you’re sending requests which are received by the “tfs” application in particular, hosted on IIS.


What can you do with it?


Ok. Now every single request passes through your filter. I think this is where I should put a large DISCLAIMER: Use this at your own risk. It’s not recommended, it’s barely documented, but it gives you COMPLETE control of what is being sent to TFS. This is where the danger lies, because any kind of mess-up here can crash an operation and leave it unusable.

Also, be prepared to deal with all kinds of content thrown at you. There are lots of web services that process those requests, some using soap with XML, others JSON content. There are a lot of formats. You’ll even receive multipart requests with files and whatnot. Tread carefully and process ONLY what you intend to, or it could hit performance really hard. Try to let everything go straight through your filter, and just pick up what you really need. As the title says.


Now what’s next?


In the next posts I’m going to show how I used this technique to create complex validations for work items, set custom fields based on conditions, trigger code review requests automatically, and more.

3 thoughts on “Like water through a sieve. Word on how to implement ITeamFoundationRequestFilter

Leave a comment