Creating a linked Workitem via the TFS API

I have a customer that wanted to create Approvals for a particular work item type. We decided the best way to do this would be to create an Approval work item type and a new Link type called Approvals.

I found it difficult to find an example out there of creating new work item and linking it to another using my own link type. Once I got it working I thought I would Blog it so the next person looking for this has one more example.

Here are the steps; first using the process editor I created a new Link Type (see screen shot below for details). You can use the command line tool witadmin importlinktype to import your link type to the project.


Now to write a web service that is called via bissubscribe to create approvals for my source work item when the source work item is created. In the real code this was a bit more complicated. We had to look up who many approvals were required and create on approval for each person that was required. I have trimmed the code down to the bare necessities just to illustrate how to create the link.  

Therefore here is a sample of the code to create a new work item of the type Approval and link it to the source work item with the relationship Approved By.

//Get the TFS Collection and ensure Authenticated
TfsTeamProjectCollection TfsCollection = new TfsTeamProjectCollection(new Uri "https://Server/tfs/Collection"));
//Get the Work item store
WorkItemStore workItemStore = TfsCollection.GetService<WorkItemStore>();
//Get the project 
Project project = workItemStore.Projects["MyProject"];
//Get the Source Work item (Take for granted I have been passed the ID of the work item to be approved
WorkItem source = workItemStore.GetWorkItem(ID);
//Make a copy of that as an Approval. This way all the common data is pushed into the approval
WorkItem approval = source.Copy(project.WorkItemTypes["Approval"], WorkItemCopyFlags.None);
//Remove the related link that is created by the copy method
//Save the new work item

//Create a link of the type Approvals
WorkItemLinkType linkType = workItemStore.WorkItemLinkTypes["Approvals"];
//Create a linktypeend using the foward name in out case that is Approved By
WorkItemLinkTypeEnd linkTypeEnd = workItemStore.WorkItemLinkTypes.LinkTypeEnds[linkType.ForwardEnd.Name];
//Add the link to the source work item
source.Links.Add(new RelatedLink(linkTypeEnd, approval.Id));

SSRS and Column Headers

As a starting point, the SSRS I’m talking about here is SQL Reporting Services (had a mix up with SSMS yesterday and I’m not taking any chances). And the basic scenario is a common one. The report, which happens to be in Tablix format, has a number of rows of headers that are intended to appear at the top of each page.

This is not an abnormal request. Not in the slightest. However a recent problem strained my patience as I attempted to put the silly headers at the top of every page.

The problem was that, on an irregular but consistent manner (which is to say that it didn’t happen for every combination of parameters, but once you saw the problem, it didn’t just “go away”), the header would go missing. Instead of appearing at the top of the page, it just not be there. Or perhaps it only some of the rows of the header would be there. In this later case, if you changed the page size, you could get it to appear. But then another combination of parameters would cause the same behavior. But the upshot is that I couldn’t depend on the headers to appear every time I needed them too. Frustrating doesn’t begin to describe the feelings I had towards SSRS and headers.

First off, if you’re looking for a solution, some of the pages you’ll find do cover the fundamental process. For example here, here and here. And the information provided therein was accurate. Yes, you need to get the RowGroup into Advanced Mode. And you need to set the RepeatOnNewPage property to true. And KeepWithGroup to After. And FixedData to true. However, I’m afraid this might not be enough. At least, it wasn’t for me. Those steps had already been performed and I was still seeing the problem.

For me, the key to getting to the complete answer was something that I just happened to stumble across. It was a line in an MSDN document (that I can’t seem to find again) that said that row headers were only displayed on each page if there was enough room vertically. Column headers, on the other hand, would always be displayed. In other words, if you had placed your ‘column headers’ as just values in rows within the Tablix, then SSRS wouldn’t do anything special to ensure that they appeared at the top of each page. And this would be true even if you had taken the steps mentioned in the previous paragraph. If there was “too much” report data on the current page, the headers would be cut off as part of the prioritization that SSRS does.

With that piece of information in hand, I had another clue to search with. And that led me to a post that talked about the fact that repeating column headings only worked *if* there is a column headings area on the report. And, depending on how you created the Tablix, that might not be the case.

You call tell if you have a column heading area if you see a double dotted line someplace in the Tablix. If you don’t, then you find yourself in the situation I was in. Now, you *could* create a column group and move your row headers up to that level. For me, that was not a practical choice (because of the complexity of the data being shown in the headers). So instead, I faked it.

