Same yet different. Getting information from a TFS Request (WebAccess JSON)

This is the third part of a series on how to implement a validation plugin using ITeamFoundationRequestFilter.

You can go to the first part by clicking the link below:

https://conradoclarkdeveloper.com/2015/03/02/iteamfoundationrequestfilter-part1-tfs

In this post I’ll explain how to handle work item create/update requests from WebAccess.


What’s in the request again ?


Last time we figured out what Visual Studio requests to TFS in order to create/update Work Items. With this information, we’ve created a simple validator which prevents a specific user from creating work items. It may work wonders when the request is being sent to the ClientService.asmx service as VS does, but unfortunately this kind of operation is not centralized, so if you try to create the work item through WebAccess, your validation just won’t work.

Keeping that in mind, we’re going to inspect WebAccess to figure out how does it creates/updates work items. It’s actually easier than before because we can see the request in the browser itself:

webaccess

This time, our URL is actually this one, you may find something very similar:

http://(server-ip-or-name):8080/tfs/(project-collection)/_api/_wit/updateWorkItems?__v=4

And this time our post data is this baby here (word wrapped for the sake of readability):

updatePackage=%5B%7B%22id%22%3A0%2C%22rev%22%3A0%2C%22projectId%22%3A%2271418ddd-5b24-4a8c-b3c7-
2f933d6ce245%22%2C%22isDirty%22%3Atrue%2C%22tempId%22%3A1%2C%22fields%22%3A%7B%221%22%3A%22Where+
bugs+come+from%22%2C%222%22%3A%22New%22%2C%229%22%3A%22Conrado+Adevany+Clarke%22%2C%2222%22%3A%22
New+defect+reported%22%2C%2224%22%3A%22Conrado+Adevany+Clarke%22%2C%2225%22%3A%22Bug%22%2C%2232%2
2%3A%7B%22type%22%3A1%7D%2C%2233%22%3A%22Conrado+Adevany+Clarke%22%2C%2210002%22%3A%22When+the+mo
ther+bug+and+the+father+bug+meet%2C%22%2C%2210012%22%3A%223+-+Medium%22%2C%2210174%22%3A1%2C%2210
176%22%3A1%2C%22-2%22%3A1%2C%22-104%22%3A1%2C%22-4%22%3A%7B%22type%22%3A1%7D%7D%7D%5D&__RequestVe
rificationToken=HjLY_kIwDLBHsFLrhOT5TTVw_5V9UDcMUgL5F1E118-bKy5GzEQYVExo8-i5pyrftxQZFNrltcXwwb16v
4gJGCLKtHIX_j3RCtn2RH6VNik1ukuw0

Reading the Update Package


After decoding and stripping the RequestVerificationToken away we get this json inside updatePackage (use a UrlDecoder):

[
   {
      "id":0,
      "rev":0,
      "projectId":"71418ddd-5b24-4a8c-b3c7-2f933d6ce245",
      "isDirty":true,
      "tempId":-1,
      "fields":{
         "1":"Where bugs come from",
         "2":"New",
         "9":"Conrado Adevany Clarke",
         "22":"New defect reported",
         "24":"Conrado Adevany Clarke",
         "25":"Bug",
         "32":{
            "type":1
         },
         "33":"Conrado Adevany Clarke",
         "10002":"When the mother bug and the father bug meet,",
         "10012":"3 - Medium",
         "10174":1,
         "10176":1,
         "-2":1,
         "-104":1,
         "-4":{
            "type":1
         }
      }
   }
]

Now this doesn’t seem as pretty as our happy XML in the last post, right? You’ve probably noticed that these mysterious numbers are the ids of the fields, and to do the same validation we did back then we have to process the above code as JSON, extract the correct field id and validate against its value. Another thing you noticed, in case you’re quite the observant one, is that it’s actually an array, not a single object. Yes, it’s possible to bulk insert/update work items in tfs, and yes we let that slip before. But to be honest, I’ll leave this part as an exercise. Json/Xml reading and all is pretty basic.


What about those Ids?


Same thing can’t be said about those field ids. How can we get to know the respective underlying fields? To that end we’re going to use the WorkItemFieldData class from the Microsoft.TeamFoundation.WorkItemTracking.Server.Dataaccesslayer.dll assembly. Which you can get from the server as well. The class itself and its methods are public, don’t worry. We can create an instance of that with our RequestContext:

WorkItemFieldData data = new WorkItemFieldData(requestContext,latestData);

This latestData variable is nothing but a Dictionary<int,object> which corresponds to the respective fields and values you got from the json. It’s pretty straightforward.

Then, you can call this method to retrieve the reference name of the fields:

Dictionary<string,object> myFields = data.GetLatestDataByRefName();

Which in turn returns a Dictionary<string,object> whose keys are the reference names of the fields, for example System.State or System.CreatedBy.


Different paths, same result


Done that, I think the best way to put it all together would be create a single model that you’ll create from either xml through ClientService.asmx or json, through the wit api. Then proceed to write your validation using this model as your base. The flow would be:

1. Check it’s a project collection operation.
2. Check which service is being called.
3. Parse the inputstream content based on the service called into a Model X.
4. Validate Model X -> throw RequestFilterException in case your model didn’t pass on validations.


What now?


That’s it for now. On the next posts, I’ll present a code that can let you change work item information before it’s saved, which you will probably consider hackish, but I don’t believe there’s another way of doing it. We had to use it to change a work item state depending on n conditions, and that state couldn’t be set by the user itself.

4 thoughts on “Same yet different. Getting information from a TFS Request (WebAccess JSON)

  1. Tânia says:

    I could not do validation from Web Access, implementing ITeamFoundationRequestFilter interface worked for Visual Studio, but the Web Access could not, you will write another article about it?

    Note. Very good your blog, differentiated content of others who found.

    Thanks
    Tania

    Liked by 1 person

    • Hello, and thanks for reading. Could you tell me what have you tried regarding validation from Web Access so I can help you further? In theory, all you need to do is to check whether the request is coming from the web access (you could search the string for “/_api/_wit/updateWorkItems” or something like this) and parse the json in order to validate. I haven’t been posting lately but I got plenty of upcoming content, I just need to put it all together.

      Like

    • I mentioned that it’s “hackish” because you need to change the request data itself through reflection before exiting the RequestReady method. So in the end the server processes a different (altered) message, which in turn will carry your changes.

      Like

Leave a comment