Model binding dynamic collections. I
Some months ago had the chance to do some MVC for a client of my company.
I will be writing about some of the (hopefully) interesting and helpful things I did.
I inherited an existing MVC web application that managed (mostly CRUD-ly) a number of items and I was in charge of a completely new area (functional area, not MVC area) to edit existing entities as well as create new ones.
Those entities contained a bunch of information, inside which was a list of related entities. So a container, contained its own information as well as a list of things with their own information.
The way people worked was pretty similar to what spreadsheet-trained people do:
- open a document
- do a bunch of changes
- persist those changes by hitting “Save”
And what they wanted to do was pretty similar:
- open an entity for update
- perform a bunch of operations on it
- save all the changes for that entity
Amongst the bunch of operations they could do, there was a subset that are interesting (but not uncommon):
- sorting the elements of a list
- deleting a given element of a list
- adding new elements to a list
Another requirement was that the application was to be very responsive to their actions, which ruled out most of the round-trip-to-the-server scenarios, unless the application was to be completely re-written (not an option by itself). They wanted to drag stuff around to sort, and get instant feedback of deletions.
For the sake of simplicity, we are going to exemplify those scenarios (sorting, deleting and adding) in an isolated manner, although, in the real solution, the three things were done at the same time in no particular order.
An Alternative solution
I want to be clear from the beginning: the solutions I implemented for the problems at had are, by no means, the absolute best solutions.
They are solutions, nonetheless, that allowed me to write as little code as possible by leveraging existing assets.
Going all asynchronous
One alternative solution was go completely asynchronous: whenever an operation was performed client-side, it could have been notified to the server and asynchronously performed and the list of entities persisted to their storage.
There could even be some clever undo operation to go back in time (remember the users are used to save all changes at once).
It is a perfectly fine solution, but I chose not go that route as involves writing a lot of plumbing code to gather information in the client (or the use of a client-side binding framework) and a bunch of data-endpoints able to handle each of the operations. (remember we are supposed to do all operations at once).
My solution is built around the realization that server-side model binding is a wonderful thing. It is extensible, but out-of-the-box solves a ton of problems that, before, had to be specifically (and often manually) solved.
Of course, I am aware that not every problem can (or should) be solved in the server, and a bit of client-side makeup will round-up the experience.