Conventional HTML in ASP.NET MVC: Client-side templates

In our last post, we brought everything together to build composable blocks of tags driven off of metadata. We did this to make sure that when a concept exists in our application, it’s only defined once and the rest of our system builds off of this concept. This reduces logic duplication across several layers, ensuring that we don’t have to “remember” to do repetitive tasks, like a required field needing an asterisk and data attributes.

All of this works great because we’ve got all the information at our disposal on the server-side, and we can push the completed product down to the client (browser). But what if we’re building a SPA, using Angular or Knockout or Ember or Backbone? Do we have to revert back to our old ways of duplication? Or can we have the best of both worlds?

There tend to be three general approaches:

  • Just hard code it and accept the duplication
  • Include metadata in your JSON API calls, through hypermedia or other means
  • Build intelligence into templates

I’ve done all three, and each have their benefits and drawbacks. Most teams I talk to go with #1, and some go with #2. Very few teams I meet even think about #3.

What I’d like to do is have the power of my original server-side Razor templates, with the strongly-typed views and intelligent expression-based helpers, but instead of complete HTML templates, have these be Angular views or Ember templates:


When we deliver our templates to the client as part of our SPA, we’ll serve up a special version of them, one that’s been parsed by our Razor engine. Normally, the Razor engine performs two tasks:

  • HTML generation
  • Binding model data

Instead, we’ll only generate our template, and the client will then bind the model to our template.

Serving templates, Ember style

Normally, the MVC view engine runs the Razor parser. But we’re not going that path, we’re going to parse the templates ourselves. The result of parsing will be placed inside our script tags. This part is a little long, so I’ll just link to the entire set of code.


A couple key points here. First, the part that runs the template through the view engine to render an HTML string:

builder.AppendLine("<script type=\"text/x-handlebars\" data-template-name=\"" + fullTemplateName + "\">");
var controllerContext = new ControllerContext(helper.ViewContext.HttpContext, new RouteData(), helper.ViewContext.Controller);
controllerContext.RouteData.Values["controller"] = string.IsNullOrEmpty(relativeDirName) ? "Home" : Path.GetDirectoryName(relativeDirName);
var result = ViewEngine.FindView(controllerContext, subtemplateName, null, false);
var stringWriter = new StringWriter(builder);
var viewContext = new ViewContext(controllerContext, result.View, new ViewDataDictionary(), new TempDataDictionary(), stringWriter);
result.View.Render(viewContext, stringWriter);


We render the view through our normal Razor view engine, but surround the result in a script tag signifying this is a Handlebars template. We’ll place the results in cache of course, as there’s no need to perform this step more than once. In our context objects we build up, we simply leave our ViewData blank, so that there isn’t any data bound to input elements.

We also make sure our templates are named correctly, using the folder structure to match Ember’s conventions. In our one actual MVC action, we’ll include the templates in the first request:


@Html.Action("Enumerations", "Home")

Now that our templates are parsed and named appropriately, we can focus on building our view templates.

Conventional Handlebars

At this point, we want to use our HTML conventions to build out the elements needed for our Ember templates. Unfortunately, we won’t be able to use our previous tools to do so, as Ember uses Handlebars as its templating language. If we were using Angular, it might be a bit easier to build out our directives, but not by much. Client-side binding using templates or directives requires special syntax for binding to scope/model/controller data.

We don’t have our convention model, or even our HtmlTag library to use. Instead, we’ll have to use the old-fashioned way – building up a string by hand, evaluating rules as we go. I could have built a library for creating Ember view helpers, but it didn’t seem to be worth it in my case.

Eventually, I want to get to this:

@Html.FormBlock(m => m.FirstName)

But have this render this:

<div class="form-group">
    <label class="required control-label col-md-2"
       {{bind-attr for="view.firstName.elementId"}}>
       First Name
    <div class="col-md-10">
        {{view TextField class="required form-control" 

First, let’s start with our basic input and just cover the very simple case of a text field.

public static MvcHtmlString Input<TModel, TValue>(this HtmlHelper<TModel> helper,
    Expression<Func<TModel, TValue>> expression,
    IDictionary<string, object> htmlAttributes)
    var text = ExpressionHelper.GetExpressionText(expression).ToCamelCase();
    var modelMetadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
    var unobtrusiveAttributes = GetUnobtrusiveValidationAttributes(helper, expression);

    var builder = new StringBuilder("{{view");

    builder.Append(" TextField");

    if (unobtrusiveAttributes.ContainsKey("data-val-required"))
        builder.Append(" class=\"required\"");

    builder.AppendFormat(" data-key=\"{0}\"", text);

    builder.AppendFormat(" valueBinding=\"model.{0}\"", text);
    builder.AppendFormat(" viewName=\"{0}\"", text);

    if (!string.IsNullOrEmpty(modelMetadata.NullDisplayText))
        builder.AppendFormat(" placeholder=\"{0}\"", modelMetadata.NullDisplayText);

    if (htmlAttributes != null)
        foreach (var item in htmlAttributes)
            builder.AppendFormat(" {0}=\"{1}\"", item.Key, item.Value);


    return new MvcHtmlString(builder.ToString());

We grab the expression text and model metadata, and begin building up our Handlebars snippet. We apply our conventions manually for each required attribute, including any additional attributes we need based on the MVC-style mode of passing in extra key/value pairs as a dictionary.

Once we have this in place, we can layer on our label helper:

public static MvcHtmlString Label<TModel, TValue>(
    this HtmlHelper<TModel> helper, 
    Expression<Func<TModel, TValue>> expression)
    var text = ExpressionHelper.GetExpressionText(expression);
    var metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
    var unobtrusiveAttributes = GetUnobtrusiveValidationAttributes(helper, expression);

    var builder = new StringBuilder("<label ");
    if (unobtrusiveAttributes.ContainsKey("data-val-required"))
        builder.Append(" class=\"required\"");
    builder.AppendFormat(" {{{{bind-attr for=\"view.{0}.elementId\"}}}}", text.ToCamelCase());

    string labelText = metadata.DisplayName ?? (metadata.PropertyName == null
        ? text.Split(new[] {'.'}).Last()
        : Regex.Replace(metadata.PropertyName, "(\\B[A-Z])", " $1"));


    return new MvcHtmlString(builder.ToString());

It’s very similar to the code in the MVC label helper, with the slight tweak of defaulting label names to the property names with spaces between words. Finally, our input block combines these two together:

public static MvcHtmlString FormBlock<TModel, TValue>(
    this HtmlHelper<TModel> helper,
    Expression<Func<TModel, TValue>> expression)
    var builder = new StringBuilder("<div class='form-group'>");
    return new MvcHtmlString(builder.ToString());

Now, our views start to become a bit more sane, and it takes a keen eye to see that it’s actually a Handlebars template. We still get strongly-typed helpers, metadata-driven elements, and synergy between our client-side code and our server-side models:

@model MvcApplication.Models.AccountCreateModel
{{title 'Create account'}}

<form {{action 'create' on='submit'}}>
        <legend>Account Information</legend>
        @Html.FormBlock(m => m.Username)
        @Html.FormBlock(m => m.Password)
        @Html.FormBlock(m => m.ConfirmPassword)

We’ve now come full-circle, leverage our techniques that let us be ultra-productive building out pages on the server side, but not losing that productivity on the client-side. A concept such as “required field” lives in exactly one spot, and the rest of our system reads and reacts to that information.

And that, I think, is pretty cool.

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 ASPNETMVC. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Pingback: Conventional HTML in ASP.NET MVC: Data-bound elements | Jimmy Bogard's Blog()

  • jimmyhogard

    Garbage. Does not scale.

    • RyanVice

      Is this really your own personal troll account Jimmy? You’ve reached new heights of awesome with this!

      • jbogard

        I don’t know what this is, I was just about to delete it lol

  • Betty

    Would this still work with optimization tools that combine everything (including views) into one js file? I guess it would probably depend on if there’s any conditional logic in the views.

    • jbogard

      Yeah, it should. We just embedded the templates in the page but ultimately the approach just builds a single string.

    • It shouldn’t be hard to adapt this to use ASP.NET bundling, and then jam them all into one JS file that (in Angular-speak) inserts them all into the $templateCache.

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1674()

  • Vlad Kopachinsky

    I think solution very complex because use magic string. We are have our template builder for ( handlebars, mustaches and etc ) with generic syntax like @each.For(r=>r.Name) . Please look at article ( )

    • jbogard

      Wow, neat stuff! My example is expression-based as well, I think we came up with the same approach, different implementations, no? I build out a helper for a model member with an expression.

      • Vlad Kopachinsky

        Maybe. Let me try compare your solution and our:
        Please look at first attach file it show how write template for form.

        You solution narrow but It no so bad. Our template builder usage for generate tables, list or something html content but can worked as form builder or everything. Please look at sample template ( load data by ajax and insert with template ) on github ( )

        P.S. Please maybe you can take 30 – 50 minutes and look our template ( also it one part of incoding framework ) . I would be very grateful. Thanks.

        • Guest

          missing attach file

  • Ciel

    I see someone saying this doesn’t scale, but I really beg to differ. I’ve yet to discover a framework, technique, pattern, or infrastructure that scales indefinitely and this is no different. It accomplishes what the author set out to do in the initial post, it is fluid and elegant, and while there is always room for improvement, it is a hell of a lot better than anyone I’ve seen critiquing in the posts up until now offering.

    Programmers who just ridicule code without offering constructive ways to solve the problem are no better than trolls, I think. We’re supposed to be building solutions that make things better for people. The only comment I’ve seen that was remotely constructive was the one on THIS post by Vlad Kapachinsky.

    TLDR; If you think it is bad, then do better. Otherwise, shut up.

  • Pingback: Conventional HTML in ASP.NET MVC: Client-side t...()

  • Sam Sippe

    Hi Jimmy, Off topic but I wanted to read some of your old category posts and the category view isn’t working on the site e.g.


  • Daniel Mackay

    Hi Jimmy. First of all, great series of posts! Do you have a complete solution with all these techniques combined?

  • housecor

    I’m not sure the benefit justifies the cost. I prefer a clear decision: It’s either:

    1. A server-rendered app with some very trivial JS via lib of your choice.
    2. A client-rendered app built in framework of your choice.

    For option 1, the amount of JS on the client is trivial enough that the complexity above would provide little benefit. The cost is clear though: The solution above couples you tightly to at least two frameworks, and likely some other JS libs. It also adds the mental burden of understanding multiple layers of abstraction at the same time: HTML helpers processed on server via .NET generate valid markup for a client-side framework. This makes debugging and changing the client-side framework more mentally taxing (though the helpers do certainly honor DRY).

    For option 2, I prefer the server-side story to merely be some JSON API. A webserver sends down plain ‘ol JS, HTML, and CSS. Make AJAX calls as needed. Serialize a POCO on the server to JSON to bootstrap the app. This means I can create my own build and deployment process for the client using modern Node-based tooling. And it maintains complete separation from the server. I find this clear separation also helps keep junior devs from making DB calls via the UI layer.

    Bottom line – I agree your solution honors DRY. But I’m not sold that benefit offsets the cost of maintaining server-side abstractions over 3rd party libraries. The resulting mental weight of mixing client and server concerns is a cost to consider.

    You still doing this today with React?