Start by adding a Parent Column Group. It doesn’t matter what you group by, so just select an arbitrary field or type in a constant. I choose ‘0’. Doing this adds the column heading areas to the report. Now we need to get rid of the added row without getting rid of the column heading area. In the Grouping Panel at the bottom of the report, right-click on the just added column group and select Delete. In the dialog that appears, you will be given the choice to delete either the group and related rows and columns or to delete just the group. The correct choice here is to delete just the group. If you also delete the related rows and columns, you will be back where you were before with no column heading area. Once you have deleted the group, you can go into the Tablix and delete the row which is related to the column group.

At this point, you will have a Tablix that has a column heading area with no rows in it. And your report will look as it did before. But, more importantly, because there is a column heading area, the row headers which you had previously created (and which had been cut off or just plain went missing) are now visible at the top of every page, regardless of whether a soft or hard page break rendering engine is used.

And now the world can get back to spinning on it’s regular axis. Whew!

The Future (Job Market) is in the Cloud

Unless you have been living in a cave (technology speaking), you should be aware of that amorphous thing known as the ‘cloud’. Even people who are not in the technology profession are aware of the term (although 29% think that it’s something related to the weather - Citrix survey). Still 97% use cloud services in one way or another and 59% believe that the workplace of the future will exist entirely in the cloud. While I don’t expect that to be the case (at least not within my lifetime…a phrase that gets easier to be correct in using with each passing year), there is no question that the cloud is no longer about future hype. It’s here, it’s real and it’s ready to grow.

So, what does that mean for you and your career. Well, if you believe the new study published by Microsoft and IDC, the answer is "lots”. According to the study, there are currently 1.7 million open cloud jobs worldwide. And companies are having a difficult time filling their needs. Not only that, the expectation is that 7 million cloud jobs will be created over the next three years.

So what are ‘cloud jobs’? Well, the contention made by the study is that the new jobs will involved architecture, design and traditional services. In other words, not just the normal heads-down, ‘tech’ job, but one that includes a mix of business acumen and IT competency. The jobs where knowing how to do stuff is not sufficient. Jobs where you need to defend and explain your choices to both technical and non-technical management. In other words, what I consider to be the ‘interesting’ IT jobs.

So how can you prepare for this ‘cloudy’ world? Get some knowledge. Unfortunately, taking one course or even a couple is just the start (ObjectSharp does offer a course on Azure). You need to learn about the broad swath of technologies that are including in the ‘cloud’. Check out the latest functionality in Windows Azure. Looked at it last month? Well, look again…it changes that quickly. Keep you ears tuned to Azure-related social media. In Canada, there is the @CdnAzure Twitter account as well as the Developer Connection blog. As well, you can follow my Twitter account (@LACanuck) or my blog. While I don’t blog about Azure too much (I’m actually in the middle of writing a book on Azure which will hopefully come out in a few months), I do tweet about it quite regularly.

In other words, the process of making yourself cloud capable is an on-going and active one. The information will not come to you unbidden. Reach out and grab it wherever you can find it. And don’t be afraid to ask. I (and many others in the community) are happy to help out whenever we can.

Want to Speak at DevTeach?

I’m privileged to be the Tech Chair for Cloud and Windows 8 tracks at DevTeach. This time out, the conference is being held at the Delta Meadowvale in Mississauga from May 28 to 30 (see for details). All of these sessions (in both topics) will take place on the same day, which (based on the current schedule) will be the 29th.

So what am I looking for? Topics that will help developers solve the problems that they face every day. Topics that will let developers become more effective. Topics that go beyond the introductory level (they can already get that through various channels, such as Channel 9) and get into the meat of the technology. The template for submission is available at: The deadline for submission isn’t until the end of January, so you have the time to be creative. And I look forward to seeing what the developer community can come up with.

A few things you might want to keep in mind as you think about your possible topics:

  • The audience for the conference will be about 50% web developer ( including about 10-20% of those who are SharePoint developers) , 25% other developer (client, mobile, etc) and 25% admin
  • I’m mostly looking for developer talks but I am willing to consider admin talks. I won’t be selecting more than one admin talk for each track
  • Crossover topics are possible. I’ll determine which track they will fall into based on the complete list of submissions.
  • ObjectSharp will be doing an intermediate to advanced level post conference workshop on Windows 8 XAML, so keep that in mind

If you have any questions, please ask. I’m happy to provide any assistance or guidance that you might need.

New TFS Administration Tool

One of the tools any TFS admin keeps in their toolbox is the TFS Administration Tool. This tool makes it very easy to manage security for TFS. Allowing you to manage user permissions on all three platforms used by TFS. Specifically TFS, SharePoint and Reporting Services.

Download version 2.2 here.

Agile in non-software environments

