Conventional HTML in ASP.NET MVC: A Primer

Other posts in this series:

I hinted last post that I wasn’t a fan of the Display/Editor templates in ASP.NET MVC. I really liked the idea of opinionated, metadata driven input and output builders – in fact, I wound up building this concept in a really large MVC project (that eventually spawned the MVC Contrib InputBuilders).

I had hoped that this concept would be effectively replaced by templated helpers in MVC, but unfortunately, it just hasn’t been the case. I’ve used templated helpers in a lot of simple scenarios, but for highly customized scenarios, or anything off the happy path, they just don’t work very well.

Instead, we’ve gone with integrating Fubu MVC HTML conventions into our project, and it’s a complete breath of fresh air. But before I dive in to the nuts and bolts of integrating Fubu into ASP.NET MVC, it’s important to understand my motivations and concerns. If you don’t have these problems or concerns, then by all means, stay with ASP.NET MVC templated helpers! But if you don’t like the defaults or hard-coded opinions, Fubu’s conventions could be a great fit.

So in no particular order, let’s look at my gripes of templated helpers.

Model metadata madness

At its core, templated helpers are a way of using model metadata to build HTML. To achieve this, we need some way of providing the builders of HTML with the metadata about which they are building. We’ll have this in our view:

<p>
    @Html.EditorFor(m => m.FirstName)
</p>

And we need to pass the metadata from the “FirstName” expression to whatever builds our HTML, because it will use all that information when deciding what to build. Dates? Do something special. Guids? Do something special, and so on. Our model is rather simple:

public class PersonEditModel 
{
	[Display(Name = "First Name")]
	public string FirstName { get; set; }
}

You might think that model metadata would include the PropertyInfo item plus perhaps some context and the model value. You’d be wrong though, we instead have another object serving as the encapsulation of our model metadata, without actually giving us access to things we really need, ModelMetadata:

http://msdn.microsoft.com/en-us/library/system.web.mvc.modelmetadata.aspx

To understand how this object gets filled, we need to understand the ModelMetadataProvider. Quick – what value does the attribute Display above populate on our ModelMetadata? What about the Hidden attribute?

What if we have a custom attribute? What if we decide to use some other validation framework, like Castle validations or Fluent Validation? We now need to augment these models to populate this model, because we have no way of getting back to the original property with its full metadata.

I have no idea what half these properties mean or what they do on ModelMetadata. However, I do know reflection, and it’s very easy to go from actual metadata objects (System.Type etc.) and build HTML. Everything I need to know is already on the Type objects, there’s no need to jump through extra hoops of ModelMetadata to get at it. In some cases, it’s not even possible to get back to the original type metadata.

Do as I say, not as I do

In order to create custom templates in ASP.NET MVC, you’re required to create Razor templates. That’s not horrible – but it’s not how the built-in templates are created! If you want to override the existing templates, you’ll likely want to just augment the existing output slightly. That’s just not possible, it’s really all-or-nothing.

You might expect to see the default templates implemented as Razor as well, but instead, it’s a static class with a bunch of methods, with a dictionary pointing to the templates. Of course this class is internal, and it takes a bit of spelunking to even find it, our DefaultEditorTemplates class.

If you want to something even more interesting – say include a label element with each input element, we need to override the object template (which oddly enough, isn’t used in our string template).

None of the methods in the DefaultEditorTemplates class are meant to be copy-pasted into Razor code, so we’re essentially starting from scratch. How can we be assured that Razor as templates is viable when not even the built-in templates are implemented in this fashion?

Razor templates and real logic

This brings us back to my biggest frustration of editor/display templates. We only have one way of providing them – through Razor. However, in practice, I’ve found that my need to use Razor in templates is by far the minority. It’s only in things like showing an editor for a generic “Address” or “Phone Number” that might have multiple fields in a single model property.

In my original Input Builder design was 100% code-based, but it had a fundamental flaw (well, several). It build on top of strings, which is a lousy abstraction of HTML. I did allow for actual view templates as a last resort, but the 99% case was completely code-driven.

But in our Razor template, if we want to do anything interesting, conditionally build up HTML based on certain criteria, our Razor templates become ugly fast. Interestingly enough, the MVC Contrib input builders have the same problem, being 100% view-driven.

Views are great for composing multiple HTML elements, but code is best for modifying/customizing individual blocks of HTML. It’s why we have both partials and HTML Helper extensions in MVC.

Resolving and extending templates

Another major limitation in templated helpers is you can’t modify the pipeline in how a template is chosen. There is an explicit list of built-in templates, and an explicit resolution mechanism. This mechanism drives either off of the property type or a template name, but that’s it.

This leads to things like a “UIHint” attribute, where we’re hard-coding the template to use inside our view models.

I’m typically doing one of two things when customizing my templates: replacing or extending. With replacing, I can only replace based on the existing hierarchy, but not more interesting things like “every property called ‘Comments’ needs to be a textarea”. Or even more interesting, being able to augment the templates on my views. I might want to tweak the resulting HTML by adding additional styling for layout or widths. None of this is possible because there’s so much distance between my model and the resulting template.

Resolving a template could be complex, depending on what’s going on. There’s simple type-based behaviors (Guids, bools, etc.) but other times I simply want to modify the default, perhaps with data attributes and so on. I don’t want to push this all onto my models explicitly, most of it can simply be inferred by looking at our model with a keen eye.

