70-486 Developing ASP.NET MVC Web Applications – Study Notes Part 2

I’ve previously posted about preparing for 70-486 and some of the general materials that are available. Now I’m going to go through the syllabus a section at a time and highlight additional resources that I found useful. As I said before a lot of the syllabus is well covered in these two books.

Professional ASP.NET MVC 5
By Jon Galloway, Brad Wilson, K. Scott Allen, David Matson

Professional ASP.NET MVC 5
Professional ASP.NET MVC 5


Exam Ref 70-486: Developing ASP.NET MVC 4 Web Applications
by William Penberthy

Exam Ref 70-486: Developing ASP.NET MVC 4 Web Applications
Exam Ref 70-486: Developing ASP.NET MVC 4 Web Applications

The links below are a supplement to reading these. Sometime the books coverage is all you need – I’ve indicated where this is the case.


The syllabus is at


I’ll go through each section and comment and provide links.

Syllabus part 1: Design the application architecture

Plan the application layers

Plan data access; plan for separation of concerns; appropriate use of models, views and controllers; choose between client-side and server side processing; design for scalability

Fairly nebulous content that is covered well by Exam Ref 70-486: Developing ASP.NET MVC 4 Web Applications.

Using an Asynchronous Controller in ASP.NET MVC

Task Cancellation

Wait Handles

Unit of work and repository pattern

More on repository pattern

Design a distributed application

Design a hybrid application (on-premises versus off-premises, including Azure), plan for session management in a distributed environment, plan web farms

Vague content that has variable coverage in the books. Content focused around azure, web farms and web service (SOA) based architectures. Professional ASP.NET MVC 5 has an excellent section on WebAPI but you will need to look elsewhere for alternative web service technology.

WCF attributes

Consuming WCF


Hybrid Applications

Azure AppFabric

Design and implement the Azure role life cycle

Identify and implement Start, Run, and Stop events; identify startup tasks (IIS configuration [app pool], registry configuration, third-party tools)

Well covered by Exam Ref 70-486: Developing ASP.NET MVC 4 Web Applications but it was unfamiliar to me so I needed extra reading.

General introduction to cloud services

Startup Tasks




Configure state management

Choose a state management mechanism (in-process and out of process state management), plan for scalability, use cookies or local storage to maintain state, apply configuration settings in web.config file, implement sessionless state (for example, QueryString)

A lot of this content hasn’t changed much since web forms so shouldn’t be much of a problem however there are additional considerations to bear in mind when dealing with Azure.

State management overview

Session State

State server vs SQL Server

Application State

Profile vs Session state

View Bag vs View Data

Windows Azure state management

Design a caching strategy

Implement page output caching (performance oriented), implement data caching, implement HTTP caching, implement Azure caching

Again, a lot of this is content that hasn’t changed that much since the old web form days. I needed extra reading about caching with Azure sites however.

Good overview of non-Azure caching

Data caching

Page Output Caching

Output Cache Attribute

Output Cache Attribute Location

Azure Caching

Design and implement a WebSocket strategy

Read and write string and binary data asynchronously (long-running data transfers), choose a connection loss strategy, decide a strategy for when to use WebSockets, implement SignalR

Unlike the last two sections, this is very much new stuff. It would be easy to spend a long time on this but it’s only a small part of the exam. An overview and understanding of when to use these techniques is probably about the right level. The exam ref book gives a good overview.

Web socket API

Web socket client

Web socket server

Signal R

Signal R example

Design HTTP modules and handlers

Implement synchronous and asynchronous modules and handlers, choose between modules and handlers in IIS

Not too difficult. This content hasn’t changed much in recent versions of MVC which makes things a lot easier. Know the difference between modules and handlers and in what situations each should be used.


Order of Http Module calls

Syllabus part 2: Design the User Experience

Apply the user interface design for a web application

Create and apply styles by using CSS, structure and lay out the user interface by using HTML, implement dynamic page content based on a design

I don’t spend an awful lot of my time creating beautiful UIs for web front ends so this content was less familiar to me. A solid understanding is required – a bit more than just an overview.


CSS Selectors

HTML5 tutorial

HTML5 Canvas element

HTML5 Canvas element fallback

HTML5 Video element

HTML5 Video element fallback

Design and implement UI behaviour

Implement client validation, use JavaScript and the DOM to control application behavior, extend objects by using prototypal inheritance, use AJAX to make partial page updates, implement the UI by using JQuery

Like the previous section but this time your JavaScript and JQuery skills are under scrutiny. There is a lot of content out there – I’ve just put links to the content where I personally had gaps.

JavaScript Prototypal Inheritance


Ajax Helper


Compose the UI layout of an application

Implement partials for reuse in different areas of the application, design and implement pages by using Razor templates (Razor view engine), design layouts to provide visual structure, implement master/application pages

Standard MVC stuff focussed around Views and Razor engine. Professional ASP.NET MVC 5 is very good and covers this off well so probably no need to look any further. I’ve provided a few links just in case.

MVC Views




Razor view engine

Enhance application behaviour and style based on browser feature detection

Detect browser features and capabilities; create a web application that runs across multiple browsers and mobile devices; enhance application behavior and style by using vendor-specific extensions, for example, CSS

The exam ref book was good enough for me for this one. There isn’t a huge amount of content as compared to some of the other sections.



Plan an adaptive UI layout

Plan for running applications in browsers on multiple devices (screen resolution, CSS, HTML), plan for mobile web applications

More mobile adaptation content. A bit meatier than the previous section but nothing to worry about. Professional ASP.NET MVC 5 has some good content on this.

CSS Media Queries

JQuery Mobile

MVC Mobile Features

Designing for mobiles

Syllabus part 3: Develop the user experience

Plan for search engine optimization and accessibility

Use analytical tools to parse HTML, view and evaluate conceptual structure by using plugs-in for browsers, write semantic markup (HTML5 and ARIA) for accessibility (for example, screen readers)

I remember Dilbert cartoon when he refers to SEO consultants as pantless weasels. That’s unlikely to come up on the exam. I really don’t think there is much to this really – the exam ref book is perfectly adequate. There is a bit more meat in the accessibility content but again the exam ref book is fine. No additional links this time.

Plan and implement globalisation and localisation

Plan a localization strategy; create and apply resources to UI, including JavaScript resources; set cultures; create satellite resource assemblies

Globalisation hasn’t changed a huge amount over the years so anyone with general MVC experience should be OK. The exam ref book is good here particularly going through globalisation with JavaScript which I was personally not that familiar with.

Good overview

Resx Files

Design and implement MVC controllers and actions