Many moons ago I blogged about agile being adapted by a school in the states. 

Colin Bowern passed on another interesting presentation called “Agile in the Bathtub

I thought I’d share another Microsoft fellow who has written and blogs about Agile not only at work but in your personal life. If your struggling with time management read J.D. Meier’s book “Getting Results the Agile Way: A Personal Results System for Work and Life”.  Meier’s blogs about Agile Results it is a must to read. In one  blog Meier’s explains how to use Evernote (a free application) as your Personal Information Assistant and become agile in all you do.

 Testa  Smile

Toronto ALM User Group

Happy New Year everyone.

We have two great sessions to start 2013.

Patterns of Testable Software – with Asaf Stone on January 24th

2013 ALM Summit in Review – with Jeremy Garner-Howe on February 7th

Looking forward to seeing you there.

Development for Office and SharePoint Moves Forward

Over the next couple of months, you’re going to start hearing more and more about the new App for Office model. In a nutshell, this is a new model for developing and deploying applications to Office 2013 and SharePoint 2013. The main idea is to remove the installation requirement for applications onto a server while still providing the full range of functionality to the applications. Is this case, the servers I’m talking about are the Exchange Server and the SharePoint farm.

At the heart of the Apps for Office/SharePoint model is Web technologies. And while it’s a major simplification, the general approach is as follows: the application (i.e. Word, Excel, SharePoint) hosts a control that displays a Web page. That Web page is the ‘app’. The site behind that Web page is hosted wherever it wants to be, but most importantly it does *not* have to be hosted in the SharePoint or Exchange environment. The Web page has the ability to interact with the application through a number of techniques, including client-side JavaScript and/or server-side code (ASP.NET, PHP, etc.). From the perspective of the user, it does *not* appear that the app is a Web page, but it feels like it is directly integrated with the application.

As you might guess, this is not a complete or thorough description of the process. But if you want to learn more, you can join me on Dec 12 in Charlotte (register here) or Dec 14 in Toronto (register here). And if those dates/places don’t work for you, keep your eyes open for new dates across North America starting in February.

Mapping to a TFS Source Control Folder

So often I see developers mapping to their local folder from the middle of the source control tree to a folder on their desktop, then another folder to a different location. It gets very messy very quickly.

Some people may like to map folders this way, however I prefer a cleaner mapping implementation. When working on a team I would rather have the same folder structure as the server and everyone else on the team. Also it’s nice not to have to map each app I work on. I would rather just map once and be done with it.

Here is what I do: From a clean never been mapped TFS source control repository. If you already have  mappings check everything in and remove them before doing this. (These instructions are for Team Explorer 2012)

Open the Source Control Explorer

Select the top node which should be your Server\Collection

Right click and select Advanced | Map to Local Folder from the context menu

Create a folder on the drive of your choice with the same name as the Collection. I like to create a Source folder then inside that folder create the Folder with the same name as the collection.  That way if I have more than one Collection they are separate folders but all under Source.







Once you hit the MGetLatestap button you will be prompted to get latest of everything in the collection.





I recommend you select No. I doubt you want everything, do you?

Now traverse the Source Control tree look and watch the Local Path at the top it changes as you move. To get a particular application just right click on the folder and select Get Latest Version and it will get it into the folder structure you see.

Have everyone on the team do this. Then when you go from machine to machine you always know where to find the source. Also it looks just like the server.

Cloaked folders in the TFS Build Workspace


Here is a little Trick I find most people don’t know about.

When setting up a Build Definition you have to tell the build server where to get the source code from. We do this by declaring the folders to download from on the workspace tab of the build definition. It takes time to download all the files to the build server so you don’t want to get any unnecessary folders from source control.

Generally you can just select the root of the branch and pick up everything from there. Although there are times when the build you are creating does not require all the files in the branch. Lets say for example that you have two builds that run one that only builds the application and one for your WIX projects to create an install package. You likely want to keep all the files together for branching purposes. Something like this:


The folders in my example are for the following:
Builds files used by the build process specific to this application. Includes third party DLL’s we do not have the source code for.
Install WIX Project.
Resources Various resource files used by the application.
Source Application Source Code.

Now what I want is to get certain folders when building the app for a CI build and different ones when creating an install package.

CI Build

Install Package









I could just do this. But then I am getting more than I need in both cases.





Or to get just what I need I could do this. (Making sure I put everything into the correct folder on the build agent.

CI Build: image





Installation Package Build:image





Or I could use the cloaked status to let the build know not to get a particular folder.

Therefore on the CI Build where I want everything but the Install Folder I could do this: image




And on the Install Package Build I don’t need Source or Resources so I could do this:image