Monday, January 14, 2008 - One of my main responsibilities at Microsoft is to help build out the developer love around ASP.NET and ASP.NET MVC using SubSonic and other contributions (like the MVC Toolkit). I've been having a lot of fun working on SubSonic over the last year and some, and it gets more and more fun as the new MVC framework emerges from the CTP crib. I've been sort of quiet about what I've been doing, and it's mostly to avoid confusion with all the offerings coming out surrounding MVC (such as David Ebbo's amazing Dynamic Data Controls). Now that MVC is sinking into the ASP Developer Consciousness, I figure it's time to let you know what I've been doing with SubSonic's MVC cousin (dubbed Makai), and all the goodness that you can play with soon (no, I don't know when :). The Vision In everything, SubSonic is here to fill the gaps, and send you home early. My goal with Makai is to give you a set of tools (and more, which I'll write on later) that will help you to crank out your application quickly so you can get home and watch American Idol with your wife/partner/friends/animals.
In everything, we focus on time as value and the idea that less code is better code"Makai" means "towards the ocean" in Hawaiian, and as I build this toolset out, I imagine that's where you're headed when you get done with work while the Sun's still up. The Scaffold, Reborn Our "money maker" has always been the scaffold control - you just pop a declaration on a page and you're off and editing. We've done the same for MVC, but in this case it's a controller:
This list comes complete with search, sorting, and server-side paging. Also note that the foreign-key columns show up as they should, and every column is formatted properly (currency symbols according to culture, right-aligned numeric fields, checkboxes for boolean fields).
You might be wondering "how do you know what field to search on, and moreover link on in the scaffold list page"? The answer here is that we don't - we guess and then tell you "well it's our convention to x, y, z" if we're wrong :). We've introduced a new property to the underlying schema (the layer that marries your object with your database schema) called Descriptor. This property is used all over the place and is the descriptive column for each record (like Product Name might describe a product in terms of a name). Our convention here is to use the first string field after the Primary Key - that's what we link on, and that's what we search on in the scaffold (using a fuzzy search).
The editor is pretty much the same as always, with the new addition of jQuery:
You also might be wondering if every scaffold will have our logo there, and the answer is yes - it will. Until you change the underlying template...
Templates
MVC is interesting in that it's insanely flexible in terms of how you want to do your UI. It's so flexible, in fact, that at some points you might feel lost (like I did) in terms of "how to do it right".
I like the way Rails does it's scaffolding - it generates a ton of code for you and you manage it from that point on. This is pretty efficient, but in many ways violates their premise of "Don't Repeat Yourself" if you consider how much HTML and UI bits are generated over and over for each table. Rather than get in a Rails debate - let me just cut to the chase and explain how I've handled this for ASP.NET MVC.
We store all the UI HTML in template files, saved as Resources in the Makai dll. They are pulled only once, and then stored in memory (cached) for use each request thereafter.
A template looks like this:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <style> $style </style> <html> <head> <title>$title</title> </head> <body> <div id="pageheader"> <div style="padding-top:10px" > <img src="http://subsonicproject.com/images/subsonic_logo.png" /> </div> </div> <div style="padding:20px"> $contents </div> </body> </html>This is our "Master" template, the thing that wraps the scaffold with our logo. We also have a CSS styles template that gets injected in the $style flag, and all the contents get injected in $contents. The List page of the scaffold looks like this:
<h1>$title</h1> <form action="$searchaction" method="get"> <fieldset> <legend>Search by $descriptor</legend> <input type="text" name="q" size="50" value="$query"/><input type="submit" value="go" /> </fieldset> </form> <div> $message </div> $table <input type="button" value="New" onclick="location.href='$newlink'" />They are very lightweight, and indeed I've tried to make them as modular as possible so you can overwrite them as needed. Which is the important part here. You can override any template we have by creating the same-named template and sticking it in App_Data/Templates. All you need to do is keep the same directory structure and we'll find it, overriding the one stored in our DLL. For example - the editor page above outputs each editor row like this:
<div style="padding-bottom:10px"> <label for="$name"><b>$label</b></label><br /> $control </div>If you like a table-based approach, you can create a new template at App_Data/Templates/Editor/EditorRow.htm and replace this HTML with whatever you like:
<tr> <td><label for="$name"><b>$label</b></label></td> <td>$control</td> </tr>Your output will then look like this (tabular format):
We have templates for everything, and I'm still working on this "Injection Model" so it can scale etc - would love to hear your ideas on the matter :).
The Fun Doesn't Stop There - Or Why Extension Methods Aren't Evil :p
The core of scaffolding is to create a "skeleton" from which to build on. Other frameworks do this by generating the code for you that you then maintain. I've taken a different tack on this (but we're still going to let you do this) and made the scaffold the result of all of our new Extension classes for SubSonic; so in essence you can "part out" the scaffold and use the dynamic pieces you like, from the entire editor right down to the individual control.
The scaffold you've bee looking at is the result of the following Extension Methods (among others):
By inheriting from this controller, you can now work with your membership bits (again, no views with this one - all templated resources):
Editing a member:
Roles Management:
Summary
There's a lot more to write about here, but I'll wrap it up for now until there is something more concrete to show. I'm working hard to get SubCommander in synch with MVC so you can use its generator features to do many of the MVC fun stuff
@Rob: Hey Rob, no fair teasing us about helping write unit tests for Query2 when most of the tests don't even seem to pass, at least without some column called Neep :) What exactly was column 'Neep' anyway? Anyway they're going to have to clone you soon with all these good bits that you keep coming out with, or at least get you an intern to write docs for all of this goodness! I've also got to ask if migrations have been back-burnered or if they still fit in anywhere in the grand scheme of things? Oh, and how does this mystery SubStage fit into all of this goodness?
Lastly just wanted to say don't get too caught up in layering on the scaffolding butter and extensions creme, not because we don't love them but because part of what turned WebForms into the plump lipsticked-pig was this desire to make everything automatic and easy even for 101 level programmers. Personally I'd rather have fewer, simpler, clean things rather than a huge slew of whiz-bang features. Also one thing to remember is that pretty much only Rails new-comers use scaffolding, it's sorta considered training wheels for the newbie.
Anyway, the point is, I love everything you're doing but don't get too fragmented with all those great ideas, perhaps some focus in just a few areas might get us an actual release of some stuff vs. a ton of teasers :)
Nice to see the direction all of this is going.
http://forums.subsonicproject.com/forums/t/2439.aspx
Also I noticed another forum post with another user having the same issue. When I do a fresh checkout of subsonic from subversion the products.cs has a "Neep" column. Just do a Find in All Files for Neep and you'll see it. Obviously this has to be on a fresh checkout, no fair re-generating the DAL since that's where the problem is.
I think I will be able go home early. May be company will employ a junior developer and send me home.
Because its they don t need me
How about throwing in a
So how about throwing a unit test of mvc / makai / subsonic (slash meaning and/or) on the web ?
Just to get us started...
Thx for your thoughts.