Apply authorization attributes, global filters, and authentication filters; specify an override filter; implement action behaviors; implement action results; implement model binding

A lot of content here and one to definitely be familiar with. The book Professional ASP.NET MVC 5 is excellent here so no extra reading is required.

Design and implement routes

Define a route to handle a URL pattern, apply route constraints, ignore URL patterns, add custom route parameters, define areas

Again Professional ASP.NET MVC 5 is excellent with a comprehensive chapter dedicated to this. However this has changed with attribute routing so make sure you are covering the most up-to-date material.

Routing overview

Attribute routing

Control application behaviour by using MVC extensibility points

Implement MVC filters and controller factories; control application behavior by using action results, viewengines, model binders, and route handlers.

A complex area that is again well covered in Professional ASP.NET MVC 5 however you may find additional material useful in this area.

Routing Extension

Custom Action Result Http Headers

Filter Extensions Action Filters

Custom Authorisation

Custom Exception Filter

Reduce network bandwidth

Bundle and minify scripts (CSS and JavaScript), compress and decompress data (using gzip/deflate; storage), plan a content delivery network (CDN) strategy (for example, Azure CDN)

Not much content in this one. The exam ref book gives a perfectly adequate coverage.



Syllabus part 4: Troubleshoot and debug web applications

Prevent and troubleshoot runtime issues

Troubleshoot performance, security, and errors; implement tracing, logging (including using attributes for logging), and debugging (including IntelliTrace); enforce conditions by using code contracts; enable and configure health monitoring (including Performance Monitor)

I found this surprisingly hard going. Health monitoring is a drag to learn particularly as I don’t believe people actually use it. IntelliTrace feels a slog as well. Code contracts are interesting though and do come up on the exam. One to know.


Using IntelliTrace to debug live issues

Code Contracts

Health Monitoring

Interestingly Health Monitoring broken in MVC (2.0)

Does anyone actually use Health Monitoring?

Design an exception handling strategy

Handle exceptions across multiple layers, display custom error pages using global.asax or creating your own HTTPHandler or set web.config attributes, handle first chance exceptions

Definitely one to be familiar with but standard stuff with few surprises. Professional ASP.NET MVC 5 has good coverage once again.



Test a web application

Create and run unit tests (for example, use the Assert class), create mocks; create and run web tests, including using Browser Link; debug a web application in multiple browsers and mobile emulators

A frustrating section. The exam is focussed around Microsoft testing technologies (Shims, MSTest etc..) but I personally don’t use these and I doubt they are in wide use. That said, knowledge of NUnit or similar is useful here but specific knowledge about MS technologies is sadly required.

Browser Link



Debug an Azure application

Collect diagnostic information by using Azure Diagnostics API and appropriately implement on demand versus scheduled; choose log types (for example, event logs, performance counters, and crash dumps); debug an Azure application by using IntelliTrace, Remote Desktop Protocol (RDP), and remote debugging; interact directly with remote Azure websites using Server Explorer.

One of those subjects that it’s really difficult to get practical experience of unless you happen to be using it on a day to day basis. Realistically it’s not a good use of time to set up an entire Azure solution just to you can practice debugging it. Do your best with the reading materials available. The exam ref book has some coverage and here are a few more links.


Enabling debugging in Azure

Performance counters

Syllabus part 5: Design and Implement security

Configure authentication

Authenticate users; enforce authentication settings; choose between Windows, Forms, and custom authentication; manage user session by using cookies; configure membership providers; create custom membership providers; configure ASP.NET Identity

Authorisation and authentication have been changed quite a bit over the years in ASP.Net so this is quite a big subject. Try to ensure you are current. Lots of links here to help out.

IIS Authentication

Difference between digest and basic authentication

Windows authentication

.Net Authorisation History

SQL Membership Provider



ASP.Net Identity


Advantages and disadvantages of .net identity


Encrypting Credentials in web.config

Configure and apply authorisation

Create roles, authorize roles by using configuration, authorize roles programmatically, create custom role providers, implement WCF service authorization

I do realise that there is a difference between authorisation and authentication (really I do) but there is overlap in the materials so many of the links in the previous section cover this material as well. Watch out for the WCF material here though.

Authorise filters

AllowAnonymous attribute

WCF authorisation

Design and implement claims-based authentication across federated identity stores

Implement federated authentication by using Azure Access Control Service; create a custom security token by using Windows Identity Foundation; handle token formats (for example, oAuth, OpenID, Microsoft Account, Google, Twitter, and Facebook) for SAML and SWT tokens

I personally found this the hardest topic by far. Very technical, almost academic content. It’s hard to find resources that give a ‘jump start’ to this topic. These links are the most useful of what I found.



Windows Identity Foundation

SAML Tokens



SWT Tokens

JWT Tokens


Creating a Security Token Service

Claims with WIF

Security Token Handlers


Azure Access Control Service

Azure Access Control Service Road Map

Manage data integrity

Apply encryption to application data, apply encryption to the configuration sections of an application, sign application data to prevent tampering

Good coverage in  Professional ASP.NET MVC 5. Here are a couple of extra links to fill out that content

SHA1 is stronger than MD5

MD5 is not considered secure

Implement a secure site with ASP.NET

Secure communication by applying SSL certificates; salt and hash passwords for storage; use HTML encoding to prevent cross-site scripting attacks (ANTI-XSS Library); implement deferred validation and handle unvalidated requests, for example, form, querystring, and URL; prevent SQL injection attacks by parameterizing queries; prevent cross-site request forgeries (XSRF)

High fives and celebratory backslaps all round. You’re nearly at the end. And happily this is some of the best and most interesting content. Professional ASP.NET MVC 5 has the best content that I have ever read in this area so there really is no need to go elsewhere. No extra links this time. None needed

Good Luck

So best of luck everyone. Microsoft exams aren’t perfect but when I’m looking at CVs for potential hires it always gives me a warm glow when someone has a couple of current MS exams under their belt. Hope it goes well for you.

70-486 Developing ASP.NET MVC Web Applications – Study Notes

I recently studied and passed the Microsoft exam Developing ASP.NET MVC Web Applications. Hooray. I thought it was a fair exam covering mostly helpful content – not something I can say for all the exams (70-551 I’m looking at you). I wrote quite extensive notes on the exam so I thought I would tidying them up and post them for general use. I’ve posted general tips here and a more detailed breakdown of the syllabus in the next post.

Overall impression

