I’ve been a software developer for over 16 years. It’s not that long but in terms of software development it’s pretty long time. Perhaps it’s like dog years – 1 development year equals 7 normal person years so actually I’ve been a developer for 112 software dev years. That seems more like it.
Over that time I’ve seen 4 major shifts in web development. Shifts up to new versions happen all the time – this is more where everything you know needs to be put in the bin and you start up again. Seems harsh but that’s the business and if you don’t like it then it’s perhaps time to move on. I’m shifting again to Node.js and React but as I do it’s kind of interesting to look back at the other shifts and how I felt about them at the time and how good they were in retrospect.
Classic ASP
It’s where it all began. Asp files with VBScript and <% %> to poke holes in the html to fit the programming stuff in
<!DOCTYPE html>
<html>
<body>
<%
For i = 0 To 5
response.write("The number is " & i & "<br>")
Next
%>
</body>
</html>
It’s all about the response.write. I loved it.
Features
Interpreted language – no compilation
Written in scripting language like VBScript or JScript
One file called *.asp. Everything is in there.
One file per page
Lots of use of Response and Request objects. Felt like you were working with the architecture of the web rather than against it
Stateless
How excited was I to use it?
Ecstatically excited. I loved coding in it. Dynamic web pages that could squirt out content for each individual user. Amazing. It was all interpreted – no compilation here – no need for it. I did this for a Masters project and we all loved it. My supervisor was talking about PhDs in it.
Downsides
It wasn’t perfect. The downsides were
Terrible IDE. It was MS InterDev and it was unusable. We all used to code in EditPad Pro which at least had colours.
No structure. You could put COM+ components in to force some structure into it but you would only do this if you really hated your coworkers.
No debugging unless you count writing acres of Response.Writes all over your code
No state management at all. You want to persist the state of a textbox then do it yourself …
which sets the stage for
ASP.Net Web Forms
A proper compiled language with a new framework and new languages to boot .To get a flavour here is the ubiquitous page load event
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
Response.Write("<br>Page has been posted back.");
}
}
Felt radical at the time.
Features
A compiled language – Wow!
Code behind – split files with markup and code in separate files combined with partial statements
Highly abstracted – managed through page life cycle events
Stateful – Automatic state management through View State
How excited was I to use it?
Passed myself with excitement. I got to build a new server first to host it and I had a big silver machine on my desk making a sound like an aircraft for months. And that was just the start – new language, new IDE that worked, proper code and architecture. Who wouldn’t like all this.
Downsides
The world moved past webforms and while they were good initially, the advent of more client side techniques such as AJAX showed it’s limitations
Worked very badly with JavaScript. WebForms mangled HTML element ids and made it difficult to work with
It was really like windows programming for the web. While hiding the complexity of the web might seem good I’m convinced that webform programming led to a cohort of web developers who really didn’t understand the nature of the web.
Inefficient – lots of postbacks and ViewState (stashing the state of the form to persist it) was massive and came over the wire every time.
Very difficult to unit test. Too many tightly bound dependencies
In the end I hated some of the components. Some were good like ListView and some were made for abuse and torture such as the UpdatePanel. Nest these babies and watch the bad times roll.
Things looked a lot brighter over at the Rails community so we got …..
ASP.Net MVC
Model, View Controllers in the Net world. It was a proper architectural pattern that was fully unit testable. It wasn’t pretending to be windows programming – it was the web and it was proud of it. Clearly still very much used today.
@{ var theMonth = DateTime.Now.Month; }
<p>The numeric value of the current month: @theMonth</p>
@{ var outsideTemp = 79; var weatherMessage = "Hello, it is " + outsideTemp + " degrees."; }
<p>Today's weather: @weatherMessage</p>
How excited was I to use it?
It wasn’t so much as excited – I was relieved. After fighting against webforms, here was something that worked with you. It was almost back to classic ASP in some ways so I felt like I was coming home.
Features
Skinny controllers, dumb Views and fat models
Clever routing so it wasn’t one file per page any more. That more than anything amazed me
Worked well with dependency injection so was testable
Worked well with JavaScript. Generally felt like the web
Stateless again
Downsides
Honestly I just like MVC and always have done. If pushed I might say
It still posts back so not as responsive as it could be
It’s a different stack to front end so you would need to know C# and JavaScript
It’s easy to write badly – massive Views full of logic aren’t good
But while we weren’t looking Node.js was discovered and we get….
React
Or I could have said Angular or Ember or fill in the blank with your favourite framework. For me, it’s the most radical shift yet because it’s not the Microsoft stack – we’re not in Kansas any more. It’s all in JavaScript, even the server. And while it’s not restricted to the client it’s focus is around ‘reactive’ single page applications (well my focus is anyway).
Blazing fast if on single page app – uses Virtual DOM to only update what it needs to on the page
Back to stateful (if on single page app)
How excited am I to use it?
I feel pretty fortunate to have to opportunity to use this in a commercial setting. I’ve always liked JavaScript and it’s fascinating to see it build out a large scale application. I like Angular for the same reason. So I’m excited once again.
Downsides
It’s not all gravy though. Downsides include
It is a steep learning curve and fast moving so the curve keeps shifting
It’s JavaScript which is great but it’s easy to write terrible JavaScript so terrible React
You’ll need a decent architecture to go with it like Redux – not a disadvantage but you need to be aware of it
It’s just the view so the rest is up to you to (re)invent.
Looking Back and Looking forward
I feel all misty eyed looking back and this is just one aspect of the development I’ve been involved in. There’s ORMs, mobile development, testability, ASP Core, the rise of Dev Ops and on and on and on. Headspinning but great.
What’s next – it’s just so hard to say. I reckon .Net Core will take off, JavaScript will be replaced or transform to something unrecognisable, everyone will decide they hate ORMs and rediscover stored procedures, machine learning will be big, driverless cars will start to fly and we will all go to live on Mars with Elon Musk. Or maybe someone will invent a web framework which combines the best of classic, web forms, mvc and react; perhaps like this ……
I recently wrote this horrible code to generate a drop down box to select any number from 1 to 12.
Html.DropDownList("ddlClockHours", new List<SelectListItem>
{
new SelectListItem {Text = 1.ToString(), Value = 1.ToString()},
new SelectListItem {Text = 2.ToString(), Value = 2.ToString()},
new SelectListItem {Text = 3.ToString(), Value = 3.ToString()},
new SelectListItem {Text = 4.ToString(), Value = 4.ToString()},
new SelectListItem {Text = 5.ToString(), Value = 5.ToString()},
@* And so on till 12 – I’m too embarrassed to continue *@
})
Ouch! It was only a test harness but after an hour I still got sick of looking at it. It’s a sin that needs to be atoned for.
The Penance
For my penance I’ve said 5 Hail Marys and identified three better ways to generate numeric range dropdowns.
Using Enumerable.Range
If I want to stick with MVC and C# then there is a static method on Enumerable that will generate sequences of numbers i.e.
Enumerable.Range(1, 12)
Will output 1 through to 12 as a list of ints. Leveraging this, my grotesque piece of Razor becomes
@Html.DropDownList("ddlClockHours", Enumerable.Range(1, 12)
.Select(x => new SelectListItem { Text = x.ToString(),
Value = x.ToString() }));
Which renders out as a normal dropdown as before
Much better.
Using HTML5
Of course we don’t even need to get into C#. If we’ve got the luxury of a modern browser we can just use HTML5 to give us a slider control.
If you don’t have the luxury of a modern browser then you can fall back to JQuery UI which has a larger range of supported browsers. The code isn’t that much more but of course you need to reference JQuery and JQuery UI libraries. It’s another slider type control and the implementation is
To atone for my sin I swapped out the horrible code for the Enumerable.Range implementation. I think that’s my preference really. I don’t really want to include a whole bunch of scripts and css to get a decent control (JQuery) and I don’t want to limit myself to the latest and greatest browsers (HTML5). Beside I think Enumerable.Range is little known but pretty smart and let’s face it – who doesn’t want to be little known but pretty smart.
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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
MVC ASP.Net (obviously)
HTML5 and CSS3 – you don’t need to be an expert but a good grounding is helpful
Azure platform as a service – there is a goodly amount of content on this
Security – this has evolved in MVC 5 so a current understanding is needed
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
Watch an overview video – just to get into the mood. Take a bath, light some candles and whet the development appetite.
Read the syllabus
Buy a couple of MVC books. Read them but cross reference against the syllabus. Unless you are desperately interested, focus on exam content.
Read syllabus again. Get onto Internet and fill in the gaps. Make copious notes
Read syllabus again. Buy so practice exam questions (but see warning below)
Take exam – pass hopefully
(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.
Books
I read two books for this – both of which were very good.
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
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.
Videos
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.
Pluralsight
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.
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 …
Attribute based routing
Filter overrides
ASP.Net Identity
Scaffolding
The security features particularly are a big change and aren’t that well documented.
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 …..
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.
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.
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.
[HttpPost]
[ValidateAntiForgeryToken]
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 ..
name="PropertyName[index].ChildPropertyName"
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
<div class="entry">
<h1>{{title}}</h1>
</div>
And binds it against some JSON
{ title: "My great page" }
To produce HTML
<div class="entry">
<h1>My great page</h1>
</div>
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
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
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
{{authorName}}
[{{index}}
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" />
</div>
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
The authors name as inputted by the user
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
Authors[2].DisplayName
So some regex the current index i.e. the number in square brackets
lastAuthorFormName.match(/\[(\d*)\]/)
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
lastAuthorFormName.match(/\[(\d*)\]/)[0]
would equal “[2]” and
lastAuthorFormName.match(/\[(\d*)\]/)[1]
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
@Scripts.Render("~/bundles/handlebars")
<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}}">
</div>
</div>
</script>
<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
lastAuthor.after(template(data));
//.. clear the input textbox
$('#txtNewAuthor').val('');
});
});
</script>
The HTML element is now correct and when this is posted back the new author will be present in the action method i.e.
[HttpPost]
[ValidateAntiForgeryToken]
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.
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 …
User searches for a book
Application queries GoogleBooks and displays a list of matches
User selects a book
Application displays the selected book.
The user amends the book record as required
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.
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.
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; }
[Required]
public string Title { get; set; }
[AllowHtml]
[DataType(DataType.Html)]
public string Description { get; set; }
[DataType(DataType.ImageUrl)]
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" } })
</div>
</div>
<!--- rest of the form, submit buttons etc.. -->
</div>
Book Save Action
This action is called when the user saves a book to his or her bookshelf. The posted back book is saved.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Book book)
{
if (ModelState.IsValid)
{
db.Books.Add(book);
db.SaveChanges();
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" } })
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
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.
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.
@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" } })