Fubu has the concept of both builders and modifiers, of actual HTML objects (not strings). It’s far more powerful and extensible – I get to choose exactly how my templates are chosen and built.

There are some other problems – resolving dependencies are another issue (drop-down list using lookup table from database for one), but you get the idea. If you’re going full on into metadata-driven HTML, you’ll likely get frustrated with display/editor templates.

In the next few posts, I’ll look at integrating Fubu MVC’s HTML conventions into an existing MVC application, and customizing them to build some truly powerful conventions.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in ASP.NET MVC. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • mxmissile

    Just googled for something like this yesterday. In over my head and spending way to much time in the EditorTemplates/DisplayTemplates folder once again.

  • http://trycatchfail.com/ Matt Honeycutt

    I prefer the Fubu approach as well. That said, I was able to introduce support for conventions based on things like property name using a custom, pluggable model metadata provider. There’s a sample in Fail Tracker: https://github.com/MattHoneycutt/Fail-Tracker/tree/master/FailTracker.Web/Infrastructure/ModelMetadata. It’s not perfect, but it will give you more flexibility if you don’t want to abandon the built-in templating system completely.

  • georgexcollins

    Does your app do i18n? That’s a whole other horror story.

  • Harry McIntyre

    If the FUBU html builders don’t work out for you, you might like to consider http://formfactory.apphb.com/

    It uses Razor templates (e.g. “Property.System.String.cshtml) l rather than the Fubu html objects, and has a few nifty tricks like automatically rendering autocompletes and sortable collections (if your model is marked up correctly).

    Apologies for the plugging.

  • http://www.frivmini.com/ friv

    I think that your perspective is deep, its just well thought out and really fantastic to see someone who knows how to put these thoughts down so well.

  • MikeSw

    Can’t wait for the next post.I’m quite fond of FUBU concepts and I even adopted some Fubu ways into my asp.net mvc projects (namely convention based Route generation, Filters and View engine rules) but I don’t know much about html conventions.

  • Robert Daniel Moore

    I’ve been working on a library that uses the model metadata (e.g. enums become drop-down, or optionally a list of radios, lists are multi-select or list of checkboxes, etc.), but provides a flexible fluent interface to customise the HTML before it gets output.

    It also gives you the ability to specify the template for your form once and reuse it consistently across the whole site (something that I think can be quite tedious usually, especially if you ever need to change it).

    https://github.com/MRCollective/ChameleonForms

  • http://www.frivgame.co/ Friv

    Your content contains great information. This topic is very interesting and profound. I agree with your point. Thank you.

  • Dariusz Lenartowicz

    “In the next few posts, I’ll look at integrating Fubu MVC’s HTML
    conventions into an existing MVC application, and customizing them to
    build some truly powerful conventions.”

    Waiting for that :)

  • http://www.gamesfriv2.com/ Friv 2

    Thank you !

  • Steel Hammerhands

    “In order to create custom templates in ASP.NET MVC, you’re required to create Razor templates.”

    Unless I’m confused about something here, this is incorrect. The existing templates are just static classes that return an MvcHtmlString object. It’s extremely easy to follow this same structure to write your own. Just put it in the System.Web.Mvc namespace and use it just like any other template.

    For instance, I have a custom editor template that I use for pretty much all of my inputs. It creates a LabelFor, EditorFor, and ValidationMessageFor for a property and wraps them all in a div. It also checks the model metadata and adds a class of ‘required’ to the LabelFor if appropriate. Works like a charm.

  • Pingback: Conventional HTML in ASP.NET MVC: A Primer | Ji...

  • ngockonvang

    I use the same basic idea to create radio button lists and checkbox lists, since they aren’t included by default.

  • Pingback: Conventional HTML in ASP.NET MVC: Adopting Fubu conventions | Jimmy Bogard's Blog

  • Pingback: Conventional HTML in ASP.NET MVC: Baseline behavior | Jimmy Bogard's Blog

  • Pingback: Conventional HTML in ASP.NET MVC: Replacing form helpers | Jimmy Bogard's Blog

  • bla

    I do not like the assumption that all boolean in an application are going to be displayed like so. Maybe the user wants a checkbox. Maybe the user wants a radio button. Maybe the user wants two buttons with a glowing green and red to show what is selected. The way we went was to use UIHint to specify the type of display we wanted.

    I agree that displayfor and LabelFor are over kill. That is why we only use EditorFor. Our EditorFor will create the html for layout, the label, and turning the label red if error occurs. We saw that layout, label, and error stuff was common to each EditorFor so we re-factored and have a layout EditorFor that the specific(UIHint) editorFors inherit. So the Phone EditorFor is responsible for masking and inherits the Layout editorfor for label and layout information.

    • jbogard

      That assumption is only valid if it holds :)

  • Pingback: Conventional HTML in ASP.NET MVC: Data-bound elements | Jimmy Bogard's Blog

  • Pingback: Conventional HTML in ASP.NET MVC: Validators | Jimmy Bogard's Blog

  • Pingback: Conventional HTML in ASP.NET MVC: Building larger primitives | Jimmy Bogard's Blog

  • Pingback: Conventional HTML in ASP.NET MVC: Client-side templates | Jimmy Bogard's Blog