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.

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

authors-correct-display

The authors are rendered in this format

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.

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

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

And binds it against some JSON

To produce HTML

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

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

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

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

authors-with-add-button

So a textbox and a button with a squirt of CSS

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

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

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

then we want the name attribute

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

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

Gluing the template together

Gluing the data into the template is pretty much boilerplate code

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

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

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

author-successfully-added

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
http://handlebarsjs.com/

Nuget page for handlebars
https://www.nuget.org/packages/Handlebars.js/

Demo application source
https://github.com/timbrownls20/BookShelf/

 

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

https://github.com/timbrownls20/BookShelf/

 Workflow

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
Save.cshtml

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.

authors-incorrect-display
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

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.

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

Book Save Action

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

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.

authors-incorrect-display
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

The Author.cshtml is pretty simple

The Corrected View

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

 

authors-correct-display
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

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

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.

Note
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.

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..

 Useful Links

More detail about EditorFor and DisplayFor templates
http://www.codeguru.com/csharp/.net/net_asp/mvc/using-display-templates-and-editor-templates-in-asp.net-mvc.htm

Some more insight into how complex data binding works
http://blog.codeinside.eu/2012/09/17/modelbinding-with-complex-objects-in-asp-net-mvc/

How to manipulate the DOM through JQuery which we would need to dig into a bit to implement adding an author
http://api.jquery.com/category/manipulation/

Google Books API reference in the blog post
https://developers.google.com/books/

 

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

Output

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

Output

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

Sadly doesn’t work

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

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

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.

The function is then available to be called

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

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

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
http://mikepfeiffer.net/2010/06/how-to-add-functions-to-your-powershell-session/

Execution Policies
https://technet.microsoft.com/library/hh847748.aspx

Better ways to work with the PowerShell execution policy
https://technet.microsoft.com/en-us/magazine/2b6812f2-e6e5-41ad-a1c4-6b9e01977cc7

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

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

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

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

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

Which gets over that issue

Before and After Attributes

Unfortunately making the installer with the revised XML generates this error

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

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

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

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

Uses

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

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
http://stackoverflow.com/questions/9518890/what-is-the-significance-of-the-programdata-folder-in-windows

WIX documentation
http://wixtoolset.org/documentation/

Windows Installer Operating System Property Values
https://msdn.microsoft.com/en-us/library/windows/desktop/aa370905(v=vs.85).aspx

Windows Installer Standard Actions
http://www.advancedinstaller.com/user-guide/standard-actions.html

WixSharp
https://wixsharp.codeplex.com/
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

WixEdit
http://wixedit.sourceforge.net/
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

e.g.

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

Builds

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.

Example

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)

Now destroy the build so it is completely gone

Example

Now destroy the build so it is completely gone

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

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
https://www.visualstudio.com/en-us/docs/build/define/general

Details of programming against TFS object model
https://msdn.microsoft.com/en-us/library/bb130146(v=vs.120).aspx

Amending PATH variable on a windows machine
http://www.howtogeek.com/118594/how-to-edit-your-system-path-for-easy-command-line-access/