If you use ASP.Net MVC in your day to day job that’s really going to help but it’s not enough. Generally be familiar with

  1. MVC ASP.Net (obviously)
  2. HTML5 and CSS3 – you don’t need to be an expert but a good grounding is helpful
  3. Azure platform as a service – there is a goodly amount of content on this
  4. Security – this has evolved in MVC 5 so a current understanding is needed
  5. Good understanding of HTTP and how the web works generally

So, just because you use MVC doesn’t mean you know enough. Things like security are something no-one does on a day to day basis. Typically, someone has set this up year ago in your organisation and no-one has gone near it since. Not good enough – you need to know about it.

Programme of study

I always make heavy weather over studying and do too much but this was my general pattern

  1. Watch an overview video – just to get into the mood. Take a bath, light some candles and whet the development appetite.
  2. Read the syllabus
  3. Buy a couple of MVC books. Read them but cross reference against the syllabus. Unless you are desperately interested, focus on exam content.
  4. Read syllabus again. Get onto Internet and fill in the gaps. Make copious notes
  5. Read syllabus again. Buy so practice exam questions (but see warning below)
  6. Take exam – pass hopefully
  7. (Optional) write a blog post about it all

Use the syallabus

Sounds obviously but the key with these exams is go through the syallbus and ensure you have covered it off. It’s easy to lull yourself into a false sense of security by reading some MVC books and watching some videos and feel that all is well and you’ve covered it. Read the syllabus again and make sure that you have.


I read two books for this – both of which were very good.

Professional ASP.NET MVC 5
By Jon Galloway, Brad Wilson, K. Scott Allen, David Matson

Professional ASP.NET MVC 5
Professional ASP.NET MVC 5

A good book and recommended. It is excellent for general MVC, security and extending MVC. Security is particularly good. Nothing on Azure though, so reading this book isn’t going to be enough. I would recommend reading it whether you are taking the exam or not. I enjoyed it.

Exam Ref 70-486: Developing ASP.NET MVC 4 Web Applications
by William Penberthy

Exam Ref 70-486: Developing ASP.NET MVC 4 Web Applications
Exam Ref 70-486: Developing ASP.NET MVC 4 Web Applications

Good again. Its makes a good job of covering the syllabus and focuses the mind on the exam. I read this through and read some parts twice or three times. Not a particularly enjoyable ready though and I wouldn’t recommend this as general reading. It is high level and you will need to research the unfamiliar parts yourself to bolster understanding.


I personally don’t learn well from videos but I did watch some for this. I know other people find videos the best way to learn.

Microsoft Virtual Academy

Free good quality videos presented by chirpy Americans. What’s not to like. I watched Developing ASP.NET MVC 4 Web Applications Jump Start which was excellent (though not that much help for the exam ironically). The updated one is Introduction to ASP.NET Core (formerly ASP.NET 5). Don’t expect great exam coverage but unless you are a ‘manic exam crammer who only wants to pass and nothing else’ then I would definitely watch it.


There is an extensive learning path for 70-486 on Pluralsight. I didn’t watch any of it. 60 hours of videos is too much for me and as I’ve said I don’t learn well from videos. But for those that do then this is a good option. I have watch many Pluralsight vids over the years and they are excellent so I’m going to make an uninformed recommendation on this content on that shaky basis.

General internet resources

These are general resources or general web stuff that is good to know but isn’t explicitly on the syllabus so is easy to miss. For a detailed breakdown of the syllabus see the next post.

ASP.Net site


Good general resource. Good start and fills you in on lesser known subjects.

Web lifecycle

Two good general resources on web application life cycle are

Http request response cycle
Life cycle of an MVC application 

The exam expects you to understand this. It assumes you do so if you don’t – well learn it. Also know about HttpRequest and HttpResponse headers. This stuff comes up time and time again.

What’s new in MVC 5

One of the hard things about MS exams is that a lot of the resources aren’t quite current enough and will be focused on the wrong techniques. This excellent code project post highlights the new stuff in MVC 5. Just so you know, the new stuff is around …

  1. Attribute based routing
  2. Filter overrides
  3. ASP.Net Identity
  4. Scaffolding

The security features particularly are a big change and aren’t that well documented.


are the bests posts I found around this area. There are more comprehensive posts but they tend to be baffling.

Exams questions

Who doesn’t like to use exam questions for revision? It’s like a giant security blanket of exam goodness wrapped around you.



There are several legitimate sellers of exam material. On this one I used Transcender as I have happy memories of the quality of the questions from a few years ago. I was shocked.  The product is of an extremely low quality. Questions were missing great chunks of information and didn’t make sense, the topics covered were all wrong (questions about webforms on an MVC exam), correct answers were clearly wrong etc.. etc.. etc… I spent my company’s money on this (much appreciated) and even then I wanted my money back. If I had spent my own money then I would have felt even more abused and exploited. The exams questions were written by someone who hadn’t read the exam or even knew anything about the subject. I think they plundered the old web forms exam (70-315) for material. Poor show guys.



The Microsoft recommended seller of questions. I didn’t use this for 70-486, however I recently used it for another Microsoft exam.  It was significantly better than Transcender but far away from perfect. You can buy them in a package that includes resits as detailed next …..

Second Shot


The best thing is probably to use the exam itself as its own practice. For not very much more money you can get 4 resits so a few goes at your local test centre will stand you in good stead. It is time limited but every year Microsoft have some kind of free retake offer that lasts 6 months or more and can include exam questions.

I bought 4 resits but I can’t go into an exam unprepared so psychologically this didn’t work for me. I meant to just ‘give it a go’ but instead I spent hour after hour preparing for the exam anyway even though I had free resits in the bag. But mental quirks aside, this is a good option for exam prep.

Next Steps

So now you’ve done the general reading it’s time to bite your lip and dive deep into the syllabus. The next post holds your hand while you are swimming about in the murky depths of the syllabus.

Passing Parameters with Automapper

OK I admit it – sometimes I find automapper hard to work with. It’s fantastic when everything is well … auto, but some of the mappings I work with on a day to day basis are anything but automatic. There is not much auto about the automappings. But enough of my troubles – one of the lesser known features of automapper that I have found useful is the ability to pass parameters around. This allows you to implement mappings that are dependent on some other part of the object graph; a part that is not normally accessible in the context you are working with.


For a demo I have a simple application that retrieves customer who have visited my lovely shop. I retrieve customer database entities and I want to map them to some DTOs. Just for the example we will display the object on a console application – I’m not concerned with the UI right now so this is good enough. I guess I missed the UI design parts of my university course. I must have slept in that day.

Database Entities

The customers object that we retrieve from the database are

public class Customer
 public int Id { get; set; }
 public string Name { get; set; }
 public DateTime DateOfBirth { get; set; }
 public virtual Address Address { get; set; }
 public CustomerType CustomerType { get; set; }


public class Address
 public int Id { get; set; }
 public int? HouseNumber { get; set; }
 public string HouseName { get; set; }
 public string StreetName { get; set; }
 public string Town { get; set; }

public enum CustomerType
 Unspecified = 0,

This is just a straight representation of our database. It’s a customer of a given type with an address. Too easy.

DTO message

As is very standard we want to map the database entity to a set of DTOs. These are

public class CustomerDto
 public string Name { get; set; }
 public DateTime DateOfBirth { get; set; }
 public AddressDto Address { get; set; }

public class AddressDto
 public int? HouseNumber { get; set; }
 public string HouseName { get; set; }
 public string StreetName { get; set; }
 public string Town { get; set; }
 public bool Residential { get; set; }

The Problem

We want the residential property on the address DTO to be false if the customer type is business but true otherwise. So let’s try that.

Constructing the mappings

Mapping an object with no parameters

So our first mapping is very straightforward

Mapper.Initialize(cfg =>
 cfg.CreateMap<Customer, CustomerDto>();

 cfg.CreateMap<Address, AddressDto>();

We are letting the automapper magic do its thing. HouseName maps to HouseName, Street maps to Street and so forth. It all looks very good.

However if I retrieve a customer that I know is residential then the residential property of the customer object isn’t set. The output of my mapping is


The residential property is false. This makes sense – I haven’t mapped

public bool Residential { get; set; }

to anything. In fact my mappings aren’t really valid at all. If I check the mappings in code with


It will throw an exception with the message

Unmapped members were found. Review the types and members below.

Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type

For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters


Address -> AddressDto (Destination member list)

Automapper.Entities.Address -> Automapper.Messages.AddressDto (Destination member list)

Unmapped properties:


This tells me exactly what my issue is. The valid mapping is

Mapper.Initialize(cfg =>
 cfg.CreateMap<Customer, CustomerDto>();

 cfg.CreateMap<Address, AddressDto>()
 .ForMember(d => d.Residential, o => o.Ignore());

And my full code for this is

 var customerRepository = new CustomerRepository();
 var customer = customerRepository.FindById(1);

 Mapper.Initialize(cfg =>
 cfg.CreateMap<Customer, CustomerDto>();

 cfg.CreateMap<Address, AddressDto>()
 .ForMember(d => d.Residential, o => o.Ignore());

 //..validate mappings

 var customerDto = Mapper.Map<CustomerDto>(customer);

Which has the same output as before but this time is actually valid.


How can I set the residential property? The problem is that I need information from the customer object when the address object is being mapped. However when I am mapping the address object I’m in the context of the address and I don’t have the customer information. I can’t do the mapping.

Mapping an object with parameters

What I want to do is pass information from the customer into the address mappings. I’m going to use parameters for that. The call to map has a ResolutionContext. This has dictionary object that I can use to pass through information i.e.

resolutionContext .Items["CustomerType"] = “information”;

So when I call the mapper I can pass what the customer is using the overload with ResolutionContext

var customerDto = Mapper.Map<CustomerDto>(customer,

opts => opts.Items["CustomerType"] = customer.CustomerType);

So now the context knows what type of customer this is. I need to grab the context in the address mappings. Happily there are several hooks into the resolution context I can use within the mappings. For this I’m going to use a custom value resolver

var customerRepository = new CustomerRepository();
var customer = customerRepository.FindById(1);

Mapper.Initialize(cfg =>
 cfg.CreateMap<Customer, CustomerDto>();

 cfg.CreateMap<Address, AddressDto>()
 .ForMember(d => d.Residential,
 o =>
 (src, dest, destMember, resContext) =>
 dest.Residential =
 (CustomerType)resContext.Items["CustomerType"] != CustomerType.Business));

//..validate mappings

var customerDto = Mapper.Map<CustomerDto>(customer,
 opts => opts.Items["CustomerType"] = customer.CustomerType);


The interesting part of the code is

.ForMember(d => d.Residential, o => o.ResolveUsing(
 (src, dest, destMember, resContext) =>
 dest.Residential =
 (CustomerType)resContext.Items["CustomerType"] != CustomerType.Business))

I am using a resolver to access the information in the resolution context and set the residential property using this. It works and the residential property is set correctly


However, I am relying on passing the information myself into the mappings. If I forget to pass in CustomerType then the mapping collapses with a null exception. Also I want these mappings to use the full automapper goodness and be able to map lists of customer entities into list of customer DTOs. It’s not going to do it.

Mapping lists of objects with parameters

To map lists of objects I want the mappings to set the context themselves. That going to be good as it will hide this away from consumers of the mappings and avoids mistakes. I’m going to use the BeforeMap function which also has an overload for ResolutionContext.

 cfg.CreateMap<Customer, CustomerDto>()
 .BeforeMap((customer, customerDto, resContext) =>
 resContext.Items["CustomerType"] = customer.CustomerType;

As the name implies it runs before the mapping takes place so it’s a good place to set up the context. So the call to the mapper becomes

var customerDtos = Mapper.Map<List<CustomerDto>>(customers);

End consumers no longer need to worry about the context; it just works. We can use the amended code to map lists of objects i.e.

var customers = customerRepository.ListAll();

Mapper.Initialize(cfg =>
 cfg.CreateMap<Customer, CustomerDto>()
 .BeforeMap((customer, customerDto, resContext) =>
 resContext.Items["CustomerType"] = customer.CustomerType;

 cfg.CreateMap<Address, AddressDto>()
 .ForMember(d => d.Residential,
 o =>
 (src, dest, destMember, resContext) =>
 dest.Residential =
 (CustomerType)resContext.Items["CustomerType"] != CustomerType.Business))

//..validate mappings 

var customerDtos = Mapper.Map<List<CustomerDto>>(customers);
foreach (var customerDto in customerDtos)


The residential property is set correctly for each object in the list. Job done!

Demo Project

Full source code for this post is on github at

Useful Links


Worked example of automapper custom value resolvers

To output a string representation of the object to the console I used a nifty bit of code on stack overflow to create a generic ToString method for objects. Nice!


Handlerbars.js and Working with Complex Objects in MVC

In a previous post I used an EditorFor template to display child objects correctly on a view. Now we are going to use some simple JavaScript templating to add child objects. We have a page display book details and want to add and save additional authors.

Demo app

The demo app is a simple bookshelf application. It has a view that uses EditorFor templates to display a book which we want to save. The book can have multiple authors. It is a complex object.

public class Book
 public int? BookID { get; set; }

 //.. lots of other properties 

 public List<Author> Authors { get; set; }
public class Author
 public int AuthorID { get; set; }
 public string DisplayName { get; set; }

The book is rendered onto the Book.cshtml view and the user sees a book then can be edited and saved as required.


The authors are rendered in this format

<input id="Authors_0__AuthorID" name="Authors[0].AuthorID" type="hidden" value="0">

<input id="Authors_0__DisplayName" name="Authors[0].DisplayName" type="text" value="Adam Freeman">

<input id="Authors_1__AuthorID" name="Authors[1].AuthorID" type="hidden" value="0">

<input id="Authors_1__DisplayName" name="Authors[1].DisplayName" type="text" value="Matthew MacDonald">

When this form is posted back, the default model binder in MVC uses the name attribute to correctly bind the authors as a child object of the book object. So we get a correctly populated book object passed through to the controller action.


public ActionResult Create(Book book)

The book parameter is populated will the correct authors. Nice. In general, to work with child objects the correct format for the name attribute in the HTML form element is ..


We’ll need to bear that in mind when we are creating a control to add new authors.

The Problem

The authors display correctly and work well but what if we want to add additional authors to the book before saving? Perhaps the book is missing authors. Perhaps I’m a rampant egotist and want to add myself as an author to every book in my virtual bookshelf. Let’s use Handlerbars.js and some JQuery goodness to do this.

The Solution


Handlebars.js is one of many JavaScript templating engines that bind fragments of HTML and produce data driven templates. Handlebars takes a template such as

<div class="entry">

And binds it against some JSON

{ title: "My great page" }

To produce HTML

<div class="entry">
   <h1>My great page</h1>

That’s going to be good for us. We’ve got some pretty chunky fragments of HTML and we want to work with it in the cleanest way we can.

Integrating Handlerbars.js into MVC

Install the package using nuget

Install-Package Handlebars.js

In it goes to the application. Now create a script bundle in BundleConfig.cs

bundles.Add(new ScriptBundle("~/bundles/handlebars").Include("~/Scripts/handlebars.js"));

and reference that bundle in the view


Creating the HandleBar template

Let’s dive straight in and create the template. We want a HTML fragment that will generate us a new author. HandlerBar templates need to be in script tags with the type


our full template is

<script id="author-template" type="text/x-handlebars-template">
        <div class="form-group shelf-author">
            <div class="col-md-10">
                <input id="Authors_{{index}}__AuthorID" name="Authors[{{index}}].AuthorID" type="hidden" value="0">
                <input class="form-control text-box single-line"

This gives us a hidden field for the AuthorID and a text field for the author name. The curly brackets tell us where the holes in the template are so



Are the two pieces of data that the template needs. Handlebars will replace these with the data we supply it.

Constructing the Author add control

Now we need a HTML control to add the author. We want something like this


So a textbox and a button with a squirt of CSS

div class="col-md-4 col-md-offset-2 form-inline">
  @Html.TextBox("txtNewAuthor", null, new { @class = "form-control" })
  <input type="button" id="btnAddAuthor" value="Add" class="btn btn-primary" />

Let’s assume that JQuery is already reference and available. Next job is to wire up the click event to the button

$(document).ready(function () {
    $('#btnAddAuthor').on('click', function () {

    //.. templating code will go here 

Which is standard stuff.

Obtaining the data for the template

Next we need to construct the JSON data that Handlebars will use to generate the HTML. We need two pieces of information

  1. The authors name as inputted by the user
  2. The next index of the author elements

Grabbing the author name is straightforward

var authorName = $('#txtNewAuthor').val();

However to get the next index we need find the current highest index. First we need to navigate the DOM to find the last author. The authors are all wrapped in the ‘shelf-authors’ class to facilitate this

var lastAuthor = $('.shelf-author:last');

then we want the name attribute

var lastAuthorFormName = $(lastAuthor).find(':text').attr('name');

Then we want the last index. If there are 3 authors then lastAuthorFormName will contain


So some regex the current index i.e. the number in square brackets


The entire regex matches “[2]” and the first and only group (\d*) matches the digit itself. The output for this is an array. The first element of the array is the full match. All subsequent elements are the matches for the containing groups (defined in regex by parenthesis). So


would equal “[2]” and


would equal “2”.  So to get the next index we need

var index = parseInt(lastAuthorFormName.match(/\[(\d*)\]/)[1]) + 1;

Now we have all the information we need to construct the data for the handlebar template

var data = {
  index: index,
  authorName: authorName

Gluing the template together

Gluing the data into the template is pretty much boilerplate code

var source = $("#author-template").html();
var template = Handlebars.compile(source);

var renderedHTML = template(data)

Grab the template with a CSS selector then compile and combine. The HTML is now correct and can be inserted into the DOM

The Complete Solution

So combining all the steps together we get


 <script id="author-template" type="text/x-handlebars-template">
   <div class="form-group shelf-author">
     <div class="col-md-10">
       <input id="Authors_{{index}}__AuthorID" name="Authors[{{index}}].AuthorID" type="hidden" value="0">
       <input class="form-control text-box single-line" id="Authors_{{index}}__DisplayName" name="Authors[{{index}}].DisplayName"  type="text" value="{{authorName}}">
 <script type="text/javascript">

 $(document).ready(function () {

 $('#btnAddAuthor').on('click', function () {

 //..don’t insert blank authors
 if ($('#txtNewAuthor').val() == '') return; 

 //.. get the author name 
 var authorName = $('#txtNewAuthor').val();

 //.. get the index
 var lastAuthor = $('.shelf-author:last');
 var lastAuthorFormName = $(lastAuthor).find(':text').attr('name');
 var index = parseInt(lastAuthorFormName.match(/\[(\d*)\]/)[1]) + 1;

 //.. format data as JSON
 var data = {
 index: index,
 authorName: authorName

 //.. combine data with template
 var source = $("#author-template").html();
 var template = Handlebars.compile(source);
 //.. insert new author HTML into DOM 

 //.. clear the input textbox


The HTML element is now correct and when this is posted back the new author will be present in the action method i.e.

public ActionResult Create(Book book)

The book parameter will have a fourth author which will be saved.


So I can now add myself as an author to every book in my library which goes some way into feeding my monstrous and uncontrolled ego – which is what it’s all about really.

Useful Links

Project page for handlebars

Nuget page for handlebars

Demo application source


ASP.Net MVC and Binding Complex Objects Magic

I’ve a habit of declaring things magical when I don’t fully understand how they work and haven’t the time to look into them any further. One of the things I’ve often declared magical is model binding with MVC. It just works. Magical.

Recently though I found model binding with child objects a bit on the difficult side of things. The magic was failing to sparkle correctly and needed a little bit of extra developer sprinkles to work. Perhaps it even needs developer understanding.

Demo Application

I’m going to demonstrate the problem and solution using a demo library application. The application queries Google Books API and allows users to edit and add those books to their own virtual bookshelf. The book shelf app can be found here



The relevant part of the application is adding of books to the library. The work flow is …

  1. User searches for a book
  2. Application queries GoogleBooks and displays a list of matches
  3. User selects a book
  4. Application displays the selected book.
  5. The user amends the book record as required
  6. The application saves the book

So once the user has typed in a search term they are presented with a list of books which they can select.

book list

Once selected a view showing the detail of the book is present to the user. The user is invited to save the book into his or her book shelf.

Fig 2: Book.cshtml

The problem is that the authors are not saved correctly. It’s pretty obvious that the authors aren’t displayed correctly. The HTML output looks fairly nonsensical.

We are going to have to dig into the application a bit further to fully understand this.

The Model

The model of the application is

public class Book
    public int? BookID { get; set; }
    public string Title { get; set; }

    public string Description { get; set; }

    public string Thumbnail { get; set; }

    public List<Author> Authors { get; set; }

public class Author
    public int AuthorID { get; set; }

    public string DisplayName { get; set; }

So a book can have multiple authors. It is a complex object. It is the complex object and how that is rendered on the Book.cshtml view that causes us the problem. When it is posted back the book object lacks authors. The binding of the complex model has failed.

Book Create Action

When the user selects a book from this list this action is called. It displays the book ready for a save. We pass in an id (from the list selection) then the service goes away and grabs the full details of the book.

public ActionResult Create(string id)
   var book = bookService.Get(id);
   return View("Save", book);

The book is then displayed on the view Save.cshtml. The user presses submit which posts the book back to the server.

<div class="form-group">
   <!-- the other properties are displayed here -->
   <div class="form-group">
      @Html.LabelFor(model => model.Authors, htmlAttributes: new { @class = "control-label col-md-2" })
      <div class="col-md-10">
         @Html.EditorFor(model => model.Authors, new { htmlAttributes = new { @class = "form-control" } })
   <!--- rest of the form, submit buttons etc.. -->

Book Save Action

This action is called when the user saves a book to his or her bookshelf. The posted back book is saved.

public ActionResult Create(Book book)
   if (ModelState.IsValid)
      return RedirectToAction("Index");
   return View("Save", book);

This action takes the book object and it is here that we want form data to bind and produce the complex object. We want the model binding to produce the book object as a parameter. We want the magic. The magic fails us.

The Problem

It doesn’t just magically work much to my disappointment. What is displayed is not helpful.

Fig3. Book.cshtml with incorrect author display

Posting this page doesn’t binding the child object and the authors aren’t there. The HTML is just not there. So how can I easily, and with as much magic as possible, change the view so that the authors are present and the form elements are named correctly? What does the default model binder actually want and how can I provide it?

The Solution

EditorFor Templates

The view needs to know how to display the author object. I could loop through in in the view but a better solution is the EditorFor template.

In View/Shared/EditorTemplates create a file called Author.cshtml. By convention MVC will find this and use it to display the Author property. We are telling it what to write out when the author property is edited i.e. what HTML to write out when the following call is made in the view

@Html.EditorFor(model => model.Authors, new { htmlAttributes = new { @class = "form-control" } })

The Author.cshtml is pretty simple

<div class="form-group">
    <div class="col-md-10">
        @Html.HiddenFor(model => model.AuthorID)
        @Html.EditorFor(model => model.DisplayName, new { htmlAttributes = new { @class = "form-control" } })

The Corrected View

Now this is in place the view looks a lot better and it works.


Fig 4. Book.cshtml with corrected author functionality

When save is pressed the full object is passed to the Save Action and the object included authors can be persisted

What is interesting is the rendered output. Viewing the page source (stripping out the validation data elements, styling etc..) we see this

<input id="Authors_0__AuthorID" name="Authors[0].AuthorID" type="hidden" value="0">

<input id="Authors_0__DisplayName" name="Authors[0].DisplayName" type="text" value="Adam Freeman">

<input id="Authors_1__AuthorID" name="Authors[1].AuthorID" type="hidden" value="0">

<input id="Authors_1__DisplayName" name="Authors[1].DisplayName" type="text" value="Matthew MacDonald">

<input id="Authors_2__AuthorID" name="Authors[2].AuthorID" type="hidden" value="0">

<input id="Authors_2__DisplayName" name="Authors[2].DisplayName" type="text" value="Mario Szpuszta">

So the convention that the default model binding requires is revealed. I wouldn’t have just guessed it but the EditorFor Template does it for us.

Although both the id and name look like reasonable candidates for model binding, it is the name attribute that is used. The format for child objects is


so more complex objects are perfectly possible


and so on until you gone down a complex rabbit hole of 7 nested objects from which you might never return.

Adding New Authors (child objects)

One of the things we might want to do is enable a user to add new authors. Perhaps the retrieved book doesn’t have all the authors and the user is a stickler for detail. Knowing the required format of the child object html is going to help us with that. In its very simplest form it could a bit of jQuery based on this idea

var index = getLastIndex() + 1;
var newAuthor = $(“#authorTextBox”).val();

$( ".container" ).after("<input id="Authors_" + index + "__AuthorID" name="Authors[" + index + "].AuthorID" type="hidden" value=0>" );

$( ".container" ).after ("<input id=’Authors_" + index + "__DisplayName' name='Authors[" + index + "].DisplayName' type=text value='"+ newAuthor + "'>" );

But we would need to bit cleverer, use templating, work out the next index etc… But this gives us the starting point to be able to provide that functionality. An exercise for another day perhaps.

I’ve now implemented a solution using Handlebars.js to add authors into the complex object. See this post for details.

DisplayFor Templates

As an aside we could/should also do a template for displaying a read version of the model i.e. when the following call is made in a view.

@Html.DisplayFor(model => model.Author)

It’s not needed to get this to work but it seems like a generally good and wholesome thing to provide this as well. The display template can be very simple..

@model Author

@Html.DisplayFor(model => model.DisplayName, new { htmlAttributes = new { @class = "form-control" } })

 Useful Links

More detail about EditorFor and DisplayFor templates

Some more insight into how complex data binding works

How to manipulate the DOM through JQuery which we would need to dig into a bit to implement adding an author

Google Books API reference in the blog post


PowerShell Join-Path with multiple parameters

In my day to day job I use a fair amount of PowerShell. Some might say the deployment process is mountains of PowerShell glued together by Team Foundation Server. Cruel but accurate. I don’t make any claims to be a PowerShell expert (I really don’t) so I post this not to show my PS brilliance but rather as a way for me to practice and learn. I appreciate this has been written about elsewhere but as I say it’s just practice and I wrote this without peeking at anybody else’s solution (promise)

Standard Call

Within the mountains of PowerShell I use Join-Path quite a bit. It’s fine for two parameters

Join-Path "C:\TestPath1" "TestPath2"



But I’m always mildly surprised it can’t cope with more parameters

Join-Path "C:\TestPath1" "TestPath2" "TestPath3"


Join-Path : A positional parameter cannot be found that accepts argument 'TestPath3'.

At line:1 char:1

+ Join-Path "C:\TestPath1" "TestPath2" "TestPath3"

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidArgument: (:) [Join-Path], ParameterBindingException

    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.JoinPathCommand

Boom – unhappy code, unhappy coder.

Piped Call

The most straightforward solution is to pipe the output of one call to a send call and so on. So

Join-Path "C:\TestPath1" "TestPath2" | Join-Path "TestPath3"

Sadly doesn’t work

Join-Path : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its

properties do not match any of the parameters that take pipeline input.

At line:1 char:40

+ Join-Path "C:\TestPath1" "TestPath2" | Join-Path "TestPath3"

+                                        ~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidArgument: (C:\TestPath1\TestPath2:PSObject) [Join-Path], ParameterBindingException

    + FullyQualifiedErrorId : InputObjectNotBound,Microsoft.PowerShell.Commands.JoinPathCommand

In order to get this to work the second parameter needs to be explicitly named

Join-Path "C:\TestPath1" "TestPath2" | Join-Path -ChildPath "TestPath3" | Join-Path -ChildPath "TestPath4"

Which then works perfectly well


Using parameter array

It feels as if it should/must/ought to be possible to do this without piping – by passing in an array of parameters. Indeed it is. This function will do the trick

function Join-ArrayPath

   if ($PathElements.Length -eq "0")
     $CombinedPath = ""
     $CombinedPath = $PathElements[0]
     for($i=1; $i -lt $PathElements.Length; $i++)
       $CombinedPath = Join-Path $CombinedPath $PathElements[$i]
  return $CombinedPath

To call it it needs to be imported into the shell, There are a number of ways to do this but the easiest is by using the dot operator (dot-sourcing) i.e.

. "C:\PowerShellLib\Join-ArrayPath.ps1"

The function is then available to be called

Join-ArrayPath "c:\TestPath1","TestPath2","TestPath3","TestPath3"

And again works perfectly well


So there you have it, both original and insightful.  Sadly the original is not insightful and the insightful is not original. But I enjoyed writing it!

Note on script permissions

When importing the script about you may see this

File C:\PowerShellLib\Join-ArrayPath.ps1 cannot be loaded because running

scripts is disabled on this system. As part of Microsoft Trustworthy Computing initiative PowerShell is secure by default won’t allow scripts to be run. To bypass this run

Set-ExecutionPolicy Unrestricted

This is just for demo purposes though. For production or anything other than quick demos then consider signing scripts (see links below).

Useful Links

Adding functions to Powershell sessions

Execution Policies

Better ways to work with the PowerShell execution policy

Conditional Deployment with WIX

Often when deploying an application you need guaranteed access to a certain area of the file system. This can change depending on the OS. The challenge is to produce an msi that can detect that and supply the correct values.

Summary of WIX

Wix is an xml based tool used to generate msi files. To use

  1. Create your WIX file – MyMsi.wxs
  2. Run the tool candle.exe to generate the wixobj file
  3. Run the light.exe tool to generate the msi

WIX has the advantages of being

  1. Free
  2. Complete – does everything that I have asked of it
  3. Fairly well documented
  4. Command line runnable so it can be easily integrated into continuous builds

It’s not all sweetness and light though. I find handcrafting the XML hard going and a bit obscure. Projects such as WixSharp and WixEdit can take the sting out of it. However when going past the basics it’s often easier to start to handcraft the XML.

The Problem

Often when deploying an application you want an area with guaranteed access to a certain area of the file system. The ProgramData folder fits the bill nicely. This folder is used for application data that is not user specific so it’s a good candidate as an area for downloads and so forth from an installed application. Unfortunately many of us need to support older OS such as XP which don’t have the ProgramData folder. In this instance a good candidate could be

C:\Documents and Settings\All Users\Application Data

We install our application using an msi generated by WIX.  What I really don’t want to do is maintain more than one wix source file (.wxs). Really, in my life I don’t want to maintain more than one of anything (DVD player, car, daughter etc…) and I really don’t want to maintain more than one wxs file. So there needs to be a way of

  1. Detecting the OS version in WIX
  2. Using that information to change a property within the wxs file

WIX is nothing if not complete so there is such a way.

Detecting OS version

The operating system is exposed by the Window Installer Property – VersionNT. So

  1. Windows 2000 is 500
  2. Windows XP is 501
  3. Windows Vista 600

And so forth as detailed here.

So to detect Windows XP you would need to include a condition element such as

<Condition Message="This application is only supported on Windows Vista or higher.">
    <![CDATA[Installed OR (VersionNT > 500)]]>

Of course this blocks the install completely rather than changes a property so it’s only half the story.

Changing a Property Setting

To change a property conditionally on OS you need to reach for the SetPropertyElement. There are a few wrinkles with this

Action attribute

My first pass at this was

<Property Id="FolderPath" Value="C:\DefaultPath" />
<SetProperty Id="FolderPath" Value="C:\XPPath">
  <![CDATA[Installed OR (VersionNT = 501)]]>
<SetProperty Id="FolderPath"  Value="C:\StandardPath">
  <![CDATA[Installed OR (VersionNT > 501)]]>

So you have a property. The two set property elements target the property element because of its common id. However if you run this then you get this error

error CNDL0045 : The SetProperty element's After or Before attribute was not found; one of these is required when attribute Id is present.

So you need to deploy the Action attribute defined in the WIX documentation as

By default the action is “Set” + Id attribute’s value. This optional attribute can override the action name in the case where multiple SetProperty elements target the same Id (probably with mutually exclusive conditions).

So the wix elements become

<Property Id="FolderPath" Value="C:\DefaultPath" />
<SetProperty Id="FolderPath" Value="C:\XPPath" Action="Action1">
  <![CDATA[Installed OR (VersionNT = 501)]]>
<SetProperty Id="FolderPath" Value="C:\StandardPath" Action="Action2">
  <![CDATA[Installed OR (VersionNT > 501)]]>

Which gets over that issue

Before and After Attributes

Unfortunately making the installer with the revised XML generates this error

error CNDL0045 : The SetProperty element's After or Before attribute was not found; one of these is required when attribute Id is present.

Which has the merit of being straightforward. It needs to know when in the install sequence the property should be set. The windows installer has a sequence of standard actions detailed here for example

  • InstallFiles
  • InstallExecute
  • InstallFinalise

And many others. (To me) it makes sense to set the property just before the files installs so …


And the WIX XML now becomes

<Property Id="FolderPath" Value="C:\DefaultPath" />
<SetProperty Id="FolderPath" Value="C:\XPPath" Action="Action1" Before="InstallFiles">
  <![CDATA[Installed OR (VersionNT = 501)]]>
<SetProperty Id="FolderPath" Value="C:\StandardPath" Action="Action2" Before="InstallFiles">
  <![CDATA[Installed OR (VersionNT > 501)]]>

Equally the After attribute can be used to set the properties after the InstallFiles install action.


SequenceType Attributes

Now when we make the WIX file we now get a more cryptic error

error LGHT0094 : Unresolved reference to symbol 'WixAction:InstallUISequence/InstallFiles' in section 'Product:{BF945826-8B20-42F7-96FD-6153F0BE235C}'.

It turns out that there are 2 install sequences

  1. UI
  2. Execute

Looking again at this standard action table you can see there are two sections

  1. Wizard Dialog Stage (UI)
  2. Install Execution Stage (Execute)

The InstallFiles installer action only exists on the execute sequence and the WIX compiler needs to know that. So you now reach for the Sequence attribute and the WIX XML becomes

<Property Id="FolderPath" Value="C:\DefaultPath" />
<SetProperty Id="FolderPath" Value="C:\XPPath" Action="Action1" Before="InstallFiles" Sequence="execute">
  <![CDATA[Installed OR (VersionNT = 501)]]>
<SetProperty Id="FolderPath" Value="C:\StandardPath" Action="Action2" Before="InstallFiles" Sequence="execute">
  <![CDATA[Installed OR (VersionNT > 501)]]>

It now compiles and creates an msi that behaves differently on XP and later versions of windows. Job done!!


Once you have the flexible property it can be used to redirect output to a different location or used as a source for a config file transform such as

<util:XmlFile Id="UpdateVersionsFolder" Action="setValue" File="[#File.app.config]" SelectionLanguage="XPath" Permanent="yes" ElementPath="/configuration/appSettings/add[\[]@key='AppSettingKey'[\]]" Name="value" Value="[ FolderPath]" />

Which can be very useful.

So well done if you read this far. All the documentation exists on the internet but I found it puzzling so I hope this might help in a general demystification effort.

Useful links

About the ProgramData folder

WIX documentation

Windows Installer Operating System Property Values

Windows Installer Standard Actions

A C# API for WIX. Good for generating a base XML file to start with. Not complete though so will need to fall back to direct XML editing for more advanced scernarios

A simple UI for the XML file. Useful.

Deleting from Team Foundation Server

It’s non-obvious how to delete items from Team Foundation Server. Things can be removed from the web interface or from team foundation explorer but they can lurk around still and bother you. It’s surprising difficult to delete. These are the ways that I’ve cleaned up after myself in Team Foundation Server 2013 and 2015.

Workitems – Bugs and Backlog Items

The straightforward way is just to set the status to removed.

Removing work item from TFS

But depending on how you construct your queries they’ve a habit of shining through again. To me, there is a difference between “a bug has been created and I had a bit of a think about it and I think it’s not relevant” to “I’ve just completely created the wrong thing and I want to get rid of it”. So if you never want to see the workitem again then it’s down to the command line

witadmin destroywi /collection:http:/{/tfsservername:port}/tfs/{collectioname} /id:{workitemid}


witadmin destroywi /collection:http:/myserver:8080/tfs/DefaultCollection /id:678

and it’s gone. Careful now – once it has gone then it’s gone forever.


On the face of it, it is straightforward to delete builds. Just go to team explorer find the build, right click and press delete.

Deleting build from TFS web UI

The problem with this is that the build still exists in some sense and is included when calculating build version number.


Build definition is


Visible in the advance tab of the build definition

Build Label

The build includes the build revision token (Rev:.r) which increments by 1 for every build



If we want to delete the send build then fine – go to the web UI and press delete. If the build is requeued we will get



The build label jumps to 2 missing out 1. The deleted build still exists and counts towards incrementing the build revision token. This might not be an issue. However if you use the build label to drive out the version of the application as we do then this can become a significant issue. Suddenly a version has been missed which could cause various shades of confusion, upset and terror.

To avoid the TFS related terror scenario then the build needs to be deleted AND destroyed. Once again jumping to the command line

To delete the build (i.e. the same as through team explorer)

TFSBuild delete /collection: http:/{/tfsservername:port}/tfs/{collectioname} /builddefinition:{ProjectName}/{BuildName} {BuildLabel}

Now destroy the build so it is completely gone

TFSBuild destroy //collection: http:/{/tfsservername:port}/tfs/{collectioname} /builddefinition:{ProjectName}/{BuildName} {BuildLabel}


TFSBuild delete /collection:http:/myserver:8080/tfs/DefaultCollection /builddefinitionMyProject/MyBuild MyBuild_1.2.3.1

Now destroy the build so it is completely gone

TFSBuild destroy http:/myserver:8080/tfs/DefaultCollection /builddefinitionMyProject/MyBuild MyBuild_1.2.3.1

Now when the build is deleted the build versions work as expected and the revision number is reused i.e.



Work Item History

Work Item History

This is trickier still, the situation where you put some errant information in a Bug or PBI and want to remove it. It could be innocuous as posting in the wrong bug post (which I have done many times). It could be as eye wateringly bad as three paragraphs of invective targeted at a colleague. Sadly the cmd line doesn’t expose a way to delete work item history.

The only way I know is to code against the TFS object model and delete from there. The object model isn’t that well documented but it’s not bad to code against. One for a future post perhaps,

A note on the command line

The command tools used here (TFSBuild and witadmin) along with other helpful tools such as tf.exe, are found in program files at

C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE

I would recommend putting this filepath on your PATH environmental variable if you find yourself doing much TFS admin. That way you won’t have to continually navigate to the program files folder. You’ll soon get sick if doing that if you have do delete something from TFS more than a few times.

Useful Links

A full list of build tokens for XAML based builds

Details of programming against TFS object model

Amending PATH variable on a windows machine